2017-11-03 157 views
-1

我一直對這個尾巴方案下一陣尾巴程序,但我似乎遇到了與我的DO循環一個惱人的問題。編譯並運行我的代碼後,它似乎只執行Do-Loop中的第一次迭代並崩潰。我多次鑽研邏輯,我不知道什麼是錯的。我對編程也很新,任何建議都會有幫助!創建用C

/** 
    *Author: William Briggs 
    *Date : 11/2/2017 
    * 
    *A Basic implementation of the tail function. 
    *Reads in text from a user specified text file and 
    *takes the specified number of lines(-n) from the tail 
    *of the file and prints it out. 
    * 
    **/ 


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

    enum { DEFAULT_LINES = 10}; 
    enum { MAX_BUFFER = 1000}; 

    /* Standard getline function */ 
    int linein(char str[], int end) 
    { 
    int chr, i; 


    for (i = 0; i < end - 1 && (chr = getchar()) != EOF && chr != '\n'; i++) 
    { 
     str[i] = chr; 
     } 

     if (chr == '\n'){ 
     str[i++] = chr; 
     } 

     str[i] = '\0'; 
     return i; 
    } 

    /* Creates copy of a string */ 
    char *dupstr(const char *str) 
    { 
     char *p = malloc(strlen(str) + 1); 

     if (p) { 
     strcpy(p, str); 
     } 

     return p; 
    } 

    int main(int argc, char *argv[]) 
    { 
     int num_of_lines = DEFAULT_LINES; 
     char **line_ptr; 
     char buffer[MAX_BUFFER]; 
     int i; 
     unsigned j, cur_line; 

     if (argc > 1) { 

     num_of_lines = atoi(argv[1]); 

     if (num_of_lines >= 0) {  
      fprintf(stderr, "Expected -n, where n is the number of lines\n"); 
      return EXIT_FAILURE;           
     } 

     num_of_lines = -(num_of_lines);           
     } 

     /* Allocates memory for a list of pointers (size n) */ 
     line_ptr = malloc(sizeof *line_ptr * num_of_lines); 

     if (!line_ptr) { 
     fprintf(stderr, "Out of memory.\n"); 
     return EXIT_FAILURE; 
     } 

     /* Changes pointers to NULL */ 
     for (i = 0; i < num_of_lines; i++){ 
     line_ptr[i] = NULL; 
     } 

     /* Reads the file */ 
     cur_line = 0; 
     do { 

     linein(buffer, sizeof buffer); 

     if (!feof(stdin)) { 

      if (line_ptr[cur_line]) { 
      free(line_ptr[cur_line]); 
      } 

      line_ptr[cur_line] = dupstr(buffer); 

      if (!line_ptr[cur_line]) { 
      fprintf(stderr, "Out of memory.\n"); 
      return EXIT_FAILURE; 
      } 

      cur_line = (cur_line + 1) % num_of_lines; 
     } 

     } while (!feof(stdin)); 
     free(line_ptr[cur_line]); 


     /* Prints data from text file */ 
     for (i = 0; i < num_of_lines; i++) { 

     j = (cur_line + i) % num_of_lines; 

     if (line_ptr[j]) { 
      printf("%s", line_ptr[j]); 
      free(line_ptr[j]); 
     } 
     } 
     return EXIT_SUCCESS; 
    } 

我從cmd行取兩個參數:行數和文本文件。 例如,編譯後的代碼,輸入看起來像含program_name -3 text.txt 我的文本文件:

From the typewriter it came, and to the typewriter 
it shall return: the phrase was proposed as a 
typing drill by a teacher named Charles E. Weller. 
Incidentally, many typing books now use the variant 
"Now is the time for all good men to come to the 
aid of their country" instead, because it exactly fills 
out a 70-space line if you put a period at the end. 

這應返回的輸出:

"Now is the time for all good men to come to the 
aid of their country" instead, because it exactly fills 
out a 70-space line if you put a period at the end. 

