我需要从stdin读取并填充_SC_PAGESIZE的缓冲区(来自sysconf()),直到stdin处于EOF。这个程序应该是一个wc克隆,所以我希望传递一个类似于常规文件内容的东西。如果缓冲区对于stdin来说不够大,那么我必须继续填充它,处理它用于获取信息,然后清除它并继续从stdin中的文件偏移量再次填充缓冲区。我跟踪stdin的EOF时遇到了问题,而且我得到了一个无限循环。这就是我所拥有的:
int pSize = sysconf(_SC_PAGESIZE);
char *buf = calloc(pSize, sizeof(char));
assert(buf);
if (argc < 2) {
int fd;
while (!feof(stdin)) {
fd = read(0, buf, pSize);
if (fd == -1)
err_sys("Error reading from file\n");
lseek(0, pSize, SEEK_CUR);
if (fd == -1)
err_sys("Error reading from file\n");
processBuffer(buf);
buf = calloc(pSize, sizeof(char));
}
close(fd);
}
我假设问题与测试条件有关(而(!feof(stdin)),所以我想我需要的是一个正确的测试条件来退出循环。
答案 0 :(得分:2)
您可以像
一样编写循环int n;
do {
n = read(0, buf, pSize);
// process it
} while(n > 0);
记住EOF只是一个退出条件,可能在任何其他错误情况发生之前不会发生。真正检查运行循环的有效性是来自read
的健康返回代码。另请注意,条件while(n > 0)
是否足够取决于您所在的位置。在stdin
的情况下,它可能就足够了。但是例如对于套接字,条件可以写成while(n > 0 || errno == EAGAIN)
答案 1 :(得分:1)
为什么您使用的是低级read
而不是打开FILE *stream
并使用fgets
(或POSIX getline
)?此外,每次打电话时都会泄漏内存:
buf = calloc(pSize, sizeof(char));
在你的循环中,因为你覆盖了buf
中包含的地址,失去了对前一块内存的引用,导致无法free
。
相反,分配缓冲区一次,然后不断填充缓冲区,将填充的缓冲区传递给processBuffer
。您甚至可以使用三元运算符来确定是打开文件还是只读取stdin
,例如
int pSize = sysconf(_SC_PAGESIZE);
char *buf = calloc(pSize, sizeof(char));
assert(buf);
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) {
perror ("fopen failed");
return 1;
}
while (fgets (buf, pSize, fp))
processBuffer(buf); /* do not call calloc again -- memory leak */
if (fp != stdin) fclose (fp); /* close file if not stdin */
(注意:,因为fgets
将一次读取一行,您可以简单地计算迭代次数以获取行数 - 前提是您的行不是超过_SC_PAGESIZE
)
如果您想使用精确的pSize
块,则可以使用fread
代替fgets
。唯一的影响是将呼叫次数减少到processBuffer
,但这完全取决于您。您唯一需要做的就是将while (...)
行更改为:
while (fread (buf, (size_t)pSize, 1, fp) == 1)
processBuffer(buf); /* do not call calloc again -- memory leak */
if (ferror(fp)) /* you can test ferror to insure loop exited on EOF */
perror ("fread ended in error");
(注意:与read
类似,fread
无法确保buf
中的 nul-terminated 字符串,因此请确保processBuffer
不会将buf
传递给期望字符串的函数,也不会迭代buf
期望在末尾找到 nul-terminatedating 字符。)
仔细看看,如果您有其他问题,请告诉我。