你有几个问题。
- 您没有初始化
numbers = 0; 或count = 0,因此在开始第一个realloc() 调用之前,变量中有一个不确定的值。这是个坏消息。
- 更大的问题是您误解了模拟二维数组所需的内存分配。
- 您的
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() 函数中运行时,这并不重要,但当工作在一个可能被许多程序使用的函数中完成时,它绝对很重要。