【问题标题】:Reallocing and manipulating a 2d-array inside a function在函数内重新分配和操作二维数组
【发布时间】:2021-02-09 10:43:08
【问题描述】:

我正在尝试重新分配 2D 数组的两个元素,并在同一函数中操作 2D 数组中的值。但我似乎无法让它工作。编译代码时不会显示任何错误,但在运行时它只会打印我在 main 函数开头指定为 initial_size 的行数。

所以看起来内部realloc 工作正常,因为它总是在启动后打印一整行。但是外部的realloc 不起作用,因为它只会打印几行。

注意:真实代码从getchar()/scanf()获取未知大小的输入。这就是为什么 realloc 函数在函数的循环内。

函数的简化版本,省略了错误处理:

void func(int ***A) {
    int i, j;
    int len = 2;
    int len2 = 2;
    
    for (i = 0; i < 10; i++) {
        // Check to see if a realloc is needed.
        if (i >= len) {
            len *= 2;
            int **tmp = realloc(*A, len * sizeof(int*));
            *A = tmp;
            printf("Len1 = %d\n", len);
        }
        len2 = 2;
    
        for (j = 0; j < 20; j++) {
            // Check to see if a realloc is needed.
            if (j >= len2) {
                len2 *= 2;
                int *new_row = realloc((*A)[i], len2 * sizeof(int));
    
                (*A)[i] = new_row;
            }
            // Assign value.
            (*A)[i][j] = i * j;
        }
    }
}

int main() {
    int i, j;
    int initial_size = 2;
    int **A;
 
    // Malloc with a starting size of 2 (could be any size).
    A = malloc(initial_size * sizeof(int*));
    for (i = 0; i < initial_size; i++) {
        A[i] = malloc(initial_size * sizeof(int));
    }

    // Call function.
    func(&A);

    // Print the results, row by row.
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 20; j++) {
            printf("%d, ", A[i][j]);
        }
        printf("\n");
    }
    return 0;
}

我已经被困了一段时间,所以非常感谢任何帮助:)

【问题讨论】:

  • 考虑使用二维数组:Correctly allocating multi-dimensional arrays.
  • 为什么在循环中调用realloc(*A, len * sizeof(int*))?总体而言,此代码似乎不必要地复杂。 1. 计算新大小,2. 重新分配,3. 完成。
  • Realloc 处于循环中,因为真正的代码正在处理未知大小的输入。所以它会重新分配数据并将数据放入同一循环中的数组中。
  • @AstonKey:您可以通过点击分数下方的灰色复选标记来接受答案。

标签: arrays c multidimensional-array malloc realloc


【解决方案1】:

当您在外部循环中realloc 时,您将指针的数量从两个(在 main 中创建的指针)增加到四个。

来自main的两个指针的值被复制到新的内存区域。

两个新指针的值是不确定的,这是你的问题。您永远不会通过分配内存来初始化它们 - 但是您会在另一个循环中使用它们。

此外,您似乎 realloc 单独的内部数组维度,但您只跟踪一个长度(即 len2)。这也是个问题。

循环之间的len2 = 2 行是错误的,因为您丢失了有关先前分配的内存的信息。

【讨论】:

  • 谢谢!!那么我该如何修复这个错误呢?
  • @AstonKey 您需要通过为两个新指针分配内存来初始化它们——就像您在main 中使用前两个指针所做的那样。但是,还请阅读有关跟踪“内部”数组大小的部分...
  • @AstonKey 重新设置“内部”数组的大小。作为第一种方法,我建议您保持所有“内部”数组的大小相同。换句话说 - 在第二个循环中重新分配时,对 all 内部数组进行重新分配。
  • 请原谅我,因为我对 c(和一般编程)还很陌生,但是 realloc 函数不分配指定的内存,并返回新的指针吗?再次感谢您的帮助:)
  • @AstonKey 第一个循环中的 realloc 为新指针分配内存(第一次是 2 个新指针)。但是这些指针并不指向任何内存。您需要为此添加代码。
【解决方案2】:

您的代码存在多个问题:

  • 您重新分配了指针数组,但没有在新分配的部分初始化指针
  • 您只需重新分配指针数组指向的第一个int 数组
  • 你没有初始化这个int数组中新分配的区域。

