【问题标题】:How to properly reallocate a two-dimensional array in C?如何在 C 中正确重新分配二维数组?
【发布时间】:2013-11-30 22:21:29
【问题描述】:

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

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

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

有人可以告诉我如何在我的程序中正确地重新分配二维数组吗?

【问题讨论】:

  • 这是一个非常。插入值时每次重新分配内存的一种非常非常糟糕的方法。
  • 使用不确定的指针numbers 执行此操作也是一个非常非常糟糕的主意,它作为第一个参数传递给realloc()。至少那个东西应该被初始化为NULL。而且您的scanf() 应该检查==2,而不仅仅是EOF。
  • 数组不是指针。您试图将指针指针视为数组数组,但事实并非如此。搜索重复,已经有几十个相同的问题了。
  • 此外,即使numberscount 元素的数组numbers[count] 也将无效。数组索引从零开始。
  • 我在这里找到了这个简单的数组stackoverflow.com/questions/2937409/resizing-an-array-with-c 所以我想为什么它不适用于二维

标签: c arrays realloc


【解决方案1】:

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

在分配新值并将 count 初始化为零之后使用 count++ 应该可以工作。 但是,阅读其他用户发布的 cmets,您确实需要更好的方法来解决这个问题。

【讨论】:

  • 我希望有人能告诉我解决这个问题的更好方法。我在 java 和 php 编程了一段时间,从来没有处理过内存分配问题。
【解决方案2】:

你有几个问题。

  1. 您没有初始化numbers = 0;count = 0,因此在开始第一个realloc() 调用之前,变量中有一个不确定的值。这是个坏消息。
  2. 更大的问题是您误解了模拟二维数组所需的内存分配。
  3. 您的scanf() 呼叫不正确;你没有传递指向它的指针。

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] 等。

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

避免“以一为增量”的替代方案通常在每次分配时使用双倍的空间量。您可以决定使用malloc() 进行初始分配,然后使用realloc() 来增加空间,或者您可以只使用realloc(),知道如果传入的指针为NULL,那么它将相当于@987654349 @。 (其实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;
}

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

【讨论】:

  • 非常感谢。我只是想问在不知道我必须存储多少输入的情况下将输入保存到数组中的最佳解决方案是什么?或者,与 java 或 php 相比,C 语言可能就是这么复杂。
  • size_t newnum = (maxnum + 2) * 2; /* 4, 12, 28, 60, ... */ 我不明白这段代码。为什么这么大的数字会增加数组的内存?
【解决方案3】:
#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]);
}

【讨论】:

    猜你喜欢
    • 2019-10-23
    • 2012-03-27
    • 1970-01-01
    • 2019-06-07
    • 1970-01-01
    • 2020-07-07
    • 2021-03-11
    • 1970-01-01
    • 2011-06-29
    相关资源
    最近更新 更多