我有一个程序,它以存储在动态数组中的至少10个响应(int(开始,但如果需要,应该使用void函数使大小翻倍。
typedef int* Statistician;
int main(int argc, char** argv) {
Statistician answer;
answer=(int*)calloc(SIZE,sizeof(int));
add(answer, &SIZE);
}
void add(Statistician answer, int *SIZE){
answer=(int*)calloc(*SIZE * 2,sizeof(int));
}
这是把它的尺寸扩大一倍的正确方法吗?我需要朝着正确的方向轻轻一推。
最大的误解是您将answer
按值传递给add()
,因此add()
会收到一份副本,而add()
中对answer
的任何更改都会在函数返回时丢失。由于类型是void
,您没有机会对调用方(此处为main()
(中的answer
进行更改
要解决此问题,请将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
(。
由于类型定义了指针,您的困惑更加复杂,请参阅typedef指示器是个好主意吗?。此外,在C中,不需要强制转换malloc
(或calloc
,或realloc
(的返回,这是不必要的。请参阅:我是否投射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] != %dn", i, answer[i]);
free (answer); /* free allocated memory */
}
注意:由于realloc()
可能会失败,因此您的函数需要一种方法将成功或失败传达给调用者。选择有意义的返回类型(int
0/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)
请始终确认您已经释放了分配的所有内存,并且没有内存错误。
如果您还有其他问题,请告诉我。