如果我的问题有些含糊不清,我对C有点新手抱歉;
我需要在2D数组上使用realloc而不会丢失它以前的数据,我在我的程序中有这个功能:
void modifyMatrix(int **iMat, int iRow, int iRow2, int iCol)
{
int i;
iMat = (int**)realloc(iMat, (iRow2)*sizeof(int*));
for(i=iRow; i<iRow2; i++)
{
iMat[i]=NULL;
}
for(i=0; i<iRow2; i++)
{
iMat[i]=(int*)realloc(iMat[i], (iCol)*sizeof(int));
}
}
iRow的原始大小和iRow 2&amp; iCol是新的尺寸,并且都在该计划的其他地方被捕获。
每当我尝试打印矩阵时,我一直在添加的行和列上获取垃圾数据或内存值,我做错了什么?
如果您需要完整的代码或任何其他问题需要澄清,请提前告知我们!
编辑: 您可以在下面看到我用来创建Matrix的代码
我的不好,我想我应该补充一点,已经在程序的其他地方创建了Matrix,这个功能我只是想修改尺寸,感谢快速响应btw!,下面你可以找到我用来创建数组的函数
void createMatrix(int ***iMat, int iRow, int iCol)
{
int **iRow2 = (int**)calloc(iRow, sizeof(int*));
int i;
for (i=0; i<iRow; i++)
{
iRow2[i] = (int*)calloc(iCol, sizeof(int));
}
*iMat=iRow2;
}
另外,我只能使用已创建的数组来执行此操作,我无法创建临时数据(我知道这是一种简单的方法)
答案 0 :(得分:0)
在c中,变量按值传递,因此iMat
内的modifyMatrix()
不会修改调用函数中的iMat
。
您需要传递void modifyMatrix(int ***iMat, int iRow, int iRow2, int iCol)
{
int i;
int **safe;
safe = realloc(*iMat, iRow2 * sizeof(int *));
if (safe == NULL)
return;
*iMat = safe;
for (i = 0 ; i < iRow ; i++)
{
int *keep_old_pointer;
keep_old_pointer = realloc(safe[i], iCol * sizeof(int));
if (keep_old_pointer == NULL)
do_something_allocation_failed();
safe[i] = keep_old_pointer;
}
for (int i = iRow ; i < iRow2 ; ++i)
safe[i] = malloc(iCol * sizeof(int));
}
的地址
NULL
另外,不要为每个元素分配realloc()
,然后尝试realloc()
,因为如果NULL
在这种情况下有意义,那么你用{{1}覆盖指针没有释放它们。
并且在检查分配是否成功之前不要覆盖realloc()
ed指针,因为如果它失败了你将无法释放先前的指针,因为你会丢失对它的引用,导致记忆泄漏。
答案 1 :(得分:0)
成功时,realloc
释放传递给它的指针,并返回指向新分配的内存的指针。你得到“垃圾值”,因为解除引用释放内存的指针是未定义的行为。
它并不漂亮,但修复此问题的方法(如另一个答案所指出)是传递三重指针(int***
)。这样,该函数可以修改指针的原始值。这就是你在C中模拟引用语义的方法,它是一种严格的“按值传递”语言。
void modifyMatrix(int ***iMat, int iRow, int iRow2, int iCol)
{
int i;
int **newMatrix = realloc(*iMat, iRow2 * sizeof(int*));
if (newMatrix == NULL) {
/* handle realloc error here */
}
else {
*iMat = newMatrix; /* assign pointer to the new memory */
}
for(i=iRow; i<iRow2; i++)
{
(*iMat)[i]=NULL;
}
for(i = 0; i < iRow2; i++)
{
int* newRow = realloc((*iMat)[i], (iCol)*sizeof(int));
if (newRow == NULL) {
/* handle realloc error here */
}
else {
(*iMat)[i] = newRow;
}
}
}
您还必须添加一些错误检查。如果realloc失败并返回一个NULL指针,那么你刚刚创建了一个内存泄漏:你不再拥有指针的先前值。
请注意,我删除了所有演员表。这在C中是不好的做法to cast the return of malloc and friends。
答案 2 :(得分:0)
当你将一个函数指针数组传递给realloc
时,你基本上有2个选择; (1)将数组的地址传递给函数(即&array
)作为参数,这意味着您的函数定义将是reallocfoo (int ***array, size_t* size)
或(2)在调用例程中分配函数的返回值。 (例如array = reallocfoo (array, &size);
)
由于您已经获得了(1)的答案,让我们看看如何实现和使用(2)。 注意:没有必要让你的函数成为数组的type
,它只是返回一个内存地址,所以使用通用的void
指针就可以了。例如:
void *xrealloc2 (void **memptr, size_t *n)
{
void *tmp = realloc (memptr, *n * 2 * sizeof tmp);
if (!tmp) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
return NULL;
}
memptr = tmp;
memset (memptr + *n, 0, *n * sizeof tmp);
*n *= 2;
return memptr;
}
同样注意,因为你正在重新分配指针数组,所以不需要传递类型大小(指针是指针是一个指针 - 在我们关心的所有情况下) 。将此工作,因为您没有传递数组的地址,您将需要分配返回以完成重新分配。 (就像你在上面的代码中所做的那样),例如:
if (ridx == rmax) /* if realloc is needed */
ia = xrealloc2 ((void **)ia, &rmax);
注意:当前指针数(rmax
)作为指针传递,因此其值可以在重新分配函数中更新为当前两倍。 (所以下次用完时,可以根据正确更新的当前数字重新分配)。将所有部分组合在一起,您会得到一个简短的示例,它只会强制重新分配两次。此外,原始分配也放在一个函数中,以保持代码主体整洁,并返回检查函数中的分配。 (您可以决定如何处理内存耗尽 - NULL
返回或exit
,两个函数中都显示了两者的示例)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define RMAX 2
#define COLS 5
void *xcalloc (size_t n, size_t s);
void *xrealloc2 (void **memptr, size_t *n);
int main (void) {
int **ia = NULL;
size_t rmax = RMAX;
size_t rows = 0;
size_t ridx = 0, cidx = 0;
srand (2275311); /* arbitrary repeatable seed */
ia = xcalloc (RMAX, sizeof *ia);
/* intentionally force reallocation */
while (ridx < 3 * RMAX) {
ia[ridx] = xcalloc (COLS, sizeof **ia);
for (cidx = 0; cidx < COLS; cidx++)
ia[ridx][cidx] = rand () % 1000 + 1;
ridx++;
if (ridx == rmax)
ia = xrealloc2 ((void **)ia, &rmax);
}
rows = ridx;
printf ("\n the reallocated 2D array elements are:\n\n");
for (ridx = 0; ridx < rows; ridx++) {
for (cidx = 0; cidx < COLS; cidx++)
printf (" %4d", ia[ridx][cidx]);
putchar ('\n');
}
putchar ('\n');
for (ridx = 0; ridx < rows; ridx++)
free (ia[ridx]);
free (ia);
return 0;
}
/** xcalloc allocates memory using calloc and validates the return.
* xcalloc allocates memory and reports an error if the value is
* null, returning a memory address only if the value is nonzero
* freeing the caller of validating within the body of code.
*/
void *xcalloc (size_t n, size_t s)
{
register void *memptr = calloc (n, s);
if (memptr == 0)
{
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
return memptr;
}
/* realloc array of pointers ('memptr') to twice current
* number of pointer ('*nptrs'). Note: 'nptrs' is a pointer
* to the current number so that its updated value is preserved.
* no pointer size is required as it is known (simply the size
* of a pointer
*/
void *xrealloc2 (void **memptr, size_t *n)
{
void *tmp = realloc (memptr, *n * 2 * sizeof tmp);
#ifdef DEBUG
printf ("\n reallocating %zu to %zu\n", *n, *n * 2);
#endif
if (!tmp) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
return NULL;
}
memptr = tmp;
memset (memptr + *n, 0, *n * sizeof tmp);
*n *= 2;
return memptr;
}
在编译代码并运行它之后,它将确认而不是仅仅最初分配的最大2
行(指针),重新分配两次,将该数字增加到8
(例如{{1}所以分配的所有6行整数都已正确分配:
2->4->8
如果您有任何疑问,请与我们联系。不要忘记,始终运行通过 the reallocated 2D array elements are:
155 573 760 410 956
553 271 624 625 934
259 291 811 161 185
756 211 16 6 449
124 869 353 210 317
310 181 897 866 831
(或类似的内存检查器)分配或重新分配的任何代码,以确保您的内存使用正确并且您分配的所有内存都是免费的。
valgrind
您可以使用==29608== Memcheck, a memory error detector
==29608== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==29608== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==29608== Command: ./bin/realloc2d
==29608==
the reallocated 2D array elements are:
<snip>
==29608==
==29608== HEAP SUMMARY:
==29608== in use at exit: 0 bytes in 0 blocks
==29608== total heap usage: 9 allocs, 9 frees, 232 bytes allocated
==29608==
==29608== All heap blocks were freed -- no leaks are possible
==29608==
==29608== For counts of detected and suppressed errors, rerun with: -v
==29608== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
标志编译上面的代码,以便在每次重新分配时将其打印到-DDEBUG
并提供当前分配的指针计数。祝你好运。