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

时间:2013-11-17 21:29:35

标签: c arrays realloc

我正在尝试将两个双数字从输入加载到每个用户输入动态调整的二维数组。

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

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

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

感谢您的帮助。

3 个答案:

答案 0 :(得分:16)

你有几个问题。

  1. 您没有初始化numbers = 0;count = 0,因此在开始第一次realloc()调用之前,您在变量中有一个不确定的值。这是个坏消息。
  2. 更主要的问题是你误解了模拟2D阵列所需的内存分配。
  3. 您的scanf()来电不正确;你没有传递指针。
  4. 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数组。目前,您没有为指针数组分配空间,这是您遇到麻烦的原因。双精度数组可以是连续的也可以是非连续的(也就是说,每行可以单独分配,但在一行中,分配必须是连续的)。

    工作代码:

    #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下运行,但我相信它会没事。


      

    在不知道我必须存储多少输入的情况下,将输入保存到阵列的最佳解决方案是什么?或者,与Java或PHP相比,它可能只是在C中复杂化了吗?

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

    另一种方法是按照您的方式分配空间(除非“递增1”除外),然后使用表达式索引数组:double *numbers = ...;numbers[i*2+0]以及{{1在您的情况下,但在更一般的情况下,使用numbers[i*2+1]列的数组,使用ncols访问行i和列j。您将numbers[i*ncols + j]的符号方便性与增加的内存分配复杂性进行了交换。 (另请注意,对于此机制,数组的类型为numbers[i][j],而不是代码中的double *numbers;。)

    避免“逐一增加”的替代方案通常使用每次分配的空间量加倍。您可以决定使用double **numbers;进行初始分配,然后使用malloc()来增加空间,或者只使用realloc()知道如果传入的指针是NULL,那么它将会做相当于realloc()。 (实际上,malloc()是一个函数中的完整内存分配管理包;如果用大小0调用它,它将realloc()内存而不是分配。)人们争论是否(ab)使用{ {1}}这样的好主意是不是。由于它是由C89 / C90及更高版本的C标准保证的,它足够安全,并且它会切断一个函数调用,所以我倾向于仅使用free()

    realloc()

    使用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函数中运行时,这并不重要,但是当工作在可能被许多程序使用的函数中完成时,这绝对是重要的。

答案 1 :(得分:1)

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

在分配新值并将计数初始化为零后得到count ++应该有效。 但是,阅读其他用户发布的评论,你真的想要一个更好的方法解决这个问题。

答案 2 :(得分:0)

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