2017-04-07 83 views
0

我想用一个名为data.txt的文件填充数组。我不知道代码有什么问题。我得到分段错误:11错误。用简单的代码填充数组

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

void input(int arr[]){ 
    FILE* f; 
    int x, i=0; 
    f= fopen("data.txt","r"); 
    while (arr[i] != EOF){ 
     fscanf(f,"%d",&x); 
     arr[i] = x; 
     i++; 
    } 
    fclose(f); 
} 

int main(){ 
    int arr[50]; 
    input(&arr[50]); 
    printf("%d", arr[0]); 
} 
+4

'arr [i]'永远不会等于'EOF',所以你永远循环并最终发生段错误。你也将第一个元素的地址传递给'input()',所以你试图写入你从一开始就不拥有的内存。 –

+2

'input(&arr [50])'应该是'input(arr)' – Barmar

+1

在使用文件指针前,您不检查是否成功打开了输入文件。这很容易导致崩溃(并且很容易修复 - 总是检查来自'fopen()'或任何其他类似开放函数的返回值)。你不检查'fscanf()'的返回值;那也是一个错误。 (请参阅[我们如何检查'scanf()'的返回值?](http://stackoverflow.com/questions/10084224)) –

回答

2

您正在阅读到x数(要复制到arr[i]),然后比较arr[i+1]EOF。这不是如何做到的。

试试这个

while (fscanf(f, "%d", &arr[i]) == 1) 
    i++; 

但是,这会违反这么多的安全限制。如果i大于某个限制,那么最好也限制检查并提前中断,但是应该将该限制传递给该函数。

另一个错误是如何将参数传递给输入。通过input(arr)而不是input(&arr[50])。如果你想使用&使用input(&arr[0])

+0

哦 - 当然不是! (除了缺少'f'作为'fscanf()'的第一个参数...)为什么不能'while(fscanf(f,“%d”,&arr [i])== 1)i ++;',例如?一般来说,无限循环是不好的。有时是必要的,但这不是其中之一。是的,如果'fscanf()'在某个时候返回0,则终止,但如果返回'EOF',则无限期地继续旋转。 –

+0

@JonathanLeffler我希望这样比较好? –

+0

嗯,我想是的。我仍然更喜欢'while(fscanf(f,“%d”,&arr [i])== 1)i ++;'作为循环。我正在跳过数组边界检查,因为大小没有传递给函数。这有好处。一种是当转换失败时'i'不会增加,因此您不必担心在循环后是否减少'i'以报告创建了多少条目。它也不需要单独的状态变量。 –

0

这将是更接近我的版本的代码:

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

static int input(int size, int arr[]) 
{ 
    const char file[] = "data.txt"; 
    FILE *f = fopen(file, "r"); 
    if (f == NULL) 
    { 
     fprintf(stderr, "Failed to open file '%s' for reading\n", file); 
     exit(EXIT_FAILURE); 
    } 

    int i; 
    for (i = 0; i < size && fscanf(f, "%d", &arr[i]) == 1; i++) 
     ; 

    fclose(f); 
    return i; 
} 

int main(void) 
{ 
    int arr[50]; 
    int num = input(50, arr); 
    for (int i = 0; i < num; i++) 
     printf("%d: %d\n", i, arr[i]); 
    return 0; 
} 

函数之前使用的static要平息-Wmissing-prototypes。函数main()告诉input()函数有多少元素在数组中,所以函数可以避免溢出缓冲区(不会出现堆栈溢出)。函数input()告诉main()函数读取了多少个值,因此main()函数不会访问未初始化的数据。关键的函数调用是错误检查 - fopen()fscanf()

的代码完全编译使用GCC 6.3.0运行MACOS塞拉利昂10.12.4以下(源文件是rf19.c)命令行一个Mac和上:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \ 
>  -Wstrict-prototypes -Wold-style-definition rf19.c -o rf19 
$ 

我所生成的数据文件23的随机整数在10到99之间,输出为:

$ ./rf19 
0: 48 
1: 33 
2: 77 
3: 42 
4: 78 
5: 51 
6: 85 
7: 56 
8: 55 
9: 56 
10: 16 
11: 38 
12: 39 
13: 52 
14: 34 
15: 63 
16: 20 
17: 23 
18: 23 
19: 19 
20: 39 
21: 44 
22: 71 
$ 

这不是可怕的信息,但总比没有好。

该代码仍有缺陷,我不打算修复 - 有些比其他更严重。例如,文件名是固定的 - 这是一个禁忌。 input()函数中的代码出错时退出;这不一定好。它在标准错误上产生一个错误消息 - 这比标准输出更好,但在GUI应用程序中不是一个好主意。产量浪费了很多水平空间;显示的数据,你可以得到每个输出行10个值(每行约70个字符),但打印更复杂,所以我没有显示它。代码将EOF和数据中的单词或标点符号对待;这可能会或可能不重要,这取决于您的应用程序。输入仅在第50次输入后停止;也许你需要知道是否有更多的条目可供阅读。我可能会将命令行参数作为文件名进行处理,或者在没有指定文件的情况下处理标准输入 - Unix'filter command'习语。我可能会做一些比打印前五十个值更令人兴奋的东西。我可能会将文件读取代码放在与文件打开/关闭代码不同的函数中。