我不想做任何假設關於文本文件中的最大行數。所以我不想將文本文件存儲在一個字符串數組中。相反,我試圖動態分配一個數組來保存我的程序需要記住的行數。我希望這足夠徹底地解釋。

+0

哪裏是你的文件嗎?我很困惑。 –

+0

對不起,我沒有澄清,你從cmd行獲取兩個參數,你想讀取的行數是int,文本文件名是char字符串。它可以是用戶指定的任何文本文件。 –

+0

@CoreyLakey OP從'stdin'讀取,也許使用'cat somefile.txt | ./app -5'或者'./app -5

回答

1

你的程序是忽略被發現argv[2],它不打開文件。

linein可以fgets被替換,有很多不必要的代碼,你可以刪除。

看來你正在讀取文件中的所有行。但是您不知道高級文件中有多少行。據我所知,你分配num_of_lines這是保證少於文件中的行總數。

此代碼將讀取該文件中的所有行,然後簡單地打印最後3行。

int total_lines = 0; //total lines in the file, we don't know it yet 
num_of_lines = 3; //get these last lines 

FILE *fin = fopen("filename.txt", "r"); 
if(!fin) return 0; 

line_ptr = 0; 

//read all the lines 
while (fgets(buffer, sizeof buffer, fin)) 
{ 
    line_ptr = realloc(line_ptr, sizeof(char*) * (total_lines + 1)); 
    line_ptr[total_lines++] = dupstr(buffer); 
} 

if(total_lines < num_of_lines) 
{ 
    printf("total_lines < num_of_lines\n"); 
    return 0; 
} 

//print the last lines 
for(i = total_lines - num_of_lines; i < total_lines; i++) 
    printf("%s", line_ptr[i]); 
printf("\n"); 

cleanup... 

要想從argv行號和文件名,命令行應該是這樣的:

app.exe -3 filename.txt 

argc是3

argv[0]將是節目的名字,(應用程序.exe在上例中)

argv[1]-3

argv[2]"filename.txt"

例子:

int main(int argc, char *argv[]) 
{ 
    ... 
    const char* filename = 0; 
    FILE *fin; 

    if(argc < 3) 
    { 
     printf("error..."); 
     return EXIT_FAILURE; 
    } 
    else 
    { 
     num_of_lines = -atoi(argv[1]); 
     if(num_of_lines < 0) { 
      fprintf(stderr, "Expected -n, where n is the number of lines\n"); 
      return EXIT_FAILURE; 
     } 

     filename = argv[2]; 
     fin = fopen(filename, "r"); 
     if (!fin) 
     { 
      printf("Cannot open file\n"); 
      return EXIT_FAILURE; 
     } 
    } 
    ... 
    return EXIT_SUCCESS; 
} 
+0

這不會在每行中讀取並將其存儲在字符數組中,是嗎?我很抱歉,我不是很擅長閱讀代碼。 –

+0

它的確如此。它將整個文件存儲在'line_ptr'中,所以'line_ptr [0]'是line1,'line_ptr [1]'是2行等。總共有'total_lines'你可能對最後3行感興趣。 –

+0

所以如果我從命令行讀取文件名,我不會使用'argv [1]'而不是''filename.txt''? –

1

問題是與後while循環的最後free。手動內存管理的第一條規則是每個malloc/new必須有一個互補free/delete,這是一個很好的一般性建議。

在你的情況,我建議你釋放內存後設置您的指針回零。通過這種方式,你可以確定你沒有試圖釋放已經被釋放的內存。這是有效的,因爲這些指針的副本被嚴格管理。

一般情況下,這是不行的,因爲有可能是指向同一個地址的多個指針。手動內存管理則殆像這樣的問題可以通過使用

  1. 仔細檢查
  2. 調試器
  3. Valgrind(發現內存泄漏的優秀工具)