如何在C中正确重新分配二维数组? [英] How to properly reallocate a two-dimensional array in C?

查看:25
本文介绍了如何在C中正确重新分配二维数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将输入中的两个双精度数加载到一个二维数组中,该数组由每个用户输入动态重新分配.

I am trying to load two double numbers from input into a two-dimensional array that is dynamically reallocated by each user input.

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

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

The program compiles without problems, but it fails every time I try to store a value in the array (it is likely a memory problem).

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

Can someone show me how to properly reallocate the two-dimensional array in my program?

推荐答案

你有几个问题.

  1. 您没有初始化 numbers = 0;count = 0 所以在开始第一个 realloc() 之前,变量中有一个不确定的值 调用.这是个坏消息.
  2. 更主要的问题是您误解了模拟二维数组所需的内存分配.
  3. 您的scanf() 调用不正确;你没有传递指向它的指针.
  1. You don't initialize numbers = 0; or count = 0 so you have an indeterminate value in the variable before you start the first realloc() call. That's bad news.
  2. The more major problem is that you've misunderstood the memory allocation that's needed to simulate a 2D-array.
  3. Your scanf() call is incorrect; you are not passing pointers to it.

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 数组.目前,您没有为指针数组分配空间,这就是您遇到麻烦的原因.双精度数组可以是连续的也可以是不连续的(即每一行可以单独分配,但在一行内,分配当然必须是连续的).

You actually need the pointer stored in numbers, the array of pointers, and the array of double. At the moment, you are not allocating the space for the array of pointers, and this is the cause of your troubles. The array of doubles can be contiguous or non-contiguous (that is, each row may be separately allocated, but within a row, the allocation must be contiguous, of course).

工作代码:

#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; 之前进行内存检查.

NB: This is still not good code. In particular, the increment-by-one-each-time mechanism in use is bad. The meme pointer = realloc(pointer, newsize); is bad too; you can't release the previously allocated memory if the allocation fails. You should use newptr = realloc(pointer, newsize); followed by a memory check before 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 下正式运行,但我相信它会没事的.

Not formally run under valgrind, but I'm confident it would be OK.

在不知道必须存储多少个输入的情况下将输入保存到数组中的最佳解决方案是什么?或者,与 Java 或 PHP 相比,C 语言可能就这么复杂?

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]

Except for the 'increment by one' part, this about the way it has to work in C, at least if you want to index into the result using two indexes: numbers[i][0] etc.

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

An alternative would be to allocate the space as you were doing (except not 'incrementing by one'), and then using an expression to index the array: double *numbers = ...; and numbers[i*2+0] and numbers[i*2+1] in your case, but in the more general case of an array with ncols columns, accessing row i and column j using numbers[i*ncols + j]. You trade the notational convenience of numbers[i][j] against the increased complication of memory allocation. (Note, too, that for this mechanism, the type of the array is double *numbers; instead of double **numbers; as it was in your code.)

避免递增一个"的替代方案通常在每次分配时使用双倍的空间量.您可以决定使用 malloc() 进行初始分配,然后使用 realloc() 来增加空间,或者您可以只使用 realloc()code> 知道如果传入的指针是 NULL,那么它会做等价于 malloc() 的事情.(实际上,realloc()是一个完整的内存分配管理包在一个函数中;如果你用size 0调用它,它会free()内存而不是分配内存.) 人们争论(ab)像这样使用 realloc() 是否是一个好主意.由于C89/C90及以后的C标准有保证,足够安全,而且省去了一个函数调用,所以我倾向于只用realloc():

The alternatives avoiding 'increment by one' typically use a doubling of the amount of space on each allocation. You can decide to do an initial allocation with malloc() and subsequently use realloc() to increase the space, or you can use just realloc() knowing that if the pointer passed in is NULL, then it will do the equivalent of malloc(). (In fact, realloc() is a complete memory allocation management package in one function; if you call it with size 0, it will free() the memory instead of allocating.) People debate whether (ab)using realloc() like that is a good idea or not. Since it is guaranteed by the C89/C90 and later versions of the C standard, it is safe enough, and it cuts out one function call, so I tend to use just 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() 函数中运行时,这并不重要,但当在一个可能被许多程序使用的函数中完成工作时,这绝对重要.

This code was checked with valgrind without problems; all code allocated was freed. Note the use of the function free_numbers() to release the memory in the error paths. That's not critical when it is running in a main() function like here, but is definitely important when the work is done in a function that may be used by many programs.

这篇关于如何在C中正确重新分配二维数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