从C函数返回指针是好/坏设计?
我想知道来自C函数的返回指针是好/坏设计? 如果这是一个不好的做法,在下面的例子中,这将是一个好习惯:
问题是继续部分: c函数返回静态变量
在data.h
文件中:
#include #include typedef struct { int age; int number; } person; person * getPersonInfo();
在data.c
#include "data.h" static struct person* person_p = NULL; person * getPersonInfo() { person_p = (struct person*)malloc(10 * sizeof(struct person)); return person_p; }
在main.c
#include "data.h" int main() { person* pointer = getPersonInfo(); return 0; }
基本上, main
文件中的main
函数需要获取静态指针person_p
指向的数组的所有元素的值,如果不是一个好习惯,那么应该是一个好的做法?
它不好的唯一原因是因为你背后没有任何内存管理结构。 在您当前的代码中,您有内存泄漏,因为您通过malloc()分配一个person
结构,但不释放它。
考虑编写一个包装器函数,为您处理内存管理,如下所示:
void freePerson(struct person * personToDelete) { free(personToDelete); }
然后在你的主要:
int main() { person* pointer = getPersonInfo(); freePerson(pointer); // After you are done using it return 0; }
我还要警告不要转换malloc()
的结果。 根据我的经验,它可能导致未定义的行为。
返回指向私有变量的指针是不好的做法。 此外,使用当前设计,您的.c文件只能有一个person对象的实例。
而且几乎不用说,动态分配对象的相同代码也应该负责释放它。 编写的代码是为了使程序中的其他模块能够清理混乱,每个设计都会导致内存泄漏。
如果您正在编写至少有些复杂的数据类型,您需要限制对私有变量的访问,拥有结构的多个实例等,那么最好使用“opaque类型”。 示例(未测试):
// data.h
#ifndef DATA_H #define DATA_H #include #include typedef struct person person; // opaque type person* person_create (void); void person_delete (person* p); void person_set_age (person* p, int age); int person_get_age (const person* p); // ... and so on, setters/getters #endif // DATA_H
// data.c
#include "data.h" struct { int age; int number; } person; person* person_create (void) { return malloc(sizeof(struct person)); } void person_delete (person* p) { free(p); } void person_set_age (person* p, int age) { p->age = age; } int person_get_age (const person* p) { return p->age; }
//来电者:
#include "data.h" int main() { person* p = person_create(); person_set_age(p, 50); printf("%d", person_get_age(p)); person_delete(p); return 0; }
有些事情需要考虑:
- 始终在h文件中使用标题保护。
- 切勿对C函数使用空参数列表
()
(但总是在C ++中使用)。 - 不要在C中强制转换malloc的结果(但总是在C ++中)。
- 如果malloc失败,则需要在此代码中添加一些error handling。
要成为一个好的设计,您必须具有匹配的function,以便在不再需要时释放分配的内存。
这是一个决定问题,而不是其他一切。
只要您了解每个专家和骗局,这两个选项都是有效的
返回指针优点:
- 封装内存分配
- 动态支持动态内存大小
返回指针缺点:
- 只有一个可能的参数
- 每次都必须在堆上分配内存
接受指针作为输入专业正好相反:
- 多个输出参数
- 内存不必在堆上分配,调用者可以使用其堆栈上的变量作为输出参数
接受指针作为输入缺点:
- 没有封装内存分配
- 动态内存大小不支持动态 – 大小必须固定或预先指定
在您的具体示例中,我将使用输出参数,因为它是固定大小,并且可以在不动态分配内存的情况下轻松调用。