在2D数组上使用realloc c

如果我的问题有些模糊,我对C有点不好意思。

我需要在2D数组上使用realloc而不会丢失它以前的数据,我在我的程序中有这个function:

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和iCol是新尺寸,并且都在程序的其他地方捕获。

每当我尝试打印矩阵时,我一直在添加的行和列上获取垃圾数据或内存值,我做错了什么?

如果您需要完整的代码或任何其他问题需要澄清,请提前告知我们!

编辑:下面你可以看到我用来创建Matrix的代码

我的坏,我想我应该补充说矩阵已经在程序的其他地方创建了,这个function我只是想修改尺寸,感谢快速响应btw!,下面你可以找到与之相关的function我正在创建数组

 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; } 

此外,我只能使用我已经创建的数组来执行此操作,我无法创建临时数据(我知道这将是一种简单的方法)

在c中,变量按值传递,因此, modifyMatrix()内的modifyMatrix()不会修改调用函数中的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覆盖指针而不释放它们。

并且在检查分配是否成功之前不要覆盖realloc() ed指针,因为如果它失败,你将无法释放前一个指针,因为你将丢失对它的引用,导致内存泄漏。

当你将一个指向数组的函数传递给realloc ,你基本上有两个选择; (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  #include  #include  #include  #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 (例如2->4->8 ),因此所有6行整数分配正确分配:

  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:  ==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标志编译上面的代码,以便在每次重新分配时将其打印到stdout并提供当前分配的指针计数。 祝好运。

成功时, 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 

您还必须添加一些错误检查。 如果realloc失败并返回NULL指针,那么您刚刚创建了内存泄漏:您不再具有指针的先前值。

请注意,我删除了所有演员表。 在C中投射malloc和朋友的回报是不好的做法。