C - 从文件中逐行读取 - 显示错误的输出

时间:2013-09-14 09:54:26

标签: c file output

我试图逐个读取文件中的整数,并将其作为一行读入程序中。列号。

我的文件内容是:

3
2 1
2 2
2 3

我的代码:

fgets(line, 2, fp);
livecells = atoi(line);
fprintf(stderr, "\n%i live cells\n", livecells);    

while ( !feof(fp) ) 
{
  fgets(line, 5, fp);

  alive_row = atoi(&line[0]);
  alive_column = atoi(&line[2]);

  fprintf(stderr, "\n Cell: (%i)(%i)", alive_row, alive_column);       
}

其中line是存储fgets内容的字符数组(字符串),以及alive_row,& alive_column是整数。

但由于某种原因,输出是:

3 live cells

 Cell: (0)(0)
 Cell: (2)(1)
 Cell: (2)(2)
 Cell: (2)(3)
 Cell: (2)(3)

问题是,为什么第一个单元格打印出来(0)(0)?我不知道为什么要打印出来...如果它显得非常明显而道歉......

编辑:显然最后重复的单元格(2)(3),哎呀。

3 个答案:

答案 0 :(得分:3)

第一列打印为(0, 0),因为atoi失败。请不要使用atoi,而应使用strtol,这样您就可以检查转换是否成功。

atoi失败的原因是因为你有一个额外的\n字符,因为fgets(fgets(line, 2, fp);你只读取一个字符 - 因为你为缓冲区的大小传递了2,并且缓冲区的1个元素是为\0字符保留的。只需使用足够大的缓冲区来读取整行,并在那里传递缓冲区的大小。

为了解决其他错误,请不要使用feof。而是检查fgets返回值以查看它从文件中读取的字符数(或者,如果您真的想在feof调用后使用fgets进行检查)。

while (  fgets(line, sizeof(line), fp) > 0) 
{
  char* end;

  alive_row = strtol(&line[0], &end, 10);

  // If the end points to the &line[0], then no 
  // characters were converted!     
  if(end == &line[0])
  {
      printf("strtol failed!\n");
      return 0;
  }

  alive_column = strtol(&line[2], &end, 10);

  // If the end points to the &line[2], then no 
  // characters were converted!     
  if(end == &line[2])
  {
      printf("strtol failed!\n");
      return 0;
  }

  fprintf(stderr, "\n Cell: (%i)(%i)", alive_row, alive_column);       
}

我们检查&line[0] == end,因为传递给strtol的第二个参数是

  

引用char *类型的对象,其值由函数设置为数值后str中的下一个字符。

如果字符串中没有数字值,则此指针将指向您尝试转换的字符串的开头。

如果您不知道数字的位数是1还是2还是其他数字,您仍然可以使用strtol来帮助您:

while (  fgets(line, sizeof(line), fp) > 0) 
{
  char* end;
  char* tmp;

  alive_row = strtol(&line[0], &end, 10);

  // If the end points to the &line[0], then no 
  // characters were converted!     
  if(end == &line[0])
  {
      printf("strtol failed!\n");
      return 0;
  }

  // If the previous strtol converted the first number
  // end will point to the space character (the first character after the number).
  // So, just pass
  // end + 1 which should point to the second number
  tmp = end + 1;
  alive_column = strtol(tmp, &end, 10);

  // If the end points to the tmp, then no 
  // characters were converted!     
  // (this is why we used this tmp to place end + 1 - we need to 
  //  check for the success of the strtol).
  if(end == tmp)
  {
      printf("strtol failed!\n");
      return 0;
  }

  fprintf(stderr, "\n Cell: (%i)(%i)", alive_row, alive_column);       
}

答案 1 :(得分:1)

由于您正在处理单个数字,因此您可以使用line[0]-'0'将行[0]转换为整数。在第一次扫描时只扫描5个字节,以便文件流移动到下一行。

   #include<stdio.h>

    int main()
    {

    FILE *fp;
    int alive_row;
    int alive_column,livecells;


    char line[10];
    fp=fopen("file1","r");
    fgets(line,5 , fp);
    livecells = line[0]-'0';
    fprintf(stderr, "\n %i live cells\n", livecells);

    while ( fgets(line, 5, fp)!=NULL)
    {
    //  puts(line);
      alive_row = line[0]-'0';
      alive_column = line[2]-'0';

      fprintf(stderr,"\n Cell: (%i)(%i)\n", alive_row, alive_column);
    }
    fclose(fp);
    }

使用此功能,您可以将行拆分为两个值作为行和列。

file1:

12
2 1
2 2
2 3
50 5
30 20
5 30
30 330
3390 447
12 1234
0 0
1234 1
154 0 

CODE:

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

int main()
{

    FILE *fp;
    int alive_row=0;    
    int alive_column=0,livecells;
    int column=0,i;

    char line[10];
    fp=fopen("file1","r");
    fgets(line,5, fp);       //read first line
    livecells = atoi(line); //convert into int
    fprintf(stderr, "\n %i live cells\n", livecells);

    while ( fgets(line, 12, fp)!=NULL)      //read next lines
        {
        for(i=0;i<strlen(line)-1;i++)      //loop to separate rows and columns , here if space occurs make flag column as 1
            {
            if(line[i]!=' ' && column!=1 )     
            alive_row = 10*alive_row+line[i]-'0'; //convert into integers
            else
                {
                if(line[i]==' ')
                i=i+1;
                alive_column=10*alive_column+line[i]-'0';
                column=1; //you can write this statement just above if but you need to add two brace 
                }
            }

        printf(" Cell:(%d)(%d)\n\n", alive_row, alive_column);
        alive_row=0;   //after every iteration just make these value to default. 
        alive_column=0;
        column=0;
        }
    fclose(fp);
}

输出

 12 live cells

 Cell:(2)(1)

 Cell:(2)(2)

 Cell:(2)(3)

 Cell:(50)(5)

 Cell:(30)(20)

 Cell:(5)(30)

 Cell:(30)(330)

 Cell:(3390)(447)

 Cell:(12)(1234)

 Cell:(0)(0)

 Cell:(1234)(1)

 Cell:(154)(0)

答案 2 :(得分:0)

如果可能,

fgets()会读取\n字符 如果不是,则在下一次读取操作中将读取\n

由于您的呼叫是fgets(line, 2, fp);,因此只读取1个字符,而第2个字符填充空字符。所以:line [0] =='3'和line [1] =='\ 0'。

行尾将在稍后阅读,因此while()循环内的第一次阅读操作就是:"\n"。这会产生atoi的任意结果(在您的情况下为零)。

考虑到:

  

fgets(line,N,fp)从文件fp中读取stdin中最多N-1个字符,   包括\ n,如果可能的话。结果排成一列,总是如此   最后的房间为\ 0字符。