我发现了一些与此类似的问题但存在一些差异。这是我的代码:student.h:
#define NUM_GRADES 5
#define NAME_LENGTH 21
#define ADDRESS_LENGTH 21
typedef struct
{
char name[NAME_LENGTH]; //name of a student - up to 20 chars.
char add[ADDRESS_LENGTH]; //address - up to 20 chars.
int grades[NUM_GRADES]; //stores the grades of a student.
}student;
//the current size of the students array.
extern int currentTotal;
//add a new student space, return 0 if failed, 1 if succeeded.
int addStudent(student **studentClass);
student.c:
int addStudent(student **studentClass)
{
//adds the count for the new student.
currentTotal++;
//a temporary pointer to hold studentClass array in case realloc fails.
student *temp=NULL;
//reallocating space for the new student.
if (!(temp = (student*)realloc(*studentClass, currentTotal * sizeof(student))))
{
printf("Not enough memory.\n");
free(*studentClass);//free the original array.
currentTotal = 0;
return 0;
}
*studentClass = temp;//point class to the newly allocated space.
printf("Added space for a student.\n");
return 1;
}
main.c中:
#include <stdio.h>
#include <stdlib.h>
#include "student.h"
void main()
{
student *studentClass=NULL;
....
if(addStudent(&studentClass)
....
currentTotal是一个外部int变量。 realloc的使用是否正确?而免费使用?一旦我将指针的地址发送到另一个函数,我总是混淆我是否应该在函数内部使用*或**。 (即有一个类似* studentClass的指针,然后将&studentClass发送到另一个函数)。
如果这确实是正确的,那么* studentClass在“* studentClass = temp;”行之前指向的原始数据会发生什么? (在student.c中)?它需要被释放吗?
编辑:请不要混淆,最初* studentClass是NULL,它只是在开始时,addStudent()意味着在循环中调用,所以在第一次之后,* studentClass不再是NULL。 addStudent()在每次调用后增加* studentClass的大小。
谢谢。
它是“保存”,因为它不会引入未定义的行为,也不会泄漏内存。你要注意,如果realloc
失败,原始数据不会被释放(所以你这样做),并且你将realloc
的结果存储在临时变量中,以免丢失指向原始数据的指针。到目前为止一切都还可以。
然而,如果addStudent
失败,它包含realloc
调用者的陷阱。在这种情况下,您释放原始内存块而不提供新内存块,但不要将指针重置为NULL
。所以传递给addStudent
的变量仍然指向一些内存,但是这个内存已被释放。调用者可能会尝试第二次释放此内存(然后产生未定义的行为)。
如果realloc
失败,我建议根据谁负责释放学生的阵列记忆来做两种选择中的任何一种:
一个。 addStudent
负责:释放原始内存并将指针设置为NULL
,这样外面没有人可以尝试两次释放内存。所以你要在*studentClass=NULL
之后添加一个free
。
湾调用者负责:如果realloc
失败,请不要释放原始内存;返回 - 正如您所做的那样 - 失败代码并让调用者完成其余的工作。所以你要删除free
。
这一切都很好。由于*studentClass
是NULL
,realloc(3)
表现得像malloc(3)
。在realloc(3)
失败的情况下,它不会修改传递的指针,这意味着*studentClass
仍然是NULL
。在free(3)
指针上调用NULL
是完全有效的,但不会发生任何事情(无操作)。然后函数返回,*studentClass
仍然是NULL
。你只需要在调用addStudent
之后检查它的值:如果它是NULL
,学生的添加失败,否则它成功了。
你使用双指针也是有效的。推理这种情况的一种方法是这样的。指针允许修改指向位置的数据。如果想要将整数传递给要修改的函数,可以将其作为int*
传递。在函数内部,一个取消引用它来修改它,例如*my_int = 0;
。因此,如果想要在函数内修改student*
,它必须作为student**
传递,然后每当想要更改其内容时解除引用。
除了Stephan Lechner提到的事实之外,代码应该单独保留分配或者将指针置空(而不是释放内存而不使指针无效),我还会看到一些其他问题:
我可以看到解决第二个问题的四种好方法:
如果学生数量增长而不是缩小,方法#3和#4可能会略有优势。如果分配区域的大小缩小为零,则无法确定对realloc
区域大小为零字节的请求是否成功(如果该区域先前具有零大小,则标准将允许realloc(prevPtr,0)
在具有零之后返回null成功发布了之前的分配,但标准也允许realloc
失败(并返回null)而不释放之前的分配。