我是否正确使用了malloc函数?

4

您好!

我需要在创建学生列表系统时使用malloc函数...为了提高效率,我们的教授要求我们在结构体上使用它,因此我创建了以下结构体:

struct student {
       char studentID[6];
       char name[31];
       char course [6];
};
struct student *array[30];

每当我添加一条记录时,就会使用malloc...

array[recordCtr]=(struct student*)malloc(sizeof(struct student));
recordCtr++;

然后我像这样释放它。
 for(i = 0; i < recordCtr; i++){
       free(array[i]);
  } 

我是否正确使用了malloc?如果我像下面这样释放它,而不是使用循环,会有什么影响。

free(array);

非常感谢。我们非常重视您的意见。

10个回答

5

你做得很好。

free(array); 是未定义的行为,因为 array 本身不是通过 malloc 分配的,所以你不能释放它,并且也不需要 - 内存将由编译器管理。


3

一个好的建议是始终要做到:

type *something;
something = malloc(n * sizeof(*something));

这是因为,如果您更改了某个东西的类型,您不必更改各种其他代码。而且sizeof在这里真正是一个编译器操作,它不会在运行时变成任何不同的东西。
另外,在C中不要转换malloc返回的void*指针,没有理由这样做,这只会进一步将您的代码连接在一起。
所以在您的情况下,请不要这样做:
(struct student*)malloc(sizeof(struct student));

但是
malloc(sizeof(**array));

2

您使用malloc的方式并没有违法,但这不是一个列表,而是指针数组。

要使用列表,您不需要事先确定大小,并且有指向下一个元素的指针。您可以将其设置为侵入式或非侵入式。

对于侵入式列表,在student的声明中加入struct student * next

对于非侵入式列表,您需要创建另一个结构体student_list_node,其中包含一个struct student实例和一个指向struct student_list_node的指针*next。

这是非侵入式版本的示例:

struct student_list_node
{
  struct student data;
  struct student_list_node * next;
};

struct student_list_node * head;
struct student_list_node * tail;

struct student_list_node * addStudentToTail()
{
   struct student_list_node * newnode = (struct student_list_node *)(malloc( sizeof(struct student_list_node ) );
   /* check malloc did not fail or use a checking vesrion of malloc */
   if( !tail )
   {
      head = tail = newnode;
   }
   else
   {
      tail->next = newnode;
      tail = newnode;
   }
   return newnode; // which is also "tail"
}

int main()
{
   struct student_list_node * node = addStudentToTail();
   struct student * pstud = &node->data;
   /* write to pstud student details */
}

如果你真的想使用数组,你可能希望将它作为student数组而不是student* 数组,这种情况下你可以使用calloc而不是 malloc。

struct student * array = (struct student *)calloc( 30, sizeof( student ) );

然后使用 free(array) 就是正确的处理方式。你也可以选择在需要时用realloc分配更多空间。(但要小心:你必须在知道realloc成功之前保留原始指针的副本)。


哇,这对我来说太复杂了。无论如何,谢谢。我会尝试学习这个的。 - newbie

1

这个数组本身没有在堆上分配。假设它是一个全局变量,在程序启动时分配在全局内存中,不需要释放。对它调用free可能会破坏你的程序。

您当前的解决方案是正确的。


1

你所做的是正确的。

你可以将*array[30]看作是一个由30个指针组成的数组。当你为每个指针分配内存时,你也需要对它们中的每一个调用free()函数。


1

是的,你使用得很正确。有比这更好的组织存储方式,但这个方法可以工作。至少在你需要超过30名学生之前...

请注意,您必须对每个由malloc()返回的指针调用free()。这意味着您循环遍历指针数组的方法是您所选择的架构的正确方法。

您尝试在数组本身上调用free将不起作用。这会引发未定义行为,因为您正在向free()传递一个指针(指向数组本身的基址),而该指针不是来自malloc()的调用。


1

有一个简单的规则:每个malloc()都应该与由malloc返回的指针配对使用free()。不多也不少。


1

看起来不错。

如果适用于您的问题,您可以一次性为所有30个结构分配空间。

 struct student *array = (struct student *)malloc(30*sizeof(struct student));

当你想要释放空间时,可以这样做

free(array)

1
你所拥有的已经可以很好地工作了。就像其他人提到的那样,你在堆栈上创建了一个指针数组,需要分别对它们进行malloc和free。
但是,您不必一次使用malloc和free一个结构体,可以这样做:
int arraySize = 30;
student * ourArray = (student*)malloc(sizeof(student) * arraySize);

只需在指针上释放一次即可。有了这个指针,您仍然可以使用括号表示法,编译器将理解它是一个类型化的指针并适当地行为,从而为您提供基本相同的东西。使用哪种方法取决于您是否需要动态大小的数组以及个人喜好。

希望这能帮到您。


1

使用 NULL 值初始化指向结构体 student 的指针数组

for(i = 0; i < recordCtr; i++){
       array[i] = NULL;
  } 

如果array[i]不为NULL,则释放内存

for(i = 0; i < recordCtr; i++){
       if(NULL != array[i])
       {
           free(array[i]);
       }
  } 

我可以知道为什么需要初始化数组并将其设置为NULL吗?谢谢。 - newbie
@新手:除非你初始化指针数组,否则它们可能包含垃圾值。如果你试图释放一个垃圾值,你的C运行时往往会崩溃成一堆冒烟的炉渣。 - JeremyP
释放 NULL 指针是合法的。在释放循环中不需要进行空指针检查。 - JeremyP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接