《C陷阱与缺陷》:缓冲输出和内存分配

程序输出有两种方式:一种是即时处理方式,另一种是先暂存起来,然后再大块写入的方式,前者往往造成较高的系统负担。

因此,C语言实现通常都允许程序员进行实际的写操作之前控制产生的输出数据量。

这种控制能力一般是通过库函数 setbuf 实现的。如果 buf 是一个大小适当的字符数组,那么:

 setbuf(stdout,buf);

语句将通知输入/输出库,所有写入到 stdout 的输出都应该使用 buf 作为输出缓冲区,知道 buf 缓冲区被填满或者程序员直接调用fflush(注:对于由写操作打开的文件,调用 fflush 将导致输出缓冲区的内容被实际的写入该文件),buf 缓冲区中的内容才实际写入到 stdout 中。缓冲区的大小由系统头文件 stdio.h 中的BUFSIZ 定义。

下面的程序的作用是把标准输入的内容复制到标准输出中,演示了 setbuf 库函数最显而易见的用法:

#include <stdio.h>

int main()
{
    int c;
    char buf[BUFSIZ];
    setbuf(stdout,buf);

    while( ( c = getchar() ) != EOF )
    {
        putchar(c);
    }

    return 0;
}

遗憾的是,这个程序是错误的,仅仅是因为一个细微的原因。程序中对库函数 setbuf 的调用,通知了输入/输出库所有字符的标准输出应该首先缓存在 buf 中。要找到问题出自何处,我们不妨思考一下buf缓冲区最后一次被清空是在什么时候?答案是在 main 函数结束之后,作为程序交回控制给操作系统之前C运行时库所必须进行的清理工作的一部分。但是,在此之前 buf 字符数组已经被释放

要避免这种类型的错误的办法是:让缓冲数组成为静态数组,既可以直接显式声明 buf 为静态:

 static char buf[BUFSIZ];

也可以把 buf 声明完全移到 main 函数之外。

第二种方法是动态分配缓冲区,在程序中并不主动释放该缓冲区,这样c运行是库进行清理工作时就不会发生缓冲区已经被释放的情况。

char *malloc();
setbuf(stdout, malloc(BUFSIZE));

这里其实并不需要检查 malloc 函数调用是否成功,如果 malloc 函数调用失败将会返回一个 NULL 指针,setbuf 函数的第二个参数可以为NULL,此时标准库不需要进行缓冲。这种情况下程序仍然能够工作,只不过速度慢一些而已。

本文摘自:《C陷阱与缺陷》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值