C语言 二维动态数组(c 中的 realloc)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20036408/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 10:19:22  来源:igfitidea点击:

two-dimensional dynamic array (realloc in c)

carraysrealloc

提问by Pastx

I am trying to load two double numbers from input to two-dimensional array dynamicaly realocated by every 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;
}

Program fails every time i try to save value into array (probably memory problem). It is compiled without problems.

每次我尝试将值保存到数组中时程序都会失败(可能是内存问题)。它编译没有问题。

Can anyone show me how to properly realloc new array ?

谁能告诉我如何正确地重新分配新数组?

Thanks for any help.

谢谢你的帮助。

回答by Jonathan Leffler

You have a couple of problems.

你有几个问题。

  1. You don't initialize numbers = 0;or count = 0so 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.
  1. 在您开始第一次调用之前,您没有初始化,numbers = 0;或者count = 0您在变量中有一个不确定的值realloc()。这是个坏消息。
  2. 更主要的问题是您误解了模拟二维数组所需的内存分配。
  3. 您的scanf()电话有误;你没有传递指向它的指针。

ASCII Art

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] |
+------------+     +---------------+---------------+

You actually need the pointer stored in numbers, the array of pointers, andthe 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).

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

Working code:

工作代码:

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

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;.

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

Input file:

输入文件:

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

Output data:

输出数据:

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

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

没有正式运行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?

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

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.

除了“递增一个”部分之外,这与它在 C 中的工作方式有关,至少如果您想使用两个索引对结果进行索引:numbers[i][0]等等。

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 ncolscolumns, accessing row iand column jusing 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.)

另一种方法是分配的空间作为你在做(“由一个递增”除了不是),然后使用表达式来索引数组:double *numbers = ...;numbers[i*2+0]numbers[i*2+1]你的情况,但在与阵列的更一般的情况ncols列使用.访问行i和列。您可以在符号上的便利与内存分配的增加的复杂性之间进行权衡。(注意,那就是,对于这一机制,数组的类型,而不是因为它是在你的代码。)jnumbers[i*ncols + j]numbers[i][j]double *numbers;double **numbers;

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():

避免“递增一个”的替代方案通常使用每次分配的空间量加倍。您可以决定使用初始分配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;
}

This code was checked with valgrindwithout 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.

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

回答by wybourn

You're incrementing the count variable too early. The first value it will index into the array will be one, however array indexing starts at zero.

您过早地增加了计数变量。它将索引到数组中的第一个值将为 1,但是数组索引从零开始。

Having the count++ after assigning the new values and initializing count to zero should work. However, read the comments other users have posted, you really want a nicer approach to this problem.

在分配新值并将计数初始化为零后使用 count++ 应该可以工作。但是,请阅读其他用户发布的评论,您真的想要一个更好的方法来解决这个问题。

回答by Leonardo Gabriel Calautti

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

void agregar_int(int **,int);
void agregar_char(char **,int); 
char **tz=NULL;
int **tr=0;
int a;

int  main(void){
    a=2;
    for (a=1;a<100;a++)
    {
        agregar_int(tr,a);
    }
    for (a=1;a<100;a++)
    {
        agregar_char(tz,a);
    }
}

agregar_int (int **tr,int a)
{
    printf ("%d----------------------------------------------\n",a);    
    tr = (int**) realloc (tr, (a+1) * sizeof(*tr));
    tr[a] = (int *) malloc (5 * sizeof(int));
    tr[a][0]=a; tr[a][1]=a;tr[a][2]=a;tr[a][3]=a;tr[a][4]=a;
    printf("%d \t %d \t %d \t %d \t %d  \n",tr[a][0],tr[a][1],tr[a][2],tr[a][3],tr[a][4]);
}

agregar_char (char **tz,int a)
{
    printf ("%d----------------------------------------------\n",a);    
    tz = (char**) realloc (tz, (a+1) * sizeof(*tz));
    tz[a] = (char *) malloc (7 * sizeof(char));
    tz[a][0]='E'; tz[a][1]='s';tz[a][2]='t';tz[a][3]='e';tz[a][4]='b',tz[a][5]='a',tz[a][6]='n';
    printf("%c%c%c%c%c%c%c \n",tz[a][0],tz[a][1],tz[a][2],tz[a][3],tz[a][4],tz[a][5],tz[a][6]);
}