使用unistd.h中的read() 函数只读取一个字节

编程语言 2026-07-11

我正在尝试启动一个Hangman项目,首先我想处理如何从终端获取用户字母。我知道我可以只读取一个字节并把该值存储到一个指针的地址里

char *ptr;
int read_bytes;

read_bytes = read(0, ptr, 1);
//NULL checks

但现在我写了一个函数,它返回一个以NULL结尾的缓冲区,只有两个字符(用户的输入和结尾的NULL字符)。

这是代码。

#include "utils.h"

char    *read_one_byte(int   fd)
{
    char        *buf;
    int     read_bytes;

    if (!(buf = malloc(sizeof(char) * 2)))
    return (NULL);
    if ((read_bytes = read(fd, &buf, 1)))
    {
        buf[1] = '\0';
        return (buf);
    }
    else
        return (NULL);
}

将缓冲区NULL结束,即使它的内容只有一个字符,值得吗,还是我根本就不应该在意?

解决方案

我知道我可以只读取一个字节并把该值存储到一个指针的地址里 [...]

不,你不能。

要使用 read(),你需要的第一件事是在某个对象中存放结果,通常称为“缓冲区”。read() 的第二个参数是缓冲区的地址——一个指针类型的值。read不能也不会把任何东西存入该地址。成功时,它会把数据存储在指向的地址处的对象中,或者如果按照C 的语义规则没有定义这样的对象,那么C 不定义该行为。若你走运,在这种情况下你的程序会崩溃。


在你的示例中,你没有缓冲区。对 read() 调用的第二个参数是一个未初始化指针变量的未确定值。就实际情况而言,这个值可能指向任意对象,或者指向空,但在许多常见的机器上,“none” 要比其他情况更可能。C的语义对这个问题并不会给出答案。


你使用一个指针变量是为了存放另一个对象的地址。你并不需要这样的变量,常常也不想要它,当你只需要“使用”一个对象的地址时。这就是取地址运算符(&)的用途,在一类常见的特殊情况下,数组到指针的衰减也能在没有任何运算符的情况下完成这项工作。

char c;
int read_bytes;

read_bytes = read(0, &c, 1);
// check read_bytes

另外要注意,只有在相当特殊的情况下,才会有空指针检查的相关性。你确实需要检查返回值,但这并不是一次空指针检查。

但现在我写了一个函数,它返回一个以NULL结尾的缓冲区,只有两个字符(用户的输入和结尾的NULL字符)。

这是可行的,但你做错了。如果你动态分配缓冲区的内存——你当然可以——那么从 malloc() 返回的指针就是要传给 read() 的值。你却传递了存放指针的变量的地址,这显然不同也是双重错误:读取的值不会放到你想要的位置,并且在成功读取时,你还会破坏存储的指针值。你应该这样写:

    // ...
    if (!(buf = malloc(2))) return NULL;  // sizeof(char) == 1 by definition
    if ((read_bytes = read(fd, buf, 1)))  // note "buf" as opposed to "&buf"
    // ...

即使缓冲区的内容只有一个字符,是否值得将其NULL结束?还是根本不必?

这取决于你打算如何使用它。如果把它作为C 字符串,那么该字符串必须以一个值为0 的字节结尾。否则,终止它可能就没有什么好处。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章