2017-04-07 86 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'習語。我可能會做一些比打印前五十個值更令人興奮的東西。我可能會將文件讀取代碼放在與文件打開/關閉代碼不同的函數中。