最大的误解是您将answer 按值传递给add(),因此add() 收到一个副本,并且add() 中对answer 的任何更改都会在函数返回时丢失。由于类型是void,因此您无法更改调用者中看到的answer(此处为main())
要解决此问题,请将answer 的地址传递给add(),以便在realloc() 而不是calloc() 将大小加倍时对原始指针地址进行操作,例如
void add(Statistician *answer, int *SIZE){
void *tmp = realloc(*answer, *SIZE * 2 * sizeof **answer);
if (!tmp) {
perror ("add-realloc-answer");
return;
}
*answer = tmp;
/* optional - zero new memory mimicking calloc() */
memset (*answer + *SIZE, 0, *SIZE * sizeof **answer);
*SIZE *= 2;
}
你调用 add like:
add(&answer, &SIZE);
(注意,SIZE 必须是正确初始化的全局int。它实际上应该在main() 的开头替换为size_t size = SIZE;,然后传递一个指向size 的指针。
您的困惑更加复杂,因为您键入指针,请参阅Is it a good idea to typedef pointers?。另外,在C语言中,malloc(或calloc,或realloc)的返回不需要强制转换,没有必要。见:Do I cast the result of malloc?
消除指针的typedef
为了使指针间接级别保持明显,避免指针的typedef 并在需要类型的地方简单地使用int* 要容易得多。进行这些更改,并使用局部变量 size 更改 SIZE 的使用,以确保作为参数传递的任何本地副本不会与全局变量冲突。添加简单的例程来填充每个整数并在 add() 之前/之后验证每个整数,首选方法是:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 128
int *add (int **answer, size_t *size)
{
/* always realloc to a temporary pointer, when realloc fails
* it returns NULL and if you assign to original pointer you
* create a memory leak with loss of your stored data.
*/
void *tmp = realloc(*answer, *size * 2 * sizeof **answer);
if (!tmp) { /* validate every allocation */
perror ("add-realloc-answer");
return NULL;
}
*answer = tmp; /* assign reallocated block to pointer */
/* optional - zero new memory mimicking calloc() */
memset (*answer + *size, 0, *size * sizeof **answer);
*size *= 2; /* update size only on success */
return *answer; /* return pointer indicating success */
}
int main(void) {
int *answer;
size_t size = SIZE;
answer = calloc(size, sizeof *answer); /* allocate */
if (answer == NULL) { /* validate */
perror ("calloc-answer");
return 1;
}
for (size_t i = 0; i < size; i++) /* fill memory */
answer[i] = i;
if (!add(&answer, &size)) /* add and validate return */
fputs ("realloc failed, using original size.\n", stderr);
else
printf ("realloc succeeded -- %zu integers.\n", size);
for (size_t i = size/2; i < size; i++) /* fill new memory */
answer[i] = i;
for (size_t i = 0; i < size; i++) /* validate complete block */
if (i != (size_t)answer[i])
fprintf (stderr, "error: answer[%zu] != %d\n", i, answer[i]);
free (answer); /* free allocated memory */
}
注意:由于realloc() 可能会失败,因此您的函数需要一种将成功或失败返回给调用者的方法。选择一个有意义的返回类型(int0/1或指针valid address/NULL等...)
使用/输出示例
$ ./bin/realloc-add
realloc succeeded -- 256 integers.
内存使用/错误检查
在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您都有 2 个职责:(1)始终保留指向起始地址的指针内存块,因此,(2) 当不再需要它时可以释放。
您必须使用内存错误检查程序来确保您不会尝试访问内存或写入超出/超出分配块的边界,尝试读取或基于未初始化的值进行条件跳转,最后, 以确认您已释放所有已分配的内存。
对于 Linux,valgrind 是正常的选择。每个平台都有类似的内存检查器。它们都易于使用,只需通过它运行您的程序即可。
$ valgrind ./bin/realloc-add
==8594== Memcheck, a memory error detector
==8594== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8594== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==8594== Command: ./bin/realloc-add
==8594==
realloc succeeded -- 256 integers.
==8594==
==8594== HEAP SUMMARY:
==8594== in use at exit: 0 bytes in 0 blocks
==8594== total heap usage: 3 allocs, 3 frees, 2,560 bytes allocated
==8594==
==8594== All heap blocks were freed -- no leaks are possible
==8594==
==8594== For counts of detected and suppressed errors, rerun with: -v
==8594== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认您已释放已分配的所有内存并且没有内存错误。
如果您还有其他问题,请告诉我。