繁体   English   中英

为什么从文件读取时C会多打印一行?

[英]Why does C print an extra line when reading from a file?

我是C语言的新手,正在尝试学习如何读取文件。 我的文件是一个简单的文件(仅用于测试),其中包含以下内容:

this file
has been
successfully read
by C!

因此,我使用以下C代码读取了文件:

#include <stdio.h>

int main() {

   char str[100];
   FILE *file = fopen("/myFile/path/test.txt", "r");

   if(file == NULL) {
      puts("This file does not exist!");
      return -1;
   }

   while(fgets(str, 100, file) != '\0') {
      puts(str);
   }

   fclose(file);

   return 0;
}

这将我的文本打印如下:

this file

has been

successfully read

by C!

当我编译并运行它时,我将其输出传递到hexdump -C并在每行末尾看到一个额外的0a

最后,为什么我需要声明一个字符数组以从文件中读取? 如果我不知道每行有多少数据怎么办?

fgets()读取换行符并将换行符保留在字符串中,而puts()始终将换行符添加到要打印的字符串中。 因此,在代码中使用时,您将获得双倍间距的输出。

使用fputs(str, stdout)代替puts() ; 它不会添加换行符。

从2011年C标准版本中删除的过时函数gets() –读取换行符但将其删除。 gets()puts()对一起很好地工作, fgets()fputs() 但是,您当然应该使用gets() 这是一场灾难,等待发生。 (1988年的第一个Internet蠕虫使用gets()进行迁移-Google搜索“ morris Internet蠕虫”)。


在评论中, 调查者问:

为什么需要将行读入特定大小的char数组中?

因为您需要确保不会超出可用空间。 C不会自动为字符串分配空间。 从某些角度来看,这是它的弱点之一。 这也是一种优势,但通常会使新来者迷惑该语言。 如果要输入代码为一行分配足够的空间,请使用POSIX函数getline()

那么,由于我不总是知道给定行上的字符数,所以最好只读取并输出直到我碰到'\\0'

不会。通常,您不会打'\\0' 大多数文本文件不包含任何这些文件。 如果您不想为一行分配足够的空间,请使用:

int c;
while ((c = getchar()) != EOF)
    putchar(c);

它可以在用户代码中一次读取一个字符,但是底层的标准I / O包可以缓冲输入内容,因此不会太昂贵-以这种方式实现程序是完全可行的。 如果需要在行上工作,请为行分配足够的空间(我通常使用char buffer[4096];常规方法)或使用getline()

查理·伯恩斯(Charlie Burns)在评论中问:

为什么我们不经常看到getline()建议?

我认为并没有经常提及它,因为getline()相对较新,并且不一定在任何地方都可用。 它已添加到POSIX 2008; 它在Linux和BSD上可用。 我不确定其他主流Unix变体(AIX,HP-UX,Solaris)。 为自己编写代码并不难(我已经做到了),但是如果您需要编写可移植的代码(尤其是如果“便携式”包括“ Microsoft”),那是很麻烦的。 它的优点之一是告诉您它实际读取的行有多长时间。

使用getline()示例

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

int main(int argc, char **argv)
{
    char *line = 0;
    size_t length = 0;
    char const name[] = "/myFile/path/test.txt";
    FILE *file = fopen(name, "r");

    if (file == NULL)
    {
        fprintf(stderr, "%s: failed to open file %s\n", argv[0], name);
        return -1;
    }

    while (getline(&line, &length, file) > 0) 
        fputs(str, stdout);

    free(line);
    fclose(file);

    return 0;
}

逐行读取时, fgets将换行符保存在行尾。 这使您可以确定是实际读取了一行还是缓冲区太小。

puts在打印时总是添加换行符。

fgets换行符或使用printf

printf("%s", str);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM