C Traps and Pitfalls 读书笔记

第1章 词法陷阱

int getc(FILE *stream) 从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。

本意: 跳过文件中的SPACE, TAB, ENTER

while (c = ' ' || c == '\t' || c == '\n')
	c = getc(f);

实际将 ' ' || c == '\t' || c == '\n'赋值给 c, ' 'ASCII值为32,!=0, 所以该表达式为 1

while (c = 1)

char *slash = '/'; // ERROR '/'不是字符指针

printf('\n'); // ERROR
printf("\n"); // RIGHT

第2章 语法陷阱

float ff(); // return value 为 float 的 func

float *g(); // g()的返回值为指向float数的指针
float* g(); // 我曾经喜欢这么写,笑死

float (*h)(); //h是函数指针, 所指向函数的返回值是float

希望调用首地址为0的子例程: (void (*)()) 00转化为返回值为void类型的函数指针 ((void (*)()) 0)();调用它

if (x == 0) // A
	if (y == 0) error; // B
	// else 与 B 处 if 配对
else{
	z = x + y;
}

这个其实敲得时候感觉很明显啊,A处的if 应该会有一个{}把剩下的ifelse括起来。

第3章 语义陷阱

b是有17个元素的数组,每个元素是个结构体

struct {
	int p[4];
	double x;
}b[17];

int c[12][31] c是一个数组,有12个元素,即c[12],每个元素是有31个int元素的数组(可以看做int arr[31], arr代表c[12]

第4章 连接

C 是separate compilation, 单独编译,由连接器整合。

static (1)在修饰变量的时候,static 修饰的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。 (2)static 修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是 extern 外部声明也不可以。 (3)static 修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。static 修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存。初始化的时候自动初始化为 0。 (4)不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用 static 修饰。 (5)考虑到数据安全性(当程序想要使用全局变量的时候应该先考虑使用 static)。

extern可以在一个文件中引用另一个文件中定义的变量或者函数

第5章 库函数

<errno.h> 头文件中有一个 errno 宏,它就用来存储错误代码,当系统调用或者函数调用发生错误时,就会将错误代码写入到 errno 中,再次读取 errno 就可以知道发生了什么错误。 使用 perror() 将错误信息(文本)打印到标准输出设备; 使用 strerror() 将错误代码转换成对应的文本信息。

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
    errno = 0;  //将 errno 设置回 0 值
    FILE *fp = fopen("./demo.txt", "r");
    if(fp){
        printf("Congratulations, the file opens successfully!\n");
    }else{
        printf("Error no.%d: %s\n", errno, strerror(errno));
    }
    return 0;
}

第6章 预处理器

第7章 可移植性缺陷