二维动态阵列(c中的realloc)

时间:2021-12-10 21:36:26

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 ?

有谁能告诉我如何正确地realloc新数组吗?

Thanks for any help.

感谢任何帮助。

3 个解决方案

#1


14  

You have a couple of problems.

你有几个问题。

  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. 不初始化数字= 0;或者count = 0,所以在开始第一个realloc()调用之前,变量中有一个不定式值。这是坏消息。
  3. The more major problem is that you've misunderstood the memory allocation that's needed to simulate a 2D-array.
  4. 更主要的问题是,您误解了模拟一个2d数组所需的内存分配。
  5. Your scanf() call is incorrect; you are not passing pointers to it.
  6. 您的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, 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).

实际上,您需要指针存储在数字、指针数组和double数组中。目前,您并没有为指针数组分配空间,这就是造成麻烦的原因。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;.

NB:这仍然不是很好的代码。特别是,使用的每一段时间机制是不好的。模因指针= realloc(指针,newsize);是不好的;如果分配失败,则不能释放先前分配的内存。你应该使用newptr = realloc(指针,newsize);在指针= 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中工作的方式,至少如果你想用两个索引来索引结果:数字[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 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.)

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

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大小调用它,它将释放()内存,而不是分配内存。人们争论像这样使用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 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.

这段代码是在没有问题的情况下进行的。所有分配的代码都被释放。注意使用函数free_numbers()释放错误路径中的内存。当它在main()函数中运行时,这并不重要,但是当工作在一个可以被许多程序使用的函数中完成时,这一点非常重要。

#2


1  

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,但是数组索引从0开始。

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++应该是可行的。但是,阅读其他用户发布的评论,你真的需要更好的方法来解决这个问题。

#3


0  

include

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

#1


14  

You have a couple of problems.

你有几个问题。

  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. 不初始化数字= 0;或者count = 0,所以在开始第一个realloc()调用之前,变量中有一个不定式值。这是坏消息。
  3. The more major problem is that you've misunderstood the memory allocation that's needed to simulate a 2D-array.
  4. 更主要的问题是,您误解了模拟一个2d数组所需的内存分配。
  5. Your scanf() call is incorrect; you are not passing pointers to it.
  6. 您的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, 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).

实际上,您需要指针存储在数字、指针数组和double数组中。目前,您并没有为指针数组分配空间,这就是造成麻烦的原因。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;.

NB:这仍然不是很好的代码。特别是,使用的每一段时间机制是不好的。模因指针= realloc(指针,newsize);是不好的;如果分配失败,则不能释放先前分配的内存。你应该使用newptr = realloc(指针,newsize);在指针= 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中工作的方式,至少如果你想用两个索引来索引结果:数字[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 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.)

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

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大小调用它,它将释放()内存,而不是分配内存。人们争论像这样使用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 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.

这段代码是在没有问题的情况下进行的。所有分配的代码都被释放。注意使用函数free_numbers()释放错误路径中的内存。当它在main()函数中运行时,这并不重要,但是当工作在一个可以被许多程序使用的函数中完成时,这一点非常重要。

#2


1  

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,但是数组索引从0开始。

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++应该是可行的。但是,阅读其他用户发布的评论,你真的需要更好的方法来解决这个问题。

#3


0  

include

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