【问题标题】:Why does this code not output the expected output?为什么这段代码没有输出预期的输出?
【发布时间】:2011-01-23 14:39:14
【问题描述】:

这对于查找错误来说是一个很好的问题。 不?至少对初学者来说还可以。

#define SIZE 4
int main(void){
  int chars_read = 1;
  char buffer[SIZE + 1] = {0};  
  setvbuf(stdin, (char *)NULL, _IOFBF, sizeof(buffer)-1);  
  while(chars_read){
    chars_read = fread(buffer, sizeof('1'), SIZE, stdin);
    printf("%d, %s\n", chars_read, buffer);
  }
  return 0;
}

使用上面的代码,我正在尝试使用重定向./a.out < data 从文件中读取。输入文件内容:

1line
2line
3line
4line

但我没有得到预期的输出,而是混入了一些图形字符。 怎么了?


提示:(由 Alok 提供)

  • sizeof('1') == sizeof(int)
  • sizeof("1") == sizeof(char)*2

所以,用 1 代替 :-)

查看this post 使用 fread 的缓冲 IO 示例。

【问题讨论】:

  • 我不懂C,但可能是文本编码的东西。
  • 我猜不是,因为使用 scanf,我得到了正确的输出。
  • fread(buffer, sizeof('1'), SIZE, stdin); 为什么是sizeof('1')?只需改用1
  • @Gentlmean:同样的事情。
  • chars_read 如何递增?

标签: c fread


【解决方案1】:

'1' 的类型在 C 中是 int,而不是 char,因此您正在读取每个 fread 中的 SIZE*sizeof(int) 字节。如果 sizeof(int) 大于 1(在大多数现代计算机上是),那么您正在读取 buffer 的存储空间。这是 C 和 C++ 不同的地方之一:在 C 中,字符文字的类型为 int,在 C++ 中,它们的类型为 char

所以,您需要chars_read = fread(buffer, 1, SIZE, stdin);,因为sizeof(char) 根据定义为1。

事实上,我会把你的循环写成:

while ((chars_read = fread(buffer, 1, sizeof buffer - 1)) > 0) {
    buffer[chars_read] = 0; /* In case chars_read != sizeof buffer - 1.
                               You may want to do other things in this case,
                               such as check for errors using ferror. */
    printf("%d, %s\n", chars_read, buffer);
}

回答你的另一个问题,'\0'int 0,所以{'\0'}{0} 是等价的。

对于setvbuf,我的文档说:

size 参数可以设为零,以像往常一样获得延迟的最佳大小缓冲区分配。

你为什么评论\\而不是///* */? :-)

编辑:根据您对问题的编辑,sizeof("1") 是错误的,sizeof(char) 是正确的。

sizeof("1") 是 2,因为 "1" 是一个包含两个元素的 char 数组:'1'0

【讨论】:

  • \\ 错字我很沮丧:P。您使用什么文档?
  • 在 linux 上,man - 否则请参阅 POSIX:opengroup.org/onlinepubs/009695399/functions/fread.html。另外,您不想要sizeof("1"),请参阅我的编辑。
  • sizeof("1")!又得救了。我俯瞰一切!
  • 我向 nvl 询问了sizeof('1'),但我猜他忽略了它。
  • @Elite:你问过,但你没有说那是错误。所以,我忽略了。
【解决方案2】:

这是一种使用重定向逐字节读取文件行的​​方法 ./a.out

至少产生预期的输出... :-)

/*

Why does this code not output the expected output ?,
http://stackoverflow.com/questions/2378264/why-does-this-code-not-output-the-expected-output

compile with:
gcc -Wall -O3 fread-test.c

create data:
echo $'1line\n2line\n3line\n4line' > data

./a.out < data

*/

#include <stdio.h>

#define SIZE 5

int main(void) 
{

   int i=0, countNL=0;
   char singlechar = 0;
   char linebuf[SIZE + 1] = {0};
   setvbuf(stdin, (char *)NULL, _IOFBF, sizeof(linebuf)-1);  

   while(fread(&singlechar, 1, 1, stdin))     // fread stdin byte-by-byte
   {
      if ( (singlechar == '\n') )
      {
         countNL++;
         linebuf[i] = '\0';
         printf("%d:  %s\n", countNL, linebuf);
         i = 0;
      } else {
         linebuf[i] = singlechar; 
         i++;
      }
   }

   if ( i > 0 )    // if the last line was not terminated by '\n' ...
   {
      countNL++;
      linebuf[i] = '\0';
      printf("%d:  %s\n", countNL, linebuf);
   }

 return 0;

}

【讨论】:

    【解决方案3】:

    字符缓冲区[SIZE + 1] = {0};

    这不是你所期望的,它使缓冲区指向程序常量数据段中的一个字节区域。即这将损坏 SIZE 字节数,并可能导致内存保护错误。始终使用 strcpy() 或等效方法初始化 C 字符串。

    【讨论】:

    • 错了!它完全符合我的意图。
    • @gregery: char buffer[SIZE+1] = {0}; 完全有效。它将buffer 的每个元素设置为0
    • 好的,所以它是有效的,但我会重写它,因为它的风格很糟糕。缓冲区填充“0”这一事实并不明显,需要阅读 c 标准才能了解部分初始化是如何填充的。我从不在具有可变内容的数组上使用编译时初始化,所以在我看来它是错误的。
    猜你喜欢
    • 2019-11-14
    • 2015-06-21
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多