《 C语言程序设计(第2版)》 读书笔记 —Brian W.Kernighan 等著 徐宝文 李志 译
- 在C语言中,所有的变量必须先声明,后使用。声明通常放在函数起始处,在任何执行语句之前。
- stdio.h scanf scanf_s printf 解密
- 标准库 字符输入、输出 getchar() putchar()
- strlen() 求字符串长度和sizeof的区别 string.h 探秘
- ‘a’ 其ASCII码为97 ‘A’的ASCII码为 65 ,小写字母比大写对应字母的ASCII码大32,
tolower() 标准库《ctype.h> atio(),itoa(),strtol() <math.h>
break 跳出本次循环 continue 立即结束本次循环
goto语句 :最常见的用法是终止程序或在某些深度嵌套的结构中处理。{
goto tag;
…
tag:
}- p71: auto static extern register 变量类型
register: 寄存器变量,声明告诉编译器,他所声明的变量在程序中使用频率较高。其思想是将register 变量放在机器的寄存器中,这样可以是程序更小,执行速度更快,但编译器可以忽略此项。 register声明只适用于自动变量以及函数形参,但寄存器变量的地址都不能访问。 p75: C预处理器: #include #define #undef (取消宏定义)
形式参数不能用带引号的字符串替换,但参数名以#作为前缀及可以:`#define dprint(expr) printf(#expr " = %g\n",expr)`
使用语句:
dprint(x/y)
调用该宏时,该宏将被扩展为:`printf("x/y" " =%g\n",x/y)`
字符串连接起来,其等价于:
`printf("x/y = %g\n",x/y)`
预处理器运算符##为宏扩展提供了一种连接参数的手段:
#define paste(front,back) front ## back
paste(name,1)
将建立记号:name1条件包含:
#if !defined(HDR)
#define HDR
/*hdr.h放在这里*/
#endif
等价于:#ifndef HDR
#define HDR
/*hdr.h放在这里*/
#endif
p79 指针与数组: C使用void*(指向viod的指针) 作为通用指针
- 指针与地址: 通常机器内有一系列连续编号或编址的存储单元,这些存储单元可以单个进行操作,也可以以连续成组方式操作。 指针只能指向某种特定类型的对象(例外是指向void类型的指针可以存放任何类型的指针,但不能间接引用其自身。
- 指针与函数参数:指针参数是的被调用函数能够访问和修改主调函数中对象的值。
- 指针与数组:指针是变量,数组名不是变量 访问数组使用指针一般比较快,*(a+i) 等价于 a[i]
- 把数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址,即在函数定义中,形式参数 char s[]与char* s 是等价的,通常使用后一种。
- 地址运算符: alloc() afree() malloc() free() 解密
- C语言保证,0永远不是有效的数据地址,因此返回值0可用来表示发生了异常事件。指针与整数之间不能互相转换,但0是唯一例外,程序经常使用NULL代替常亮0,便于清晰的说明常量0是指针的一个特殊值。NULL 定义在
<stddef.h>
中 下面两个定义有很大差别:
'char amessage[] = "now is the time"; /* 定义一个数组 */ char *pmessage = "now is the time"; /* 定义一个指针 */'
amessage是一个仅仅足以存放初始化字符串以及空字符’\0’的一维数组。数组中的单个字符可以进行修改,但amessage 始终指向同一个存储位置。另一方面,pmessage是一个指针,其初值指向一个字符串常量,之后可以被修改以指向其他地址,但如果试图修改字符串的内容,结果是没有定义的。
p92 指针数组: 数组元素中存数的是指针
`char *line[10]`
line 是一个含有10元素的一维数组,其中数组的每个元素是一个指向char型的指针,即line[i]是一个字符指针,而*line[i]是指向的第i个文本行的首字符。
p95 多维数组: int a[3][5],若作为参数传递给函数,必须指明列数,
f(int a[3][5]){...}
解*(*(a+i)+j)
或f(int a[][5]){...}
或f(int (*a)[5]){...}
(指向数组的指针)p 98 命令行参数:
在支持c语言的环境中,可以在程序中将命令行的参数传递给程序,在调用主程序是,其有两个参数,
`main( int argc,char *grgv[])`
argc:用于统计参数个数, argv,用于参数向量,是一个指向字符串数组的指针,其中每个字符串对应一个参数。
按照c语言约定,argv[0]的值是启动该程序的程序名,因此argc的值至少为1
指向函数的指针:
`int (*comp)(void*,void*)` //comp是一个指向函数的指针
结构体: (解密结构体声明及使用)
struct tag
{
}计算结构体的大小:sizeof(struct);(对齐原则)
类型定义:typedef:
`typedef struct node *treenode`
联合体可以(在不同时刻)保存不同类型和长度的对象的变量,编译器负责跟踪对象的长度和对其要求。
uinon u_tag
{
int a;
float b;
char* c;
} u;
其所有的成员相对于基地址的偏移量都为0,此结构空间大要大到足够容纳最“宽”成员。union 解密:
位字段:位字段是C语言中一种存储结构,不同于一般结构体的是它在定义成员的时候需要指定成员所占的位数。
`typedef struct bit_field { unsigned int a : 5; unsigned int b : 3; unsigned int c : 20; unsigned int d : 4; } bit_field_s;
`
在如上定义中,bit_field_s结构体只占用一个DWORD的空间,即4个字节。其中成员a占用5位,成员b占用3位,成员c占用20位,成员d占用4位.输出输出:
标准输入与输出:
<stdio.h>
stdin stdoutint getchar() //一次读取一个字符,遇到结尾返回EOF(-1) 均为宏定义
int putchar(int) //一次输出一个字符,出错返回EOF
格式化输入输出
int printf(char *format,arg1,arg2,..)//返回打印的字符数 int scanf(char *format,arg1,arg2,...)//从标准输入中读取参数,按照format中说明的格式对字符串序列进行解释,并把结果保存到其余参数中, char * gets ( char * str );//读取字符串,欲换行符'\n'结束,并删除换行符, int puts ( const char * str );//输出字符串,末尾自动添加换行符 int sprintf(char *string,char* format,arg1,arg2,...)//将输出保存到字符串string中 int sscanf(char* string,char* format,arg1,arg2,...)//扫描字符串string的内容,并把结果保存在arg1,arg2...的参数中
文件访问:
`FILE *fp; FILE *fopen(char* name,char *mode)`
调用fopen函数,打开文件
`fp=fopen(name,mode)`
文件被打开后,对文件读写:
`int getc(FILE *fp)//读文件,返回字符 int putc(int c,FILE *fp)`//将c写到文件
对于文件的格式化输入输出,则为:
`int fscanf(FILE *fp,char *format,...) int fprintf(FILE* fp,char* format,...)`
关闭文件,释放资源
`int fclose(FILE* fp)`
错误处理:
`stderr \\标准错误输出 int ferror(FILE *fp)\\如果流fp中出现错误,则函数ferror返回一个非0值 int feof(FILE *fp)\\如果指定的文件到达文件结尾,它将返回一个非0值 exit(expr); 在main函数中等价于return expr,返回0 ,正常,异常返回非0,`
行输入与输出:
`char *fgets(char *line,int maxline,FILE *fp)//从fp指向的文件中读取下一个输入行(包括换行符),并将它存放在字符数组中,最多可以读取maxline-1个字符,读取的行以'\0'结尾。 int fputs(char*line,FILE *fp)`//将一个字符串(不需要包含换行符)写入到一个文件中
字符串操作函数
<string.h>
字符类别测试和转换函数
<ctype.h>
'ifalpha(c) isupper(c) islower(c)'
ungetc()函数
命令执行函数: ‘system(char* s)’
存储管理函数:
`void *malloc(size_t n) void *calloc(size_t n,size_t size) void free (void* ptr);`
随机发生器函数
int rand (void);//Returns a pseudo-random integral number in the range between 0 and RAND_MAX. eg: v1 = rand() % 100; // v1 in the range 0 to 99 v2 = rand() % 100 + 1; // v2 in the range 1 to 100 v3 = rand() % 30 + 1985; // v3 in the range 1985-2014