【问题标题】:read file line by line in C(without using fgets)在C中逐行读取文件(不使用fgets)
【发布时间】:2019-05-10 06:56:58
【问题描述】:

我有一个包含 3 行的文件,我想读取这个文件并将每一行保存为一个单独的字符串。 这是我尝试做的,它确实保存了第一行,但它通过保存第一行和第二行来覆盖它,我无法理解如何将每一行保存为单独的字符串,并且我也遇到了错误->

* 检测到堆栈破坏 *:/home/ubuntu/workspace/ex12.c.o 已终止 中止

 #include <stdio.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include<stdio.h> 
 #include<fcntl.h> 
 #include<errno.h> 
 #include <unistd.h>
 extern int errno;                               
int main( int argc, char *argv[] )  {
    char *path1;   
    char  firstline[80];
    char  secondline[80];
    char  thirdline[80];  

    printf("Program name %s\n", argv[0]);

    if( argc == 2 ) {
         printf("The path of the config file that you supplied is %s\n", argv[1]);
    }
    else if( argc > 2 ) {
        printf("Too many arguments supplied.\n");
    }
    else {
        printf("One argument expected.\n");
    }

    int fd1 = open(argv[1], O_RDONLY | O_CREAT);  

    if (fd1 ==-1) 
    { 
        // print which type of error have in a code 
        printf("Error Number % d\n", errno);  

        // print program detail "Success or failure" 
        perror("Program"); 
        exit(EXIT_FAILURE);
    }       
    else {            
        char c;
        int i=0;            

        while ((read(fd1, &c, 1) == 1) )
        {                
            firstline[i++]=c;                
            if(c=='\n')
            {
                //printf("end of line"); 
                printf("%s",firstline);
            }

        }
    }
    int close(int fd1);         
    return 0;        
}

注意:我不想使用 fopen、fgets、sscanf 或 getline。 任何帮助将不胜感激

【问题讨论】:

  • 首先,发布格式良好、缩进良好的代码总是值得的。没有人愿意阅读之字形。其次,int close(int fd1); 是一个函数原型。它不是函数调用,也不会关闭任何文件。第三,你总是读到firstline。为什么你希望它不会被覆盖?最后,不要在迭代结束时重置 i 并用完数组边界。
  • 例如您必须在第 1 行结束后退出 while 循环 break; 。另外i没有结尾,第一行很容易溢出!
  • 贴出的代码无法编译!即使在猜测了您的实际代码包含哪个头文件之后,编译器仍然会发出一些关于未使用变量等的警告。请修复发布的代码,以便它可以干净地编译,
  • @Tom Kuschel 但如果我在第 1 行结束后中断,我将无法获得第 2 行和第 3 行,我想像第 1 行一样将它们作为 2 个单独的字符串获得。
  • @user3629249 我已经添加了头文件,现在应该可以编译了

标签: c file operating-system system-calls


【解决方案1】:

这是一个示例,用于演示您的示例中第一个循环的制动:

#define MAXLENGTH 80    
...

