各种糟糕,入坑这么久才开始看K&R的The C Programming Language学C,而且还是为了应付开学某场滚回本体的考试(虽然觉着即使复习了还会被各种吊打),废话不多说,开始施工.
|-->
第一章 导言
数据类型小结:
关键字 | 位长(字节) | 范围 | 格式化字符串 |
char | 1 bytes | -128..127(或0..255,与体系结构相关) | %c |
unsigned char | 1bytes | 0..255 | %c, %hhu |
signed char | 1bytes | -128..127 | %c, %hhd, %hhi |
int | 2bytes(16位系统) | -32768..32767 | %i, %d |
4bytes | -2147483648..2147483647 | ||
unsigned int | 2bytes | 0..65535 或 | %u |
4 bytes | 0..4294967295 | ||
signed int | 2bytes | -32768..32767 | %i, %d |
4bytes | -2147483648..2147483647 | ||
short int | 2bytes | -32768..32767 | %hi, %hd |
unsigned short | 2 bytes | 0..65535 | %hu |
signed short | 2bytes | -32768..32767 | %hi, %hd |
long int | 4bytes | -2147483648..2147483647 | %li, %ld |
8bytes | -9223372036854775808..9223372036854775807 | ||
unsigned long | 4bytes | 0..4294967295 或 | %lu |
8 bytes | 0..18446744073709551615 | ||
signed long | 4 bytes | -2147483648..2147483647 或 | %li, %ld |
8bytes | -9223372036854775808..9223372036854775807 | ||
long long | 8bytes | -9223372036854775808..9223372036854775807 | %lli, %lld |
unsigned long long | 8bytes | 0..18446744073709551615 | %llu |
float | 4bytes | 3.4x10−38..3.4x10+38 (7 sf) | %f, %e, %g |
double | 8bytes | 1.7x10−308..1.7x10+308 (15 sf) | %lf, %e, %g |
long double | 8 bytes或以上 | 编译器相关 | %Lf, %Le, %Lg |
第二章 类型、运算符与表达式
除法、取模:
整数除法会截断结果中的小数部分(向零取整,truncate towards 0),故先乘后除. 在有负操作数的情况下,整数除法截取的方向以及取模运算结果的符号取决于具体机器的实现,这和处理上溢或下溢的情况是一样的,可以保证的是 (x / y) * y + ( x % y) == x. (C99明确a / b、a % b结果正负与a相同)
类型转换:
当把float转换为int时小数部分会被截断,float转换为double时截断还是四舍五入取决于具体实现(待补CSAPP).
1UL < -1L < 1U
条件表达式:
对于expr1 ? expr2 : expr3,若expr2、expr3类型不同,结果类型由类型转换规则决定.
运算符优先级与结合性:
()、 []、 -> 、 . | 圆括号、方括号、指针、成员 |
++ 、 -- 、 * 、 & 、 ~ 、 ! 、 + 、 - 、 sizeof、(type) | 单目运算符(右结合) |
* 、 / 、 % | 算术运算符 |
+ 、 - | 算术运算符 |
<< 、 >> | 位运算符 |
< 、 <= 、 > 、 >= | 关系运算符 |
== 、 != | 关系运算符 |
& | 位与 |
^ | 位异或 |
| | 位或 |
&& | 逻辑与 |
|| | 逻辑或 |
? 、 : | 条件运算符 |
= 、 += 、 -= 、 *= 、 /= 、 %= 、 &= 、 |= 、 ^= | 赋值运算符(右结合) |
, | 顺序(逗号)运算符(右结合) |
除&&、||、,(逗号运算符)外C语言没有指定同一运算符多个操作数的计算顺序,以及函数各个参数的求值顺序.
第四章 函数与程序结构
全局变量、静态全局变量:
全局变量作用于所有源文件,但如果要在不包含该定义的源文件中引用,需要在所引用的源文件中声明为extern;
静态全局变量仅仅作用于所在源文件。
补充:
未初始化的全局变量存储在bss段 (Block Started by Symbol);
已初始化且不为0的全局变量存储在数据段(Data Segment)。
第五章 指针与数组
由于右结合性,*p++ ó *(p++) ,故若要表示 *p += 1 应写为 (*p)++。
注意指针是一个变量,而数组名不是变量;
在函数定义中,形参 char s[] 与 char s[] 等价。
一个用法:
void strcpy(char *s, char *t)
{
while(*s++ = *t++);
}
进栈出栈标准用法:
*p++ = val;
val = *--p;
多维数组、指针数组:
f(arr[i][j]) ó f(arr[][j]) ó f((*arr)[j]) //I, j 为常量
char *name[] = {"Link", "Zelda", "Rauru", "Fado"};
复杂声明:
K&R C为此直接写了一个Parser @_@ 私以为还是遵循"从内往外,从右往左"的读法。(参考 )
第六章 结构
sizeof:
sizeof <object name> or sizeof(<type name>)
#if 中不能使用 sizeof,因为预处理器不对类型名进行分析。而预处理并不计算#define中的表达式,所以在其中可以合法使用sizeof。
binsearch的一点修改:
设low=&a[0]、high=&a[n]分别表示指向表头、表尾元素的指针,则下面表达式无法计算中间元素位置:
mid = (low+high) / 2 /* wrong*/
原因是两个指针间加法是非法的,而减法是合法的,正确表达如下:
mid = low + (high-low) / 2
一点注意:
结构体的长度不一定等于各成员长度之和,与内存对齐要求有关。
位域(Bit Field):
struct S { // will usually occupy 8 bytes: // 5 bits: value of b1 // 27 bits: unused // 6 bits: value of b2 // 15 bits: value of b3 // 11 bits: unused unsigned b1 : 5; unsigned :0; // start a new unsigned int unsigned b2 : 6; unsigned b3 : 15;}; /* 摘自: http://en.cppreference.com/w/c/language/bit_field */
第七章 输入与输出
printf与scanf:
e/f/g 对printf来说指 double 类型(变长参数中float会提升为double);对scanf来说指 float* 类型,le/lf/lg 指double* 类型.
注意:
gets在读取字符串时将删除结尾'\n',puts再写入字符串时则会添加'\n'.
IO函数小结:
int getchar();int putchar(int);printf(const char * format, ...);scanf(const char * format, ...);/ * 文件操作 */int getc(FILE *fp);int putc(int c, FILE *fp);int fscanf(FILE *fp, char *format, ...);int fprintf(FILE *fp, char *format, ...);int fclose(FILE *fp);int ferror(FILE *fp);int feof(FILE *fp);char *fgets(char *line, int maxline, FILE *fp);int fputs(char *line, FILE *fp);
第八章 UNIX系统接口
暂时不管(从这强行跳票 = ,=
附录
有些挺有用的,以后碰到再做补充.
可变参数列表:
#include <stdarg.h>
va_list ap;
va_start(ap, lastarg);
Type value = va_arg(ap, Type);
va_end(ap);
<--|
C99:
具体参考
C11:
(Finished@2016/2/1)