[C陷阱和缺陷] 第5章 库函数

  有关库函数的使用,我们能给出的最好建议是尽量使用系统头文件,当然也可以自己造轮子,随个人喜好。本章将探讨某些常用的库函数,以及编程者在使用它们的过程中可能出错之处。
 

5.1 返回整数的getchar函数

  我们首先考虑下面的例子:

    #include<stdio.h>

    int main()
    {
        char c;

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

        return 0;
    }

  上面代码在某些情况下可能出错,原因在于变量 c 被声明为 char 类型,而不是 int 类型。这意味着 c 无法容纳下所有可能的字符,(有可能发生“截断” )特别是,可能无法容纳下EOF。
  因此可能出现两种可能。一种可能是,某些合法的输入字符在被“截断” 后使得 c 的取值与EOF相同;另一种可能是,c 根本不可能取到EOF这个值。对于前一种情况,程序将在文件复制的中途终止;对于后一种情况,程序将陷入一个死循环。

5.2 更新顺序文件

  看下面这段代码:

    FILE    *fp;
    fp = fopen(filename,"r+");
    struct record rec;
    .....
    while(fread( fread( (char*)&rec, sizeof(rec), 1, fp ) == 1 )
    {
        if(/*rec必须被重新写入*/)
        {
            fseek(fp, -(long)sizeof(rec), 1); //文件指针向前移动一个结构体大小的长度
            fwrite( (char*)&rec, sizeof(rec), 1, fp );
        }
    }

 
  这段代码咋看上去毫无问题: &rec 在传入 fread 和 fwrite 函数时被小心翼翼地转换为字符指针类型,sizeof(rec)被转换为长整型 ( fseek 函数要求第二个参数是long类型,因为 int 类型的整数可能无法包含一个文件的大小;sizeof返回一个unsigned值,因此首先将其转换为有符号类型才有可能将其反号)。但是这段代码仍然可能运行失败,而且出错的方式非常难以察觉。
  问题出在:为了保持与过去不能同时进行读写操作的程序的向下兼容性,一个输入操作不能随后直接紧跟一个输出操作,反之亦然。如果要同时进行输入和输出操作,必须在其中插入 fseek 函数的调用,即使fseek什么也没做。解决的办法是把这段代码改写为:

    while(fread( fread( (char*)&rec, sizeof(rec), 1, fp ) == 1 )
    {
        if(/*rec必须被重新写入*/)
        {
            fseek(fp, -(long)sizeof(rec), 1); //文件指针向前移动一个结构体大小的长度
            fwrite( (char*)&rec, sizeof(rec), 1, fp );
            fseek(fp, 0L, 1);
        }
    }

  第二个 fseek 函数虽然看上去什么也没做,但它改变了文件的状态,使得文件现在可以正常地进行读取了。

5.3 缓存输出与内存分配

  当一个程序生成输出时,.....(未完待续)

猜你喜欢

转载自www.cnblogs.com/linuxAndMcu/p/10067594.html