缓冲输出和内存分配的问题一直让我很头痛,学了几天了,总算有点眉目,下面是一些这方面资料和大家共享.
由于立即安排输出的显示通常比将其暂时保存在一大块一起输出要昂贵得多。因此,
C
实现通常允许程序员控制产生多少输出后在实际地写出它们。
这个控制通常约定为一个称为
setbuf()
的库函数。如果
buf
是一个具有适当大小的字符数组,则
setbuf(stdout, buf);
将告诉
I/O
库写入到
stdout
中的输出要以
buf
作为一个输出缓冲,并且等到
buf
满了或程序员直接调用
fflush()
再实际写出。缓冲区的合适的大小在中定义为
BUFSIZ
。
因此,下面的程序解释了通过使用
setbuf()
来讲标准输入复制到标准输出:
#include
main() {
int c;
char buf[BUFSIZ];
setbuf(stdout, buf);
while((c = getchar()) != EOF)
putchar(c);
}
main() {
int c;
char buf[BUFSIZ];
setbuf(stdout, buf);
while((c = getchar()) != EOF)
putchar(c);
}
不幸的是,这个程序是错误的,因为一个细微的原因。
要知道毛病出在哪,我们
需要知道缓冲区最后一次刷新是在什么时候。答案;主程序完成之后,库将控制交回到操作系统之前所执行的清理的一部分。在这一时刻,缓冲区已经被释放了
!
有两种方法可以避免这一问题。
首先,使用静态缓冲区,或者将其显式地声明为静态:
static char buf[BUFSIZ];
或者将整个声明移到主函数之外。
另一种可能的方法是动态地分配缓冲区并且从不释放它:
char *malloc();
setbuf(stdout, malloc(BUFSIZ));
setbuf(stdout, malloc(BUFSIZ));
注意在后一种情况中,不必检查
malloc()
的返回值,因为如果它失败了,会返回一个空指针。而
setbuf()
可以接受一个空指针作为其第二个参数,这将使得
stdout
变成非缓冲的。这会运行得很慢,但它是可以运行的。