我目前正在阅读Robert Love的Linux系统编程,并且我被read()示例所困扰,该示例处理了所有五种错误情况。我得到一个free(): invalid pointer
错误。我认为这与在读取未完成的情况下推进缓冲区有关。
如果我存储偏移量并将指针返回到其原始位置,则可以工作。这本书里没有提到这一点。有没有更好的方法?
#include <stdio.h>
#include <malloc.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
int main()
{
int fd;
if( (fd = open("someFile.txt", O_CREAT | O_WRONLY | O_TRUNC, 0664)) < 0)
perror("open for write");
char * text = "This is an example text";
write(fd, text, strlen(text));
close(fd);
if( (fd = open("someFile.txt", O_RDONLY)) < 0)
perror("open");
char *buf;
if( (buf = (char *) calloc(50, sizeof(char))) == NULL )
perror("calloc");
int len = 50;
ssize_t ret;
/* If I store the offset in a variable it works */
off_t offset = 0;
while (len != 0 && (ret = read (fd, buf, len)) != 0) {
if (ret == -1) {
if (errno == EINTR)
continue;
perror ("read");
break;
}
len -= ret;
buf += ret;
offset += ret; // Offset stored here
}
if( close(fd) == -1 )
perror("close");
buf -= offset; // Here I return the pointer to its original position
free(buf);
return 0;
}
这段代码有多个bug。
首先,perror
没有被正确使用,因为它只打印一个错误——这里还应该有代码在错误时中止,这样后续代码就不会尝试使用失败操作的结果。
其次,只有calloc
的结果才能给出free。结果保存在buf
中,但随后的代码更改buf
的值并尝试释放更改后的值。将更改存储在offset
中应该可以解决这个问题,但这充其量是一个容易出错的解决方案。如果你有多个修改buf
的代码路径,你必须确保每一个都以同样的方式修改偏移量。
一个更好的方法是不修改buf
,而是在读取中使用第二个指针变量,该变量初始化为buf
的值,然后在每次读取后进行修改。
如前所述,给定给calloc
的数与len
初始化为的数不同。这是一个滥用神奇数字的完美例子。20和50都应该替换为相同的符号(变量或常量或#define),这样你就不会得到缓冲区溢出错误。