在C语言中的空字符数组和使用read和fgets的区别

3
我曾经做过类似的事情从标准输入读取内容。
char *lines[50];
char buffer[50];

while((fgets(buffer, sizeof(buffer), stdin))!=NULL) {
    buffer[strlen(buffer)-1] = '\0';
    lines[i] = malloc(strlen(buffer));
    memcpy(lines[i++], buffer, strlen(buffer));
}

我希望使用read系统调用来实现类似的功能。

while((nread=read(0, buffer, sizeof(buffer)))>0) {
    buffer[strlen(buffer)-1] = '\0';
    lines[i] = malloc(strlen(buffer));
    memcpy(lines[i++], buffer, strlen(buffer));
}

将 i 重置为0,并使用 printf("%s", lines[i]) 打印字符串时,我在第一种方法中得到了正确的结果,但在第二种方法中并不总是得到相应的结果。这是为什么?

另外,在使用 read 从标准输入读取时,是否需要在字符串末尾添加空字符,还是 read 会自动添加?

我将输入从包含以下内容的文件中导入:

This is test input
This is another test input

Not reading correctly, not reading correctly

使用fgets()获取输入后打印输出会得到与输入完全相同的内容。

使用read()获取输入后打印输出会得到以下结果:

This is test input
This is another test input

Not
reading correctly, not reading correctly
put

No

额外的注意事项:

如果我将char buffer[50]改为更大的容量,第二种情况就能正常工作,但我不明白为什么在这一特定情况下不能正常工作。

问题似乎是当我从文件中重定向输入时,read会读取所有的50个字符。有没有办法让read每次迭代只读取到换行符为止?它似乎在从控制台接收输入时可以做到这一点。


2
您需要在调用malloc()时为NULL字符分配空间,并确保在调用memcpy之后使用NULL终止。由strlen()返回的长度不包括NULL字符。 - DaV
1
lines[i] = malloc(strlen(buffer)+1);memcpy(lines[i++], buffer, strlen(buffer)+1); - BLUEPIXY
2
@Zaphod。buffer没有以NULL结尾。因此,您不能将其传递给strlen() - DaV
2
在成功调用 fgets() 后,buffer 末尾总是以 '\0' 结尾。但它可能不会以 '\n''\0' 结尾。所以,使用 buffer[strlen(buffer)-1] = '\0'; 并不是处理潜在的 '\n' 的好方法。建议使用 size_t len = strlen(buffer); if (len > 0 && buf[len-1] == '\n') buf[--len] = '\0'; - chux - Reinstate Monica
1
@Michael Burr同意strdup()更易读,但不幸的是它不是C规范的一部分。 - chux - Reinstate Monica
显示剩余8条评论
1个回答

7

read不会添加任何内容,也没有终止符0。在read之后,strlen(buffer)返回取决于在read之前缓冲区中存在什么的任何东西。好消息是,你根本不需要调用strlen,因为read返回传输的字符数:

while((nread = read(0, buffer, sizeof(buffer) - 1))>0) {
    buffer[nread] = '\0';
    lines[i] = malloc(nread + 1));
    memcpy(lines[i], buffer, nread + 1);
}

提示:别忘了测试nread是否为-1。


2
同时递增 i,否则每次都会覆盖上一行。 - DaV
@Zaphod。strlen()期望传递一个以NULL结尾的字符串。buffer没有以NULL结尾。buffer[strlen(buffer)-1] = '\0';我认为我不能再清楚地表达了。 - DaV
@Zaphod 用户58697说得对,read()之后,buffer中并没有任何'\0'。如果代码想将其作为C字符串处理,则附加一个'\0'是个好主意。 - chux - Reinstate Monica
将最后两行改为调用 strdup()。这是一个很好的简单函数调用,而不是一对容易出错的混乱表达式,容易出现细节错误。 - Michael Burr
@user58697。我在打印一些输出时得到了与你相同的答案。但是,我想将每行存储在自己的字符串中。我猜当使用read时这是不可能的?如果我从键盘输入而不是从文件中输入,则可以实现。 - Mars
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接