2017-11-03 118 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(发现内存泄漏的优秀工具)