请注意,二维矩阵在 C 中作为数组的数组更为惯用,但当外部维度在编译时不固定时,很难操作此类数组。

您应该为当前和目标大小使用具有指定维度的重新分配函数,并适当地处理重新分配和释放块。还要避免三重指针:只返回可能重新分配的外部数组。

#include <stdio.h>
#include <stdlib.h>

int **func(int **A, int rows, int cols, int new_rows, int new_cols) {
    int i, j;

    /* free the rows that are discarded */
    if (new_rows < rows) {
        for (i = new_rows; i < rows; i++) {
            free(A[i]);
        }
    }
    /* free the outer array if new rows is zero */
    if (new_rows == 0) {
        free(A);
        return NULL;
    }
    /* reallocate the outer array if required */
    if (new_rows != rows) {
        A = realloc(A, sizeof(*A) * new_rows);
    }
    /* reallocate the existing rows */
    if (new_cols != cols) {
        for (i = 0; i < rows; i++) {
            A[i] = realloc(A[i], sizeof(int) * new_cols);
            if (new_cols > cols) {
                for (j = cols; j < new_cols; j++)
                    A[i][j] = 0;
            }
        }
    }
    /* allocate the new rows (initialized to 0) */
    for (i = rows; i < new_rows; i++) {
        A[i] = calloc(sizeof(int), new_cols);
    }
    return A;
}

int main() {
    int **A = NULL;

    /* reallocate to 10x20 */
    A = func(A, 0, 0, 10, 20);

    // Print the results, row by row.
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 20; j++) {
            printf("%d, ", A[i][j]);
        }
        printf("\n");
    }
    /* reallocate to 0x0 (free the matrix) */
    func(A, 10, 20, 0, 0);
    return 0;
}

请注意,上面的代码不会检查内存分配失败。为了处理这种可能性,分配一个新数组并复制当前值会简单得多,然后如果没有发生分配错误,则释放前一个矩阵。将所有行分配为单个内存块也会更有效。下面是这种方法的一个例子:

#include <stdio.h>
#include <stdlib.h>

int **func(int **A, int rows, int cols, int new_rows, int new_cols) {
    int i, j;
    int **B = NULL;

    if (new_rows == rows && new_cols == cols)
        return A;

    if (new_rows != 0 && new_cols != 0) {
        /* allocate the new matrix */
        B = malloc(sizeof(*B) * new_rows);
        if (B == NULL)
            return NULL;
        B[0] = calloc(sizeof(int) * new_cols, new_rows);
        if (B[0] == NULL) {
            free(B);
            return NULL;
        }
        /* initialize the row pointers */
        for (i = 1; i < new_rows; i++) {
            B[i] = B[i - 1] + new_cols;
        }
        /* copy the current data */
        for (i = 0; i < new_rows && i < rows; i++) {
            for (j = 0; j < new_cols && j < cols; i++) {
                B[i][j] = A[i][j];
            }
        }
    }

    /* free the previous matrix */
    if (A != NULL) {
        free(A[0]);
        free(A);
    }
    return B;
}

int main() {
    int **A = NULL;
    int i, j;

    /* reallocate to 10x20 */
    A = func(A, 0, 0, 10, 20);
    if (A == NULL) {
        printf("Matrix reallocation failed\n");
        return 1;
    }

    // Print the results, row by row.
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 20; j++) {
            printf("%d, ", A[i][j]);
        }
        printf("\n");
    }
    /* reallocate to 0x0 (free the matrix) */
    func(A, 10, 20, 0, 0);
    return 0;
}

【讨论】:

  • 非常感谢!!如果您在运行时不知道尺寸 (10x20),您将如何处理?例如从输入读取直到到达 EOF?再次感谢!!
  • @AstonKey:你可以一次读取一行输入,你可以从第一行开始确定列数并为每一新行插入一个额外的行,然后你可以将值设置为您使用strtol() 解析该行
猜你喜欢
  • 2021-03-11
  • 1970-01-01
  • 1970-01-01
  • 2016-06-21
  • 2013-02-10
  • 2012-03-27
  • 1970-01-01
  • 1970-01-01
  • 2021-10-11
相关资源
最近更新 更多