c - 如何在 C 中正确地重新分配二维数组?

标签 c arrays realloc

我正在尝试将两个 double 从输入加载到一个二维数组中,该数组由每个用户输入动态重新分配。

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


int main(int argc, char** argv) {

    int count;
    double number1, number2, **numbers;

    while (scanf("%lf,%lf", number1, number2) != EOF) {

        count++;
        numbers = (double**) realloc(numbers, count * 2 * sizeof (double));
        if (numbers == NULL) {
            exit(1);
        }
        numbers[count][0] = number1;
        numbers[count][1] = number2;
    }

    return 0;
}

程序编译没有问题,但每次我尝试在数组中存储一个值时都会失败(这可能是内存问题)。

谁能告诉我如何在我的程序中正确地重新分配二维数组?

最佳答案

你有几个问题。

  1. 您没有初始化 numbers = 0;count = 0 因此在开始第一个 realloc() 之前变量中有一个不确定的值 调用。这是个坏消息。
  2. 更主要的问题是您误解了模拟二维数组所需的内存分配。
  3. 您的 scanf() 调用不正确;你没有传递指向它的指针。

ASCII 艺术

+---------+
| numbers |
+---------+
     |
     v
+------------+     +---------------+---------------+
| numbers[0] |---->| numbers[0][0] | numbers[0][1] |
+------------+     +---------------+---------------+
| numbers[1] |---->| numbers[1][0] | numbers[1][1] |
+------------+     +---------------+---------------+
| numbers[2] |---->| numbers[2][0] | numbers[2][1] |
+------------+     +---------------+---------------+

您实际上需要存储在numbers 中的指针、指针数组、 double 数组。目前,您没有为指针数组分配空间,这就是您遇到麻烦的原因。 double 组可以是连续的或不连续的(即每一行可以单独分配,但在一行内,当然分配必须是连续的)。

工作代码:

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

int main(void)
{
    int count = 0;
    double number1, number2;
    double **numbers = 0;

    while (scanf("%lf,%lf", &number1, &number2) != EOF)
    {
        numbers = (double **) realloc(numbers, (count + 1) * sizeof(*numbers));
        if (numbers == NULL)
            exit(1);
        numbers[count] = (double *)malloc(2 * sizeof(double));
        if (numbers[count] == 0)
            exit(1);
        numbers[count][0] = number1;
        numbers[count][1] = number2;
        count++;
    }

    for (int i = 0; i < count; i++)
        printf("(%8.2f, %8.2f)\n", numbers[i][0], numbers[i][1]);

    for (int i = 0; i < count; i++)
        free(numbers[i]);
    free(numbers);

    return 0;
}

注意:这仍然不是好的代码。特别是,使用中的每次增加一个机制是不好的。模因 pointer = realloc(pointer, newsize); 也很糟糕;如果分配失败,您将无法释放先前分配的内存。您应该使用 newptr = realloc(pointer, newsize);,然后在 pointer = newptr; 之前进行内存检查。

输入文件:

12.34,23.45
34.56,45.67
56.78,67.89
78.90,89.01

输出数据:

(   12.34,    23.45)
(   34.56,    45.67)
(   56.78,    67.89)
(   78.90,    89.01)

没有在 valgrind 下正式运行,但我相信它会没问题。


What is the best solution for saving inputs into array without knowing how many inputs I have to store ? Or maybe it is just this complicated in C compared to Java or PHP?

除了“增量一”部分,这是关于它在 C 中的工作方式,至少如果你想使用两个索引索引结果:numbers[i][0]

另一种方法是像您所做的那样分配空间(除了不是“递增一个”),然后使用表达式来索引数组:double *numbers = ...;numbers[i*2+0]numbers[i*2+1] 在你的情况下,但在更一般的情况下,数组有 ncols 列,使用 numbers[i*ncols + j] 访问行 i 和列 j。您用 numbers[i][j] 的符号便利性来换取内存分配的增加的复杂性。 (还要注意,对于这种机制,数组的类型是 double *numbers; 而不是 double **numbers;,就像你的代码中那样。)

避免“增加一个”的替代方案通常在每次分配时使用双倍的空间量。您可以决定使用 malloc() 进行初始分配,然后使用 realloc() 来增加空间,或者您可以只使用 realloc() 知道如果传入的指针为 NULL,那么它将执行与 malloc() 等效的操作。 (实际上,realloc() 是一个完整的内存分配管理封装在一个函数中;如果您以 0 大小调用它,它将free() 内存而不是分配.) 人们争论是否(ab)像那样使用realloc() 是个好主意。由于C89/C90及以后版本的C标准有保障,足够安全,省去了一次函数调用,所以我倾向于直接使用realloc():

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

static void free_numbers(double **array, size_t size)
{
    for (size_t i = 0; i < size; i++)
        free(array[i]);
    free(array);
}

int main(void)
{
    int count = 0;
    double number1, number2;
    double **numbers = 0;
    double maxnum = 0;

    while (scanf("%lf,%lf", &number1, &number2) != EOF)
    {
        if (count == maxnum)
        {
            size_t newnum = (maxnum + 2) * 2;   /* 4, 12, 28, 60, ... */
            double **newptr = (double **)realloc(numbers, newnum * sizeof(*numbers));
            if (newptr == NULL)
            {
                free_numbers(numbers, count);
                exit(1);
            }
            maxnum = newnum;
            numbers = newptr;
        }
        numbers[count] = (double *)malloc(2 * sizeof(double));
        if (numbers[count] == 0)
        {
            free_numbers(numbers, count);
            exit(1);
        }
        numbers[count][0] = number1;
        numbers[count][1] = number2;
        count++;
    }

    for (int i = 0; i < count; i++)
        printf("(%8.2f, %8.2f)\n", numbers[i][0], numbers[i][1]);

    free_numbers(numbers, count);

    return 0;
}

这段代码用valgrind检查没有问题;所有分配的代码都被释放。请注意使用函数 free_numbers() 来释放错误路径中的内存。当它在像此处这样的 main() 函数中运行时,这并不重要,但当工作在一个可能被许多程序使用的函数中完成时,这绝对是重要的。

关于c - 如何在 C 中正确地重新分配二维数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20036408/

相关文章:

c - 为什么不同结构指针之间的类型转换是可行的?

c - 我输入一个值以使循环精确运行,但它不起作用

javascript - 删除数组中不存在的索引元素上的运算符行为?

arrays - tcl 数组问题 - 带引号的键

c - 重新分配三重指针

python - 使用 Python 以外的语言为 Sublime Text 3 创建插件

C fscanf 和指针数组

c - 打印结构数组

c - 使用动态数组进行 realloc() 后的意外行为

c - 尝试在 C 中学习正确的内存处理——malloc、realloc 和 free