【问题标题】:printing character array garbage打印字符数组垃圾
【发布时间】:2015-06-28 21:23:03
【问题描述】:
#include<sys/stat.h>
#include<stdio.h>
#include<fcntl.h>
#include<sys/types.h>
int main()
{
  int n,i=0;
  int f1,f2;
  char c,strin[100];
  f1=open("data",O_RDWR|O_CREAT|O_TRUNC);

  while((c=getchar())!='\n')
  {
    strin[i++]=c;
  }
  strin[i]='\0';
  write(f1,strin,i);
  close(f1);

  f2=open("data",O_RDONLY);
  read(f2,strin,0);
  printf("\n%s\n",strin);
  close(f2);
  return 0;
}

这段代码在某些机器上运行良好,而在其他机器上打印出垃圾,如何让它在所有机器上正确运行?

【问题讨论】:

  • 请先检查open()的返回值是否成功。
  • 即使我省略了文件访问部分,即只填充字符串然后再次打印,我仍然得到相同的结果
  • 您尝试过格式化 i/o 吗?
  • "man -S2 read" 说:DESCRIPTION read() 尝试从文件描述符 fd 中读取 count 个字节到缓冲区,从 buf 开始。如果 count 为零,则 read() 返回零并且没有其他结果。如果 count 大于 SSIZE_MAX,则结果未指定。但我尝试了此代码和 read(),同样使用 count==0,返回读取字节数!!!
  • 我告诉你,我上面指出的奇怪情况是由于我没有清理缓冲区!

标签: c linux string pointers


【解决方案1】:

我认为这个问题很简单,当您使用 getchar() 获取字符直到 '\n' 时,您实际上并没有考虑到 Windows 回车是 \r\n 而它在 Unix 中是 \n 您将在下面的链接中获得详细信息

Does Windows carriage return \r\n consist of two characters or one character?

附:我是这里的新手,所以如果这个答案不是你想要的,我先道歉。

【讨论】:

    【解决方案2】:

    您编写的代码无法正常工作!问题很简单!或者你写然后你在字符串末尾也读取 \x0 或者,当你阅读时,你将 \x0 添加到读取字符串的末尾! :)

    同时保存 \x0

    write(f1,strin,i+1);
    

    读取并添加 \x0

    i=read(f2,strin,sizeof(strin)-1);
    strin[i]=0;
    

    我认为最好的解决方案是第二种!;)

    【讨论】:

      【解决方案3】:

      您对 read() 的调用实际上并没有读取任何内容。第三个参数是要读取的最大字节数,您将其传递为 0:

      read(f2,strin,0);
      

      您需要将缓冲区的大小改为减一以容纳终止的 nul 字节:

      int bytesread = read(f2,strin,99);  /* since your buffer is size 100 */
      strin[bytesread] = '\0';
      

      这一直有效的唯一原因是因为您在第一次通过 getchar() 填充它和第二次通过 read() 填充它时没有清除字符串。所以当你看到数据时,它是第一次的剩余数据。如果添加:

      memset(strin, 0, 100);
      

      到 read() 之前的原始代码,你会发现它永远不会在任何机器上打印数据。

      【讨论】:

      • 奇怪的是,在我的 ubuntu 上,函数 read() 也用 count==0 读取......我读到那个人说用 counter 0 read() 什么都不做!!!但是我已经尝试像上面的代码一样使用 read 并且它会读取!
      • 你确定吗?尝试在 read() 之前用 memset 擦除缓冲区,看看它是什么样子的。当我这样做时,很明显 read() 什么也没做。如果你不先擦除字符串,虽然你可能会看到它以前的内容并被愚弄以为是 read() 把它放在那里的。
      • 你说的我已经试过了!不清理缓冲区是我的错误!
      • 你在这一点上是完全正确的......但是问题是我试图省略所有文件访问功能,即只是填充字符串并按原样再次打印......并且仍在某些机器上打印垃圾
      • 您能否分享删除文件访问功能的代码,以便我们准确了解您在做什么?