当用 C 语言编程时,我们通常创建初始化的数据结构,然后在不再需要时将其释放。例如,如果我们想创建一个动态的 double 数组,通常声明
struct vector {
double *data;
int size;
int capacity;
}
typedef struct vector vector;
vector *v_new(int n) {
vector *v = malloc(sizeof(vector));
v->data = malloc(n * sizeof(double));
v->size = n;
v->capacity = n;
return v;
}
Run Code Online (Sandbox Code Playgroud)
问题是关于自由函数的常见模式。在 C 语言中,该函数free接受 NULL 指针并且不执行任何操作。以这种方式设计v_free函数是一种常见的模式,还是它们通常期望一个非 NULL 指针?明确地说,您期望这种实现吗?
void v_free(vector *v) {
if (v != NULL) {
free(v->data);
}
free(v);
}
Run Code Online (Sandbox Code Playgroud)
或者这个?
void v_free(vector *v) {
free(v->data);
free(v);
}
Run Code Online (Sandbox Code Playgroud)
提出这个问题是因为我们在法国预科学校开始向本科生教授C语言,而我们在“C设计模式”方面没有那么多经验。
谢谢你的建议。
v->data如果为 NULL,则无法访问v。因此,如果有可能发生这种情况,您必须执行检查该情况的版本,最好写为
void v_free(vector *v) {
if (v != NULL) {
free(v->data);
free(v);
}
}
Run Code Online (Sandbox Code Playgroud)
如果v这里永远不应该为 NULL,那么最好添加一个断言来明确假设:
void v_free(vector *v) {
assert(v != NULL);
free(v->data);
free(v);
}
Run Code Online (Sandbox Code Playgroud)
这样程序员就会注意到他们做错了什么。
请注意,这两个版本都没有检测到悬空指针,即。指向已销毁对象的指针。这包括指向已经释放的内存(即,这里有双重释放)或通过指向不再在范围内的局部变量的指针。