【C语言】三剑客之《C陷井与缺陷》完整笔记( 二 )


main(){int i;char c;for(i = 0;i<5;i++){scanf("%d",&c);printf(“%d” , i);}}
随便输入五个数 3 2 5 8 6
输出是 0 0 0 0 0 1 2 3 4
因为输入的是int , 但却被指向了char , char放不下int , 剩下的int部分覆盖了char附近的内存 , 编译器决定了这块内存其实就是整数i的低端部分 ,  而i高8位在这里本来就是0 , 相当每读一次char , i就刷新为0 , 直到读取结束 , scanf没得读了 , 这是i才得以递增
4.4 头文件
一个好的习惯应该是:每个外部变量只在一个地方那个声明 , 这个声明的地方一般在一个头文件中 , 需要用到这个变量就包含这个头文件 , 定义该外部对象的模块也需要包含这个头文件
第5章:库函数 5.1 函数
先看一个例子:
#include main(){char c;while ((c = getchar()) != EOF){putchar(c);}}
c被声明成char类型而不是int类型 , 这一意味着c无法容下所有可能的字符 , 特别是无法容下EOF 。有可能字符被截断后使得c与EOF相同 , 也有可能c永远取不到EOF这个值 , 陷入死循环
5.2 更新顺序文件
while(fread((char*) &rec , sizeof(rec)  ,  1 ,  fp)==1){/*对rec执行某些操作*/if(/*rec必须被重新写入*/) {fseek(fp , -(long) sizeof(rec)  ,  1) ;fwrite((char*) &rec , sizeof(rec)  ,  1 ,  fp) ;}}
但是这样就可以了吗
while(fread((char*) &rec , sizeof(rec)  ,  1 ,  fp)==1){/*对rec执行某些操作*/if(/*rec必须被重新写入*/) {fseek(fp , -(long) sizeof(rec)  ,  1) ;fwrite((char*) &rec , sizeof(rec)  ,  1 ,  fp) ;fseek(fp ,  0L , 1);}}
不要忘了这是一个循环语句 , 别顾头不顾腚
5.3 缓冲输出和内存分配
#includemain(){int C;char buf[BUFSIZ] ;setbuf(stdout,buf) ;while((c = getchar() )!=EOF)putchar(c);}
但这样是错的 , 因为buf在被清空之前已经被释放(出main函数时) , 清空会出错

【C语言】三剑客之《C陷井与缺陷》完整笔记

文章插图
两作者提供种种解决思路:
一是让缓冲区成为静态数组 , 既可以显式声明为: char buf[]; , 也可以把buf声明放在main之前
二是动态分配缓冲区 , main结束时 , 系统就不会主动释放分配的缓冲区
其实我想 , 我在main结束前清理一下buf不就好了 , 这在一般子函数里是常规操作 , 不过作者通过上面两种方法提醒了我们两点:main里的变量也是有生命周期的;系统会自动清理我们定义的变量 , 如果在这之前 , 变量的声明周期已经结束被释放 , 就不妙了
5.4 函数5.5 使用errno检测错误
#include #include #include extern int errno ;int main (){FILE *fp;fp = fopen("file.txt", "r");if( fp == NULL ) {fprintf(stderr, "Value of errno: %d\n", errno);fprintf(stderr, "Error opening file: %s\n", strerror(errno));}else {fclose(fp);}return(0);}
让我们编译并运行上面的程序 , 当文件 file.txt 不存在时 , 将产生以下结果: