2012-02-09 55 views
35

我一直在爲我的CIS類做一個小小的練習,並且非常困惑於C使用從文件中讀取的方法。我真正需要做的就是逐行讀取文件,並使用從每行收集的信息進行一些操作。我嘗試過使用getline方法,其他人沒有運氣。 我的代碼是目前如下:逐行瀏覽文本文件C

int main(char *argc, char* argv[]){ 
     const char *filename = argv[0]; 
     FILE *file = fopen(filename, "r"); 
     char *line = NULL; 

     while(!feof(file)){ 
     sscanf(line, filename, "%s"); 
     printf("%s\n", line); 
     } 
    return 1; 
} 

現在我正在與sscanf的方法賽格故障,我不知道爲什麼。我是一個總C諾伯,只是想知道是否有一些我失蹤的大圖片。 謝謝

+1

此代碼甚至不應該編譯。 '的sscanf(行,文件名, 「%S」);'應該是'的sscanf(線,文件 「%s」);' – Mawg 2016-08-10 14:50:18

+0

注意['雖然'永遠是錯的(FEOF(文件)!)](HTTP ://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong)。 – 2017-05-08 21:17:11

+0

的可能的複製[C逐行讀取文件中的行(https://stackoverflow.com/questions/3501338/c-read-file-line-by-line) – 2017-11-24 16:37:55

回答

93

在這麼幾行中有這麼多問題。我可能會忘記一些:

  • argv [0]是程序名稱,而不是第一個參數;
  • 如果你想在一個變量來讀,你必須分配內存
  • 一個上FEOF永遠循環,一個上的IO功能循環,直到失敗,FEOF然後用來確定的失敗的原因,
  • sscanf的是有解析一條線,如果要解析的文件,使用的fscanf,
  • 「%S」將在第一空間停止作爲一個格式?scanf系列
  • 讀取線,標準功能是fgets,
  • 返回1從主意味着失敗

所以

#include <stdio.h> 

int main(int argc, char* argv[]) 
{ 
    char const* const fileName = argv[1]; /* should check that argc > 1 */ 
    FILE* file = fopen(fileName, "r"); /* should check the result */ 
    char line[256]; 

    while (fgets(line, sizeof(line), file)) { 
     /* note that fgets don't strip the terminating \n, checking its 
      presence would allow to handle lines longer that sizeof(line) */ 
     printf("%s", line); 
    } 
    /* may check feof here to make a difference between eof and io failure -- network 
     timeout for instance */ 

    fclose(file); 

    return 0; 
} 
+19

不要忘了'FCLOSE(文件)'返回之前。 – vivisidea 2014-02-18 09:46:04

+5

了'FCLOSE(文件)'實際上是沒有必要的,因爲它發生在'main',它會自動關閉所有打開的文件緩衝區。 – Leandros 2015-08-09 13:52:01

+11

@Leandros總是比較安全,而不是抱歉! – Vallentin 2016-07-29 21:26:01

6

要從文件中讀取一行,應該使用fgets函數:它從指定文件讀取一個字符串,直到換行符或EOF

在你的代碼中使用的sscanf不會在所有的工作,你用filename作爲格式字符串從line讀入一個常量字符串字面%s

SEGV的原因是您寫入line指向的未分配內存。

2

除了其他答案外,在最近的C庫(符合Posix 2008)中,您可以使用getline。見this answer(涉及相關問題)。

3

假設你正在處理一些其他的分隔符,如\t標籤,而不是\n換行符。

的更一般方法的分隔符是使用getc(),其抓住一次一個字符。

注意getc()返回int,這樣我們就可以測試與EOF平等。

其次,我們定義char類型的數組line[BUFFER_MAX_LENGTH],爲了存儲多達在堆棧上BUFFER_MAX_LENGTH-1字符(我們有保存用於\0終止字符的最後一個字符)。

使用數組可避免使用mallocfree在堆上創建正確長度的字符指針。

#define BUFFER_MAX_LENGTH 1024 

int main(int argc, char* argv[]) 
{ 
    FILE *file = NULL; 
    char line[BUFFER_MAX_LENGTH]; 
    int tempChar; 
    unsigned int tempCharIdx = 0U; 

    if (argc == 2) 
     file = fopen(argv[1], "r"); 
    else { 
     fprintf(stderr, "error: wrong number of arguments\n" 
         "usage: %s textfile\n", argv[0]); 
     return EXIT_FAILURE; 
    } 

    if (!file) { 
     fprintf(stderr, "error: could not open textfile: %s\n", argv[1]); 
     return EXIT_FAILURE; 
    } 

    /* get a character from the file pointer */ 
    while(tempChar = fgetc(file)) 
    { 
     /* avoid buffer overflow error */ 
     if (tempCharIdx == BUFFER_MAX_LENGTH) { 
      fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n"); 
      return EXIT_FAILURE; 
     } 

     /* test character value */ 
     if (tempChar == EOF) { 
      line[tempCharIdx] = '\0'; 
      fprintf(stdout, "%s\n", line); 
      break; 
     } 
     else if (tempChar == '\n') { 
      line[tempCharIdx] = '\0'; 
      tempCharIdx = 0U; 
      fprintf(stdout, "%s\n", line); 
      continue; 
     } 
     else 
      line[tempCharIdx++] = (char)tempChar; 
    } 

    return EXIT_SUCCESS; 
} 

如果你必須使用一個char *,那麼你仍然可以使用此代碼,但你strdup()line[]陣列,一旦其與線的價值輸入的灌滿。你必須free此複製串一旦你用它做,否則你會得到一個內存泄漏:

#define BUFFER_MAX_LENGTH 1024 

int main(int argc, char* argv[]) 
{ 
    FILE *file = NULL; 
    char line[BUFFER_MAX_LENGTH]; 
    int tempChar; 
    unsigned int tempCharIdx = 0U; 
    char *dynamicLine = NULL; 

    if (argc == 2) 
     file = fopen(argv[1], "r"); 
    else { 
     fprintf(stderr, "error: wrong number of arguments\n" 
         "usage: %s textfile\n", argv[0]); 
     return EXIT_FAILURE; 
    } 

    if (!file) { 
     fprintf(stderr, "error: could not open textfile: %s\n", argv[1]); 
     return EXIT_FAILURE; 
    } 

    while(tempChar = fgetc(file)) 
    { 
     /* avoid buffer overflow error */ 
     if (tempCharIdx == BUFFER_MAX_LENGTH) { 
      fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n"); 
      return EXIT_FAILURE; 
     } 

     /* test character value */ 
     if (tempChar == EOF) { 
      line[tempCharIdx] = '\0'; 
      dynamicLine = strdup(line); 
      fprintf(stdout, "%s\n", dynamicLine); 
      free(dynamicLine); 
      dynamicLine = NULL; 
      break; 
     } 
     else if (tempChar == '\n') { 
      line[tempCharIdx] = '\0'; 
      tempCharIdx = 0U; 
      dynamicLine = strdup(line); 
      fprintf(stdout, "%s\n", dynamicLine); 
      free(dynamicLine); 
      dynamicLine = NULL; 
      continue; 
     } 
     else 
      line[tempCharIdx++] = (char)tempChar; 
    } 

    return EXIT_SUCCESS; 
} 
+1

之前看到這種「最佳實踐」,即使發生藍色月亮的情況下,我也會對任何'while(!feof(file))'進行倒退投票(注意,可能永遠不會是真的,在這種情況下會留下一個循環,「while(true)」也會起作用。)有太多的人認爲這是正確的習慣用法。 – AProgrammer 2012-02-09 14:18:18

+0

我不知道這是一個問題。我真的很想更多地瞭解這一點。這種用法有什麼問題? – 2012-02-10 01:38:05

+0

有很多問題出現在這裏,例如http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong。 – AProgrammer 2012-02-10 10:22:58