调用read系统调用读取文件时,为何要将缓冲区buf设为'\0'?
为什么读取文件后、关闭文件描述符前要给缓冲区buf设置'\0'?
示例代码如下:
ssize_t read_textfile(const char *filename, size_t letters) { int fd; int i, y; char *buf; if (!filename) return (0); fd = open(filename, O_RDONLY); if (fd < 0) return (0); buf = malloc(sizeof(char) * letters); if (!buf) return (0); i = read(fd, buf, letters); if (i < 0) { free(buf); return (0); } buf[i] = '\0'; // 疑问指向的代码行 close(fd); y = write(STDOUT_FILENO, buf, i); if (y < 0) { free(buf); return (0); } free(buf); return (y); }
原因解析
这段代码里给buf[i] = '\0'的操作,本质是防御性编程的习惯,具体原因有这几点:
- 防止后续字符串操作出问题:当前代码用
write输出时,明确指定了写入长度是i(实际读取的字节数),确实不需要依赖'\0'。但如果之后代码有修改(比如改成用strlen(buf)获取长度、或者用puts这类依赖字符串结尾的函数),没有'\0'就会读取到内存里的垃圾数据,甚至触发越界访问的未定义行为。提前加上终止符,能避免这类后续维护时的潜在bug。 - 处理malloc未初始化的内存:
malloc分配的内存是未清零的,里面会有随机的垃圾值。如果文件内容长度小于letters,read只填满了前i个字节,剩下的内存空间是脏数据。加上'\0'后,即使后续有调试打印buf的操作,也只会显示到实际读取的内容为止,不会输出垃圾。 - 符合C字符串规范:C语言中标准字符串必须以
'\0'结尾,把缓冲区按字符串的标准来处理,是一种良好的编程习惯,能减少因“非标准字符串”引发的意外问题。
代码隐患提醒
这段代码存在一个潜在bug:如果read刚好读取了letters个字节(即i == letters),那么buf[i] = '\0'会访问malloc分配的内存之外的空间,属于越界写入,会触发未定义行为。正确的做法应该是给malloc多分配一个字节的空间,用来存储终止符:
buf = malloc(sizeof(char) * (letters + 1));
内容的提问来源于stack exchange,提问作者Tiisetso
相关产品推荐
相关产品推荐

