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

查看:131
本文介绍了如何在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. 更主要的问题是您误解了模拟2D阵列所需的内存分配.
  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] |
+------------+     +---------------+---------------+

您实际上需要存储在数字中的指针,指针数组, 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?

除了递增1"部分外,这与它在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.

一种替代方法是按您的方式分配空间(除非不是递增1"),然后使用表达式对数组进行索引: 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()知道如果传入的指针为NULL,则它将等效于 malloc().(实际上, realloc()是一个完整的内存分配管理包;在一个函数中,如果调用它的大小为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天全站免登陆