使用realloc(X,0)代替free()并使用长度为+1的malloc +1

所以这次我真的不知道如何把这个头衔。 首先,我想说,如果问题与“家庭作业”有关,我在这个页面上看到了一些关于警告的评论。 我的是,但它也已完成,我只是想进一步了解代码发生了什么。

我已经阅读了一段时间的post和书籍,但我想我仍然缺少一些东西。

在我使用的代码中,我有两行代码,我不太明白。 这项工作是关于获取用作参数的任何文件(如果它是0个文件,它从stdin读取),并将其打印在标准输出上。 所有这些,谈论C,因为我试图放入标签。

第一个问题是:

array = realloc (array, 0); 

其中数组定义为

 char **array; 

而问题是免费不起作用,它没有释放使用的空间(也许我用错了?在其他地方我知道如何使用它,但不是这次)。 通过我已经完成的测试和我读过的内容,我相信realloc也在做同样的事情,但我不是100%。

第二个是:

 char* alloc = malloc (strlen ((char*)string)+1); 

其中alloc用于复制我要放入数组的行的确切长度,所以我可以在此之后向后打印文本。

问题是为什么我必须使用+1。 我的意思是如果由于某种原因我不使用它不起作用,我尝试使用不同的数字,它每次都有效,但如果我不这样做+1它不能正常工作。

我知道可能这个问题太模糊,写得不好真的得到回答但又一次,我不确定,我尽力解释自己(英语没有母语,因为它可能很明显)。

当C11(当前版本)时,大小为0时realloc的行为是不同的。 标准说(C11为7.20.3.1,C1x为7.22.3.1)

如果请求的空间大小为零,则行为是实现定义的:返回空指针,或者行为就像大小是非零值一样,但返回的指针不应用于访问对象

所以, free使用,不要依赖realloc

当通过char*处理字符串时,请记住为null终止符\0包含一个额外的字符。 这是显示字符串结束位置的常用方法(另一种是显式字符串长度)。

当使用mallocfree请记住它们必须完全匹配。 您需要free mallocrealloc返回的确切指针(值)。

array = realloc(array,0);

大小为零的Realloc在某些C实现上等同于free() ,但不是全部。

问题是免费不起作用,它没有释放所使用的空间

想一想char **array含义以及它在应用程序中的分配方式。 通常,指针指针用作二维数组,表示为数组数组。 大多数应用程序通过多次调用malloc()来分配它们。 array只是一个char *数组,其中该数组的每个元素都是一个char数组。 简单地在char *数组上调用free()将释放char *数组,但不释放每个char数组。

您需要多次调用free(), 如此处所述 。

我尝试了不同的数字,它每次都有效,但如果我不这样做,它就无法正常工作。

C字符串以空值终止 ,这意味着程序通过在字符串末尾放置一个空字符来跟踪字符串结束的位置。 这意味着长度为N的C字符串需要N个字符的空间,加上一个空字符。 然后,存储空间的总长度为N + 1。

第一个问题:

realloc(array, 0) 等于free(array)

标准(C99,§7.20.3.4¶1)说:

realloc函数解除分配ptr指向的旧对象,并返回指向具有size指定size的新对象的指针。

并且没有给出size==0 “特殊情况”; 所以,你得到一个指向大小为零的对象的指针 – 但它仍然是一个对象,但仍然必须被释放。

有趣的是,我认为realloc可能在这种情况下失败,返回NULL ; 在这种情况下,在你的代码中,内存被泄露,因为,当realloc失败时,它不会释放你传递给它的原始内存块(这就是你永远不会做array = realloc(array, size)但你总是使用中间变量检查NULL以避免内存泄漏)。

实际上,标准确实为所有内存分配函数指定了size==0实现定义的行为,而不仅仅是我记忆中的malloc ; 所以,行为是实现定义的,如下所示:

更直观地说, realloc在另一个指针上与malloc + memcpy + free “在概念上是等价的”,而malloc -an一个0字节的内存块返回NULL或者一个唯一的指针,不用于存储任何东西(你问过)对于0字节),但仍然是free 。 所以,不,不要像这样使用realloc ,它可能适用于某些实现(即Linux),但肯定不能保证。

此外,还不清楚你如何推断free无效。 我可以想到两种你可能已经确信的方法:

  1. array的值和它指向的数据不变;
  2. 任务管理器/ top分配的内存/不减少的内存。

对于第一种情况,这是正常的; 当你释放一个指针时,它不会神奇地被擦除 – 你的指针仍然指向它指向的位置,但是那个内存不再是你的 – 它现在又回到了C运行时,它可能在将来重新放弃它malloc 。 这就是为什么这个东西被称为“悬空指针”,许多人在free将其设置为NULL以避免再次在已经释放的内存空间中写入。

至于第二种,分配器的通用策略是不立即向操作系统返回内存(除非我们谈论的是非常大的块); 这个想法可能是应用程序很快就会再次需要这样的内存,并且保留当前进程的内存可以避免连续的系统调用从操作系统中获取/提供内存。 由于用于监视正常使用的内存的系统实用程序只能看到操作系统为进程提供的内容,因此它们不显示任何内存使用量减少是正常的。

顺便说一句,请记住,如果你的char ** array包含指向malloc分配的东西的指针,你必须先free它们,否则你就会泄漏内存。


第二个问题:

C字符串以空值终止,即字符串的最后一个字符始终为\0以标记字符串结尾,而strlen为您提供不包括空终止符的字符串长度。 因此,如果您不添加+1 ,则分配一个小于实际存储字符串所需内存的char


附录

通过不起作用我的意思是它确实崩溃了(问题可能已经在其他地方了)但是当我把它改为realloc(X,0)时它确实有效,在删除使用过的动态用过的内存的意义上

正如联机帮助页所说,

malloc(),calloc(),realloc()或free()中的崩溃几乎总是与堆损坏相关,例如溢出已分配的块或释放相同的指针两次。

您的代码中可能还有其他一些错误,但如果没有看到它,则无法确定错误的位置/位置。

关于第二个问题:

在C中,字符串应以空字符’\ 0’结尾。 当您使用strlen时,此字符不计算,但您需要为其分配足够的空间(即+1)。

如果您尝试打印不包含空字符的字符串,则可能会打印一些“随机”字符,但它也会崩溃。 如果使用strcpy,则会发生缓冲区溢出。

如果你希望保持兼容性, realloc(p,0)永远不会等同于free(p) ,并且没有后续释放的零分配是内存泄漏简单明了,即使在Linux上也是如此。

 /* leak.c */ #include  #include  int main(int argc, char* argv[]) { void* p; mtrace(); p = malloc(0x100); p = realloc(p, 0); exit(EXIT_SUCCESS); } $ cc -g leak.c -o leak $ export MALLOC_TRACE=/tmp/t $ ./leak $ mtrace ./leak $MALLOC_TRACE 

问题出在char **数组!! 这是怎么建的? 听起来它不是一个连续的mem块,它的构建如下:

 char **array = malloc(sizeof(char*)*size); for (size_t i=0; i< size; i++) { array[i] = malloc(strlen(string)+1); } 

如果是这种情况,那么每个数组索引都有它的随机内存块的单独指针! 在这种情况下,在清理arrays之前,您需要释放每个索引!

 for (size_t i=0; i 

同样使用realloc,NULL也可能意味着失败,因此你正在悬挂旧指针! 永远不会做

 foo= realloc(foo, new_size); 

 if (tmp = realloc(foo, new_size) ) { foo = tmp; } else { // clean your ram, how do you handle failure? free(foo);foo = NULL; // or you're ok without the new size,or try to realloc again // up to you }