我发现了一些与此相似的问题,但存在一些差异。 这是我的代码: 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这样的指针,然后将&amp; studentClass发送给另一个函数)。
如果这确实是正确的那么* studentClass在该行之前指向的原始数据会发生什么 &#34; * studentClass = temp;&#34; (在student.c中)? 它需要被释放吗?
编辑: 请不要混淆,最初* studentClass是NULL,它只是在开始时,addStudent()意味着在循环中调用,所以在第一次之后,* studentClass不再空值。 addStudent()在每次调用后增加* studentClass的大小。
感谢。
答案 0 :(得分:1)
它&#34;保存&#34;从某种意义上说,它不会引入未定义的行为,也不会泄漏内存。您需要注意的是,如果<v-text-field
:value="currentValue"
@input="handleInput"
:mask="###.###.###-##"></v-text-field>
失败,原始数据不会被释放(所以你这样做),并将realloc
的结果存储在临时变量中,以免丢失指向原始数据的指针数据。到目前为止一切都还可以。
如果realloc
失败,它包含addStudent
调用者的陷阱。在这种情况下,您可以释放原始内存块而不提供新内存块,但不要将指针重置为realloc
。因此,传递给NULL
的变量仍指向某个内存,但此内存已被释放。调用者可能会尝试第二次释放此内存(然后产生未定义的行为)。
如果addStudent
失败,我建议根据谁负责释放学生的阵列记忆来做两种选择中的任何一种:
一个。 realloc
负责:释放原始内存并将指针设置为addStudent
,这样外面没有人可以尝试两次释放内存。因此,您需要在NULL
之后添加*studentClass=NULL
。
湾调用者负责:在free
失败的情况下,不要释放原始内存;返回 - 正如您所做的那样 - 失败代码并让调用者完成其余的工作。因此,您要删除realloc
。
答案 1 :(得分:0)
这一切都很好。由于*studentClass
为NULL
,realloc(3)
的行为与malloc(3)
相似。在realloc(3)
失败的情况下,它不会修改传递的指针,这意味着*studentClass
仍然是NULL
。在free(3)
指针上调用NULL
是完全有效的,但不会发生任何事情(无操作)。然后函数返回,*studentClass
仍为NULL
。您只需要在调用addStudent
后检查其值:如果是NULL
,则添加学生失败,否则成功。
你使用双指针也是有效的。推理这种情况的一种方法是这样的。指针允许修改指向位置的数据。如果想要将整数传递给要修改的函数,可以将其作为int*
传递。在函数内部,可以取消引用它以对其进行修改,例如*my_int = 0;
。因此,如果想要修改函数内的student*
,则必须将其作为student**
传递,然后每当想要更改其内容时取消引用。
答案 2 :(得分:0)
除了Stephan Lechner提到的事实之外,代码应该单独保留分配或者将指针置空(而不是释放内存而不使指针无效),我还会看到一些其他问题:
如果不希望调用者从内存不足状态恢复,则分配函数在发生时不应返回。相反,他们应该发出故障信号(可能是通过提升信号)然后退出(如果发出故障信号并没有强制退出)。有一个功能保证它永远不会返回失败可以大大简化客户端代码。
如果函数要使用全局变量来保存分配的大小,它应该使用指向分配的全局指针。如果它将使用由传入地址标识的对象指针,则它应该使用也由传入地址标识的对象计数。
我可以看到解决第二个问题的四种好方法:
像现在一样传入双间接指针,但也传递指向包含学生数量的整数类型对象的指针。
传入一个指向结构的指针,该结构包含学生指针和学生数。
定义一个结构,该结构包含学生类型的计数和灵活的数组成员,并保留指向该结构而不是第一个学生的指针。
如上所述,但保留指向第一个学生的指针(而不是分配区域的开头)。这将要求调整使用malloc / realloc / free的任何代码来抵消与这些函数交换的指针。
realloc
区域大小为零字节的请求是否成功(如果该区域之前的大小为零,则标准将允许{{ 1}}在成功释放先前的分配后返回null,但标准也允许realloc(prevPtr,0)
失败(并返回null)而不释放先前的分配。