char  firstline[MAXLENGTH + 1] = {0};
char  secondline[MAXLENGTH + 1] = {0};
char  thirdline[MAXLENGTH + 1] = {0};  
....
else {            
    char c;
    int i=0;            
    while ((read(fd1, &c, 1) == 1 && i < MAXLENGTH)
    {                
        firstline[i++]=c;                
        if(c=='\n')
        {
            break; /* break from first loop */
        }
    }
    /* add a '\0' to the end of the string! */
    firstline[i] = '\0';
    //printf("end of line"); 
    printf("%s",firstline);
    i=0;            
    while ((read(fd1, &c, 1) == 1 && i < MAXLENGTH)
    {                
        secondline[i++]=c;                
        if(c=='\n')
        {
            break; /* break from second loop */
        }
    }
    /* add a '\0' to the end of the string! */
    secondline[i] = '\0';
    printf("%s",secondline);
    i = 0;
    int i=0;            
    while ((read(fd1, &c, 1) == 1 && i < MAXLENGTH)
    {                
        thirdline[i++]=c;                
        if(c=='\n')
        {
            break; /* break from third loop */
        }
    }
    /* add a '\0' to the end of the string! */
    thirdline[i] = '\0';
    //printf("end of line"); 
    printf("%s",thirdline);
}
...

【讨论】:

    【解决方案2】:

    printf 打印直到看到 NULL 终止字符。您的 printf 会遍历未分配的内存区域,因为您没有在字符串末尾插入 NULL(值 0)。 另外,您忘记将 i 重新初始化为 0。

    while ((read(fd1, &c, 1) == 1) )
    {                
        firstline[i++]=c;                
        if(c=='\n')
        {
            firstline[i] = 0;
            i = 0;
            //printf("end of line"); 
            printf("%s",firstline);
        }
    }
    

    【讨论】:

      【解决方案3】:

      您收到错误的原因很可能是因为您从未将 i 重置回 0,因此您一直在向 firstline 读取超过 80 个字符

      至于将每一行保存到自己的字符串中,您只需要使用其他变量,而不是一直使用firstline

      有几种方法可以做到这一点:

      1. 当您检测到行尾时退出循环(使用break),并开始另一个循环,您将在其中将字符放入secondline。对第三个做同样的事情。

      2. 1234563每次检测到行尾时更改地址,如下所示:currentLine = secondline

      还记得在您阅读的每一行的末尾加上“\0”,否则当您尝试将您阅读的内容打印到屏幕上时,您的程序可能会打印垃圾。

      【讨论】:

      • 你的意思是我应该使用 break 来退出 while 循环?那么如何从第一个循环停止的地方开始一个新的 while 循环呢?
      • 您不需要从第一个停止的地方开始,您需要从头开始 - 确保 i 为零并确保您读入不同的数组。当您open 一个文件并从中读取时,系统会保留一个内部指针,接下来要从哪里读取。您在程序中的哪个位置调用 read 并不重要 - 它始终会从上次调用 read 的位置继续读取文件。
      【解决方案4】:

      以下建议的代码:

      1. 干净编译
      2. 执行所需的功能
      3. 正确检查和处理错误
      4. 给出“神奇”数字 (3, 80) 有意义的名称

      现在,建议的代码:

      #include <stdio.h>
      #include <stdlib.h>
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
      #include <errno.h>
      #include <unistd.h>
      
      #define MAX_LINES 3
      #define MAX_LINE_LEN 80
      
      
      int main( int argc, char *argv[] )  
      {
          char Lines[ MAX_LINES ][ MAX_LINE_LEN ] = { '\0' };
      
      
          if( argc != 2 )
          {
              fprintf( stderr, "USAGE: %s <configFileName>\n", argv[0] );
              exit( EXIT_FAILURE );
          }
      
          // implied else, correct number of command line arguments
      
      
          int fd1 = open(argv[1], O_RDONLY );  
      
          if (fd1 ==-1) 
          { 
              perror( "open failed" ); 
              exit(EXIT_FAILURE);
          }  
      
          // implied else, open successful        
      
          char c;
      
          for( int i = 0; i < MAX_LINES; i++ )
          {
              for( int j=0; j< MAX_LINE_LEN; j++ )
              {
                  ssize_t bytecount = read(fd1, &c, 1 );
                  if( bytecount < 0 )
                  {
                      perror( "read failed" );
                      close( fd1 );
                      exit( EXIT_FAILURE );
                  }
      
                  // implied else, read successful 
      
                  Lines[ i ][ j ] = c;
      
                  if( c == '\n' )
                  {
                      break;
                  }   
              } 
          }
      
          for( int i = 0; i< MAX_LINES; i++ )
          {
              printf( "%s\n", Lines[i] );
          }
      
          close( fd1 );         
          return 0;        
      }
      

      注意:此代码假定每行少于 80 个字符

      针对自己的源文件运行建议的代码会导致:

      #include <stdio.h>
      
      #include <stdlib.h>
      
      #include <sys/types.h>
      

      【讨论】:

      • 能否请您澄清一下为什么要编辑代码?(我目前编译了您以前的代码并仔细阅读它以试图理解它)
      • 编辑原因:1) read() 不会在换行符处停止,因此读取的方式不止一行 2) 我曾建议使用 getline() 然后我注意到您不想要使用getline()。由于read() 不会因为换行而停止,我不得不修改代码以逐个字符读取并检查每个字符是否有换行符
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多