8

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

我也阅读了一段时间的帖子和书籍,但我认为我仍然缺少一些东西。

在我使用的代码中,我有两行我不太了解的代码。这项工作是关于获取用作参数的任何文件(如果它是 0 个文件,则从标准输入读取),并将其向后打印到标准输出上。所有这一切,在我试图放入标签时谈论 C。

第一个问题是这样的:

array = realloc (array, 0);

其中数组定义为

char **array;

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

第二个是:

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

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

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

我知道这个问题可能太模糊而且写得不好,无法真正得到回答,但同样,我不确定这一点,我尽我所能解释自己(英语没有母语,因为这可能很明显)。

4

6 回答 6

8

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

如果请求的空间大小为零,则行为是实现定义的:要么返回空指针,要么行为好像大小是某个非零值,但返回的指针不应用于访问对象

所以,使用free而不是依赖realloc.

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

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

于 2013-05-26T14:13:05.743 回答
3

数组 = realloc(数组,0);

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

问题是 free 不起作用,它不会释放使用的空间

考虑一下char **array在您的应用程序中分配的方式和方式。指针到指针通常用作二维数组,表示为数组的数组。大多数应用程序通过多次调用 malloc() 来分配这些。array只是一个 的数组char *,其中该数组的每个元素都是 的数组char。简单地在数组上调用 free()char *将释放 的数组char *,但不会释放 的每个数组char

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

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

C 字符串是空终止的,这意味着程序通过在字符串末尾放置一个空字符来跟踪字符串的结束位置。这意味着长度为 N 的 C 字符串需要 N 个字符的空间,外加一个 nul 字符。那么内存空间的总长度为N+1。

于 2013-05-26T13:59:47.353 回答
2

第一个问题:

realloc(array, 0)不等于。_free(array)

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

realloc函数释放 所指向的旧对象,ptr并返回一个指向具有 指定大小的新对象的指针size

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

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

实际上,该标准确实size==0为所有内存分配函数指定了实现定义的行为,而不仅仅是malloc我记得的那样;因此,行为是实现定义的,如下所述:

更直观地说,在另一个指针上与 to ++“概念上等效”,并且-ingrealloc一个malloc0字节的内存块返回一个唯一的指针,不用于存储任何东西(您要求 0 字节),但是仍有待编辑。所以,不,不要那样使用,它可能适用于某些实现(即 Linux),但肯定不能保证。memcpyfreemallocNULLfreerealloc

此外,目前尚不清楚您是如何推断出这free行不通的。我可以想到两种你可能已经确信这一点的方法:

  1. array它指向的数据的值和值不变;
  2. 任务管理器中分配的内存top//无论什么都没有减少。

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

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

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


第二个问题:

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


附录

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

正如手册页所说,

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

您的代码中可能还有其他一些错误,但是如果没有看到它,就不可能知道哪里/哪里出了问题。

于 2013-05-26T14:13:30.637 回答
1

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

/* leak.c */
#include <mcheck.h>
#include <stdlib.h>
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
于 2013-09-11T15:49:39.810 回答
1

关于第二个问题:

在 C 中,字符串应以空字符 '\0' 终止。当你使用 strlen 时,这个字符不会被计算在内,但你需要为它分配足够的空间(即 +1)。

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

于 2013-05-26T13:52:34.227 回答
-1

问题在于 char **array !那是怎么建的?听起来它不是一个连续的内存块,它的构建方式如下:

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

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

for (size_t i=0; i<size; i++) {
    free(array[i]);
}
free(array);

同样使用 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
}
于 2018-08-16T20:02:21.820 回答