在2D数组c

时间:2015-10-08 05:16:30

标签: c arrays realloc

如果我的问题有些含糊不清,我对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;
}

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

3 个答案:

答案 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并提供当前分配的指针计数。祝你好运。