├── README.md ├── ch1 ├── a_guick_start ├── a_guick_start.c ├── ch1.txt ├── p3 ├── p3.c ├── p5 ├── p5.c ├── p6 └── p6.c ├── ch10 ├── ch10.txt ├── p1.c ├── p2.c └── p3.c ├── ch11 ├── ch11.txt ├── p1.c ├── p2.c └── p3.c ├── ch12 ├── ch12.txt ├── p1.c ├── p2.c ├── p3.c ├── p4.c ├── p5.c ├── p6.c ├── q1.c └── q4.c ├── ch13 ├── ch13.txt ├── q1.c ├── q1.md ├── q11.md ├── q2.c ├── q3.c ├── q4.c ├── q5.c ├── q7.md └── q9.md ├── ch14 ├── ch14.txt ├── p1.c ├── q1.md ├── q2.md ├── q3.md ├── test.c ├── 宏和函数的不同之处.png └── 预定义符号.png ├── ch2 ├── ch2.txt ├── p1 │ ├── increment.c │ ├── increment.h │ ├── main │ ├── main.c │ └── negate.h ├── p2 ├── p2.c ├── q3 ├── q3.c ├── q4 └── q4.c ├── ch3 ├── ch3.txt └── q23.c ├── ch4 ├── ch4.txt ├── do语句执行过程.png ├── for语句执行过程.png ├── p1.c ├── p2.c ├── p3.c ├── p4.c ├── p5.c ├── p7.c ├── q10.c ├── q11.c ├── q12.c ├── q13.c ├── q14.c ├── q15.c ├── q16.c ├── q4.c ├── test.txt └── while语句执行过程.png ├── ch5 ├── UU7TH(Q{9])M44@~0HGE]Y1.png ├── ch5.txt ├── p1.c ├── p2.c ├── p3.c ├── p4.c └── p5.c ├── ch6 ├── a.out ├── ch6.txt ├── p1.c ├── p2.c ├── p3.c ├── p4.c ├── p5.c └── p6.c ├── ch7 ├── a.out ├── ch7.txt ├── factorial.c ├── fibonacci.c ├── p1.c ├── p2.c ├── p3.c ├── p4.c ├── p5.c └── p6.c ├── ch8 ├── a.out ├── ch8.txt ├── p1.c ├── p2.c ├── p3.c ├── p4.c ├── p5.c ├── p6.c ├── p7.c ├── p8.c ├── q19.c └── q4.c └── ch9 ├── a.out ├── ch9.txt ├── p1.c ├── p10.c ├── p11.c ├── p12.c ├── p13.c ├── p14.c ├── p15.c ├── p2.c ├── p3.c ├── p4.c ├── p5.c ├── p6.c ├── p7.c ├── p8.c ├── p9.c ├── test9.6.1.c └── test9.6.2.c /README.md: -------------------------------------------------------------------------------- 1 | # Pointers_On_C 2 | 《C和指针》读书笔记 3 | 4 | 本笔记为作者在2016年寒假期间所写,写此笔记的目的是为了复习和巩固C语言的知识。 5 | 每一个文件加代表一个《C和指针》中一章内容。其中.txt文件中记录了作者整理的每 6 | 一章的重点内容,并且包含每章课后练习和问题(以p开头的表示练习题,以q开头的表 7 | 示问题)。 8 | -------------------------------------------------------------------------------- /ch1/a_guick_start: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch1/a_guick_start -------------------------------------------------------------------------------- /ch1/a_guick_start.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #define MAX_COLS 20 /*所能处理的最大的列数*/ 5 | #define MAX_INPUT 1000 /*所能输入的最大的列数*/ 6 | 7 | 8 | /* 9 | *从命令行读取字符串 10 | */ 11 | int read_column_numbers( int columns[], int max) 12 | { 13 | /* 14 | *在定义数组参数的时候没有定义数组的长度,这导致函数会处理该指针之后的任意长度 15 | *的内存中的数据,这是不安全的,所以一般都是同时定义一个表示该数组长度的变量 16 | */ 17 | 18 | int num = 0; 19 | int ch; /*防止输入的字符意外被解释成EOF,声明成int类型*/ 20 | 21 | while( num < max && scanf( "%d", &columns[num] ) == 1 && columns[num] > 0) 22 | /* 23 | *对于scanf函数来说,除了从标准输出中读取一个字符串之外,其他情况下, 24 | *都需要在变量之前加一个&符号 25 | */ 26 | { 27 | num++;/*使用while时通常会忘记++操作*/ 28 | } 29 | 30 | if( num % 2 != 0)/*num可以表示已经读取的个数*/ 31 | { 32 | puts("Last column number is not paired!"); 33 | /* 34 | *gets的输出版本,将字符串输出到标准输出中,并在末尾添加一个换行 35 | *gets丢弃换行符,在在字符串的末尾加一个NUL作为终止符 36 | */ 37 | exit( EXIT_FAILURE);/*直接退出无返回值*/ 38 | } 39 | 40 | while( (ch = getchar()) != EOF && ch != '\n' );/*过滤掉负数后面的数*/ 41 | 42 | return num; 43 | } 44 | 45 | /* 46 | *处理输入的字符串 47 | */ 48 | void rearrange( char *output, char *const input, int const columns[], int num_column ) 49 | { 50 | int length = strlen( input ); 51 | int output_column = 0; /*output数组的下标*/ 52 | 53 | for( int column = 0; column < num_column; column += 2 ) 54 | /* 55 | * for循环中第一部分初始化只执行一次,第二部分在每次循环之前执行, 56 | * 第三部分在每次循环之后执行 57 | */ 58 | { 59 | int nchars = columns[column+1] - columns[column] + 1; 60 | /* 61 | *输入的行结束或者输出的行数组已经满了(通过数组下标来判断) 62 | */ 63 | if( output_column > MAX_INPUT - 1 || columns[column] > length) 64 | { 65 | break; 66 | } 67 | 68 | /* 69 | *输出的数组的空间不够,能存多少就存多少 70 | */ 71 | if( nchars > MAX_INPUT - output_column - 1 ) 72 | { 73 | nchars = MAX_INPUT - output_column - 1; 74 | } 75 | 76 | strncpy( output + output_column, input + columns[column], nchars ); 77 | output_column += nchars; 78 | } 79 | 80 | output[output_column] = '\0';/*字符串结束*/ 81 | } 82 | 83 | int main() 84 | { 85 | int columns[MAX_COLS]; 86 | char input[MAX_INPUT]; 87 | char output[MAX_INPUT]; 88 | 89 | int num = read_column_numbers( columns, MAX_COLS); 90 | int index = 0; 91 | 92 | while( fgets( input, sizeof(input), stdin ) != NULL && input[0] != '\n') 93 | { 94 | /* 95 | *删去不想要的换行 96 | */ 97 | if(input[strlen(input)-1]=='\n') 98 | input[strlen(input)-1]='\0'; 99 | printf("输入字符串:%s\n", input ); 100 | rearrange( output, input, columns, num ); 101 | printf("输出字符串:%s\n", output ); 102 | } 103 | return EXIT_SUCCESS; 104 | } 105 | -------------------------------------------------------------------------------- /ch1/ch1.txt: -------------------------------------------------------------------------------- 1 | 1.编译程序时,出现如下的警告: 2 | 82:2: warning: ‘gets’ is deprecated (declared at /usr/include/stdio.h:638) [-Wdeprecated-declarations] 3 | 经过查资料发现,原来使用gets容易引起内存溢出,可以使用fgets代替 4 | 5 | 2.使用#define指令给常量值取名,这样当改变常量时,只需要在一处改动,所有使用该常量的地方都会变。 6 | 7 | 3.始终要进行数组的越界检查.使用下标之前先检查它的值 8 | 9 | 4.gcc的全称是什么: 10 | gcc 是 gnu compiler collecti 编译器套装),它不仅仅只是编译c语言的编译器,它提供了 11 | 对c、面向对象的c(object c), c++, java, ada 语言的编译服务。过去有一段时间, 12 | 它被成为gnu c compiler是因为它最初的开发目的的确是只提供了c编译功能,但是现在已经不在是这样了。 13 | 14 | 5.gcc 和g++什么关系 15 | 事实上只有一个c++编译器,那就是g++。g++不仅仅是一个c++预处理器,而是一个实实在在的c++编译器。 16 | 由于它的名字 gnu c++ compiler 也能缩写成gcc,所以有时候有人叫它gcc也并不错。 17 | 而我们通常所说的gcc是一个编译器套装,gcc命令只是一个调用各个实际编译器的快捷方式而已。 18 | 19 | 6.gcc所支持的c语言规范有哪些 20 | 目前主要的c语言规范有c89(c90), c95(94)和c99。c89是最早的c语言规范,于89年提出,90年先由美国国家标准局推出ansi版本, 21 | 后来被接纳为iso国际标准 (iso/iec 9899:1990),因而有时也称为c90。但在94和96年分别对c90进行了两次错误修正, 22 | gcc支持的是修正后的c89(90)版本的c语言规范。在95年提出过对90版规范的修订案,称为 c95或者amd1。gcc也支持c95规范。 23 | 最新的一次c规范修订在99年制定(iso/iec 9899:1999),即常称的c99规范。在2001年对c99的错误进行了修正,gcc支持的修正后的c99规范, 24 | 但是到目前为止,gcc还没有完成对c99规范的完全支持。 25 | 在默认设置下,gcc对c语言进行了一些自己的扩展。在不加语言设置参数的情况下,gcc使用c89规范和自己的一些扩展。 26 | 在将来如果gcc完成了对c99的全面支持,可能默认会使用c99规范加gcc自己的扩展。 27 | 28 | 7.gcc下的语言规范设置: 29 | -std=iso9899:1990,-ansi或-std=c89 (三者完全等同)来指定完全按照c89规范,而禁止gcc对c语言的扩展。 30 | -std=iso9899:199409 使用c95规范 31 | -std=c99 或者 -std=iso9899:1999 使用c99规范。 32 | -std=gnu89 使用c89规范加上gcc自己的扩展(目前默认) 33 | -std=gnu99 使用c99规范加上gcc自己的扩展 34 | 35 | 8.gcc支持传统C语言(也就是K&R C),包括一些处于规范之外但常见且使用的C语法。在编译时,指定'-traditional'选项即可。 36 | 另外该选项还支持GNU对C语言的扩展gcc 的'-ansi'选项'-ansi'支持符合ANSI标准的C程序,这样就会关闭GNU C中某些不兼容ANSI C的特性, 37 | 例如asm, inline和 typeof关键字,以及诸如unix和vax这些表明当前系统类型的预定义宏,同时开启不受欢迎和极少使用的ANSI trigraph特性,以及禁止`$'成为标识符的一部分。 38 | 尽管使用了'-ansi'选项,下面这些可选的关键字, __asm__, __extension__, __inline__和__typeof__仍然有效.你当然不会把他们用在ANSI C程序中, 39 | 但可以把他们放在头文件里,因为编译包含这些头文件的程序时,可能会指定 `-ansi'选项。另外一些预定义宏,如__unix__和__vax__,无论有没有使用 ‘-ansi’选项,,始终有效。 40 | 使用‘-ansi'选项不会自动拒绝编译非ANSI程序,除非增加`-pedantic'选项作为 `-ansi'选项的补充。 41 | gcc 的‘-pedantic‘选项可打开完全服从ANSI C标准所需的全部警告诊断;拒绝接受采用了被禁止的语法扩展的程序。无论有没有这个选项,符合ANSI C标准的程序应该能够被正确编译(虽然极少数程序需要‘-ansi' 选项)。然而,如果没有这个选项,某些GNU扩展和传统C特性也得到支持。使用这个选项可以拒绝这些程序。没有理由使用这个选项,他存在只是为了满足一些书呆子(pedant)。对于替选关键字(他们以’__'开始和结束) ,‘-pedantic'不会产生警告信息。Pedantic 也不警告跟在__extension__后面的表达式,不过只应该在系统头文件中使用这种转义措施,应用程序最好 避免。 42 | -------------------------------------------------------------------------------- /ch1/p3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch1/p3 -------------------------------------------------------------------------------- /ch1/p3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include/* strlen函数在这个文件中 */ 3 | #include/* EXIT_SUCESS在stdlib.h文件中*/ 4 | #define MAX_INPUT 1000 5 | /* 6 | *当checksunm溢出的时候,由于该类型为有符号的字符行,所有以整数输出的时候 7 | * 将会是负值 8 | */ 9 | int main() 10 | { 11 | char input[MAX_INPUT]; 12 | signed char checksum = -1; 13 | 14 | if( fgets( input, sizeof(input), stdin ) != NULL ) 15 | { 16 | int index = 0; 17 | int length = strlen( input );/* strlen显示的字符串长度包括\0的长度 */ 18 | printf("字符串的长度为: %d,sizeof(input)= %ld \n", length, sizeof( input ) ); 19 | 20 | while ( input[ index ] != '\0') { 21 | checksum += input[ index ]; 22 | index++;/* s使用while循环时切记要进行索引的自增设置 */ 23 | } 24 | 25 | printf("输入的字符串为:%s", input ); 26 | printf("checksum为:%d\n", checksum ); 27 | } 28 | return EXIT_SUCCESS; 29 | } 30 | -------------------------------------------------------------------------------- /ch1/p5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch1/p5 -------------------------------------------------------------------------------- /ch1/p5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #define MAX_COLS 20 /*所能处理的最大的列数*/ 5 | #define MAX_INPUT 1000 /*所能输入的最大的列数*/ 6 | 7 | 8 | /* 9 | *从命令行读取字符串 10 | */ 11 | int read_column_numbers( int columns[], int max) 12 | { 13 | /* 14 | *在定义数组参数的时候没有定义数组的长度,这导致函数会处理该指针之后的任意长度 15 | *的内存中的数据,这是不安全的,所以一般都是同时定义一个表示该数组长度的变量 16 | */ 17 | 18 | int num = 0; 19 | int ch; /*防止输入的字符意外被解释成EOF,声明成int类型*/ 20 | 21 | while( num < max && scanf( "%d", &columns[num] ) == 1 && columns[num] > 0) 22 | /* 23 | *对于scanf函数来说,除了从标准输出中读取一个字符串之外,其他情况下, 24 | *都需要在变量之前加一个&符号 25 | */ 26 | { 27 | num++;/*使用while时通常会忘记++操作*/ 28 | } 29 | 30 | if( num % 2 != 0)/*num可以表示已经读取的个数*/ 31 | { 32 | puts("Last column number is not paired!"); 33 | /* 34 | *gets的输出版本,将字符串输出到标准输出中,并在末尾添加一个换行 35 | *gets丢弃换行符,在在字符串的末尾加一个NUL作为终止符 36 | */ 37 | exit( EXIT_FAILURE);/*直接退出无返回值*/ 38 | } 39 | 40 | while( (ch = getchar()) != EOF && ch != '\n' );/*过滤掉负数后面的数*/ 41 | 42 | return num; 43 | } 44 | 45 | /* 46 | *处理输入的字符串 47 | */ 48 | void rearrange( char *output, char *const input, int const columns[], int num_column ) 49 | { 50 | int length = strlen( input ); 51 | int output_column = 0; /*output数组的下标*/ 52 | 53 | for( int column = 0; column < num_column; column += 2 ) 54 | /* 55 | * for循环中第一部分初始化只执行一次,第二部分在每次循环之前执行, 56 | * 第三部分在每次循环之后执行 57 | */ 58 | { 59 | int nchars = columns[column+1] - columns[column] + 1; 60 | /* 61 | *输入的行结束或者输出的行数组已经满了(通过数组下标来判断) 62 | */ 63 | if( columns[column] > length ) 64 | { 65 | continue; 66 | }else if( output_column > MAX_INPUT - 1 ) 67 | { 68 | break; 69 | } 70 | 71 | /* 72 | *输出的数组的空间不够,能存多少就存多少 73 | */ 74 | if( nchars > MAX_INPUT - output_column - 1 ) 75 | { 76 | nchars = MAX_INPUT - output_column - 1; 77 | } 78 | 79 | strncpy( output + output_column, input + columns[column], nchars ); 80 | output_column += nchars; 81 | } 82 | 83 | output[output_column] = '\0';/*字符串结束*/ 84 | } 85 | 86 | int main() 87 | { 88 | int columns[MAX_COLS]; 89 | char input[MAX_INPUT]; 90 | char output[MAX_INPUT]; 91 | 92 | int num = read_column_numbers( columns, MAX_COLS); 93 | 94 | while( fgets( input, sizeof(input), stdin ) != NULL && input[0] != '\n') 95 | { 96 | printf("输入字符串:%s\n", input ); 97 | rearrange( output, input, columns, num ); 98 | printf("输出字符串:%s\n", output ); 99 | } 100 | return EXIT_SUCCESS; 101 | } 102 | -------------------------------------------------------------------------------- /ch1/p6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch1/p6 -------------------------------------------------------------------------------- /ch1/p6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #define MAX_COLS 20 /*所能处理的最大的列数*/ 5 | #define MAX_INPUT 1000 /*所能输入的最大的列数*/ 6 | 7 | 8 | /* 9 | *从命令行读取字符串 10 | */ 11 | int read_column_numbers( int columns[], int max) 12 | { 13 | /* 14 | *在定义整型数组参数的时候没有定义数组的长度,这导致函数会处理该指针之后的任意长度 15 | *的内存中的数据,这是不安全的,所以一般都是同时定义一个表示该数组长度的变量 16 | */ 17 | 18 | int num = 0; 19 | int ch; /*防止输入的字符意外被解释成EOF,声明成int类型*/ 20 | 21 | while( num < max && scanf( "%d", &columns[num] ) == 1 && columns[num] > 0) 22 | /* 23 | *对于scanf函数来说,除了从标准输出中读取一个字符串之外,其他情况下, 24 | *都需要在变量之前加一个&符号 25 | */ 26 | { 27 | num++;/*使用while时通常会忘记++操作*/ 28 | } 29 | 30 | 31 | while( (ch = getchar()) != EOF && ch != '\n' );/*过滤掉负数后面的数*/ 32 | 33 | return num; 34 | } 35 | 36 | /* 37 | *处理输入的字符串 38 | */ 39 | void rearrange( char *output, char *const input, int const columns[], int num_column ) 40 | { 41 | int length = strlen( input ); 42 | int output_column = 0; /*output数组的下标*/ 43 | 44 | for( int column = 0; column < num_column; column += 2 ) 45 | /* 46 | * for循环中第一部分初始化只执行一次,第二部分在每次循环之前执行, 47 | * 第三部分在每次循环之后执行 48 | */ 49 | { 50 | 51 | int nchars = 0; 52 | if( column < num_column-1 ) 53 | { 54 | nchars = columns[column+1] - columns[column] + 1; 55 | }else 56 | { 57 | nchars = length - columns[column] + 1; 58 | } 59 | /* 60 | *输入的行结束或者输出的行数组已经满了(通过数组下标来判断) 61 | */ 62 | if( columns[column] > length ) 63 | { 64 | continue; 65 | }else if( output_column > MAX_INPUT - 1 ) 66 | { 67 | break; 68 | } 69 | 70 | /* 71 | *输出的数组的空间不够,能存多少就存多少 72 | */ 73 | if( nchars > MAX_INPUT - output_column - 1 ) 74 | { 75 | nchars = MAX_INPUT - output_column - 1; 76 | } 77 | 78 | strncpy( output + output_column, input + columns[column], nchars ); 79 | output_column += nchars; 80 | } 81 | 82 | output[output_column] = '\0';/*字符串结束*/ 83 | } 84 | 85 | int main() 86 | { 87 | int columns[MAX_COLS]; 88 | char input[MAX_INPUT]; 89 | char output[MAX_INPUT]; 90 | 91 | int num = read_column_numbers( columns, MAX_COLS); 92 | 93 | while( fgets( input, sizeof(input), stdin ) != NULL && input[0] != '\n') 94 | { 95 | printf("输入字符串:%s\n", input ); 96 | rearrange( output, input, columns, num ); 97 | printf("输出字符串:%s\n", output ); 98 | } 99 | return EXIT_SUCCESS; 100 | } 101 | -------------------------------------------------------------------------------- /ch10/ch10.txt: -------------------------------------------------------------------------------- 1 | 1.struct { struct { 2 | int a; int a; 3 | char b; char b; 4 | float c; float c; 5 | } y[20], *z; } x; 6 | 以上连个声明虽然成员列表完全相同,但是y,z和x属于不同的类型,所以, 7 | z = &x;是非法的。 8 | 2.为了使y,z和x属于同一个类型,可以使用一下两种方法进行声明: 9 | 1)typedef struct { 10 | int a; 11 | char b; 12 | float c; 13 | } Simple; 14 | Simple x; 15 | Simple y[20], *z; 16 | 2)struct Simple { 17 | int a; 18 | char b; 19 | float c; 20 | }; 21 | struct Simple x; 22 | strcut Simple y[20], *z; 23 | 3.typedef struct { 24 | int a; 25 | SELF_REF3* b; 26 | int c; 27 | } SELF_REF3;错误,类型名直到末尾才定义,在声明的内部尚未定义。 28 | 可以用一个标签来解决这个问题: 29 | typedef struct SELF_REF3_TAG { 30 | int a; 31 | struct SELF_REF3_TAG *b; 32 | int c; 33 | } SELF_REF3; 34 | 4.不完整声明 35 | struct B; 36 | struct A{ 37 | struct B *partner; 38 | }; 39 | struct B{ 40 | struct A *partner; 41 | }; 42 | 5.结构变量可以用花括号来初始化变量,这些值的类型必须符合初始化的成员,如果初始化 43 | 列表的值不够,剩余的值按照默认值初始化。 44 | 6.在实现结构存储的边界的对齐时,可能会浪费一部分空间。根据边界对齐要求降序排列 45 | 成员可最大限度的减少结构中浪费的空间。 46 | 7.sizeof返回的值包含结构中浪费的空间。 47 | 8.宏offsetof( type, member )表示指定成员开始存储的位置距离结构开始存储位置 48 | 几个字节。 49 | 9.向一个函数传递结构指针效率更高(除了结构特别小的情况下),通常添加一个const 50 | 防止函数修改指针指向的内容。 51 | 10.位段的不同之处: 52 |    位段成员必须声明为int、signed int或者unsigned int类型(显示的声明int到底是 53 |    unsigned还是signed是有好处,因为int类型到底是unsigned还是signed是由编译器决 54 | 定的 55 |    成员名后跟一个:和一个整数,该整数指定该位段占用的位的数目 56 |    位段的可移植性不太好,原因如下: 57 |     int位段被当做unsigned还是signed由编译器决定 58 |     许多编译器把位段长度限制在一个整型长度之内 59 |     位段的成员是从左网右分配还是从右往左分配是由编译器决定的 60 |     当指定了两个位段的时候,第二个位段比较长无法容纳于第一个位段所剩余的位,编译器 61 |     可能把第二个位段放到下一个字,也可能把放到第一个位段之后 62 |    使用位段的好处: 63 |     节省内存空间 64 |     可以方便的访问一个整型值的部分内容 65 |    例子: 66 | struct DISK_REGISTER_FORMAT { 67 | unsigned comand :5; 68 | unsigned serctor :5; 69 | }; 70 | 71 | #define DISK_REGISTER \ 72 | (struct DISK_REGISTER_FORMAT *)0xc0000220 73 | DISK_REGISTER->serctor = .... 74 | 75 | 11.一个联合的素有成员存储在一个内存位置,某一时刻联合中的字段只有一个被使用,联合 76 | 的长度就是最长的成员的长度。在实现变体记录的时候特别有用,可以通过一个枚举类型来标 77 | 明属于哪种变体。联合的初始化必须是第一个成员类型。 78 | 12.现在右一个指针p指向某一结构体,考虑如下的情况: 79 | 1)p做左值时,p表示存储这个结构体的地址的内存位置,p+1不是合法的左值,因为其值并 80 | 不存储于任何可标示的内存位置。 81 | 2)p做右值时,p表示表示这个结构体的地址,p+1不是合法的右值,因为无法分辨内存的下 82 | 一个位置所存储的是这些结构的元素还是其他东西。 83 | 3)*p做右值时,*p表示p所指向的整个结构体, 84 | 4)*p做左值时,*p表示p所指向的整个结构体的内存位置 85 | 5)*p+1和*(p+1)是非法的,前者是因为*p是一个结构体,但是结构体并没有规定加1操作; 86 | 后者p+1是一个标量,不能进行加减操作。 87 | -------------------------------------------------------------------------------- /ch10/p1.c: -------------------------------------------------------------------------------- 1 | struct Phone_Number{ 2 | char quhao[4];//区号 3 | char jiaohuantai[5];//交换台 4 | char zhantaihao[5];//站台号 5 | }; 6 | 7 | struct Date{ 8 | int year; 9 | int month; 10 | int day; 11 | }; 12 | 13 | struct Time{ 14 | int hour; 15 | int minute; 16 | int second; 17 | }; 18 | 19 | struct Message{ 20 | struct Phone_Number phone_number[3]; 21 | struct Date *date; 22 | struct Time *time; 23 | }; 24 | -------------------------------------------------------------------------------- /ch10/p2.c: -------------------------------------------------------------------------------- 1 | struct Full_Sales 2 | {//全额销售 3 | 4 | float sales_tax; 5 | float licensing_fee; 6 | }; 7 | 8 | struct Lease_Sales 9 | {//租赁销售 10 | float down_payment; 11 | float security_deposit; 12 | float monthly_payment; 13 | int lease_term; 14 | }; 15 | 16 | struct Loan_Sales 17 | { 18 | float sales_tax; 19 | float licensing_fee; 20 | float doun_payment; 21 | int loan_duration; 22 | float interest_rate; 23 | float monthly_payment; 24 | char name_of_bank[21]; 25 | }; 26 | struct Sales_Record 27 | { 28 | char customer_name[21]; 29 | char customer_address[41]; 30 | char model[21]; 31 | float suggested_retail_prise; 32 | float actual_selling_price; 33 | enum{ PURE_CASH, CASH_LOAN, LEASE } type; 34 | union 35 | { 36 | struct Full_Sales* f_sales; 37 | struct Lease_Sales* l_sales; 38 | struct Sales_Record* s_sales; 39 | }record; 40 | }; 41 | -------------------------------------------------------------------------------- /ch10/p3.c: -------------------------------------------------------------------------------- 1 | typedef union//使用无符号整数 2 | { 3 | unsigned short addr; 4 | struct { 5 | unsigned opcode:10; 6 | unsigned 7 | unsigned 8 | } sgl_op; 9 | struct { 10 | unsigned 11 | unsigned 12 | unsigned 13 | unsigned 14 | unsigned 15 | } dbl_op; 16 | struct { 17 | unsigned 18 | unsigned 19 | unsigned 20 | unsigned 21 | } reg_src; 22 | struct { 23 | unsigned 24 | unsigned 25 | } branch; 26 | struct { 27 | unsigned 28 | } misc; 29 | } machine_inst; 30 | -------------------------------------------------------------------------------- /ch11/ch11.txt: -------------------------------------------------------------------------------- 1 | 1.使用完malloc、calloc、realloc使用完之后要对得到的结果判断是否为NULL。 2 | 2.当函数的参数中有指针的时候,在函数体中要首先判断函数指针是否为NULL。 3 | 3.动态内存允许程序在运行时为一个已知长度的数组分配连续的内存。 4 | 4.只有使用malloc、calloc、realloc分配内存得到的指针才可以使用free函数释放。 5 | 5.当使用calloc函数时,两个参数分别为元素分配的个数和每个元素的大小,并且把分配 6 | 的内存初始化为0,而malloc函数没有。 7 | 6.使用realloc函数时,可能分配内存的方式是新分配一块更大的内存,将原来内存中的数 8 | 据复制到新内存中。 9 | -------------------------------------------------------------------------------- /ch11/p1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define NUL '\0' 5 | 6 | void *calloc( size_t num_elements, size_t element_size ) 7 | { 8 | char *new_memory; 9 | num_elements *= element_size; 10 | new_memory = malloc( num_elements ); 11 | 12 | if( new_memory != NULL ) 13 | { 14 | char *ptr = new_memory; 15 | while( --num_elements >= 0 ) 16 | *ptr++ = NUL; 17 | } 18 | 19 | return new_memory; 20 | } 21 | -------------------------------------------------------------------------------- /ch11/p2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char const *argv[]) { 5 | int n, count = 0; 6 | int *array, *ptr; 7 | 8 | scanf("%d", &n); 9 | array = malloc( (n+1) * sizeof( int ) ); 10 | if( array == NULL ) 11 | { 12 | printf(" malloc error\n" ); 13 | return ; 14 | } 15 | 16 | ptr = array; 17 | *ptr++ = n; 18 | count++; 19 | 20 | while( scanf("%d", ptr++ ) != EOF) 21 | { 22 | count++; 23 | if( count >= n ) 24 | { 25 | array = realloc( array, (n = 2 * n + 1) ); 26 | if( array == NULL ) 27 | { 28 | printf( " realloc errror \n" ); 29 | return ; 30 | } 31 | else 32 | ptr = array + n / 2; 33 | } 34 | } 35 | int index; 36 | for( index = 0; index < count ;index++ ) 37 | { 38 | printf(" %d \n", array[index]); 39 | } 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /ch11/p3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define NUL '\0' 7 | 8 | char *readstring() 9 | { 10 | int ch; 11 | int buffer_length = 0; 12 | char *buffer = NULL ; 13 | int counter = 0; 14 | char *buffer_ptr = buffer; 15 | 16 | do { 17 | ch = getchar(); 18 | if( ch == EOF || ch == '\n' )//及时有空格也可以继续输入 19 | ch = NUL; 20 | if( counter >= buffer_length ) 21 | { 22 | buffer_length += 256; 23 | buffer = (char *)realloc( buffer, buffer_length ); 24 | assert( buffer != NULL );//代替if( buffer == NULL ){} 25 | buffer_ptr = buffer + counter;//更新buffer_ptr的指针,有可能buffer的地址改变 26 | } 27 | 28 | *buffer_ptr++ = ch; 29 | counter++; 30 | 31 | } while( ch != NUL ); 32 | 33 | buffer_ptr = (char *) malloc( counter * sizeof( char )); 34 | assert( buffer_ptr != NULL ); 35 | strcpy( buffer_ptr, buffer ); 36 | free( buffer ); 37 | return buffer_ptr; 38 | } 39 | int main(int argc, char const *argv[]) { 40 | 41 | char *str = readstring(); 42 | printf("%s\n", str); 43 | free( str ); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /ch12/ch12.txt: -------------------------------------------------------------------------------- 1 | 1.单链表只能以一个方向进行遍历。 2 | 2.插入和删除一个节点时,寻找该节点的前一个节点,插入的函数的参数为指针的指针,并且 3 | 利用next的指针。 4 | 3.插入到链表中需要分两个步骤:首先将新节点的next字段设置为目标节点的后续节点,前一 5 | 个节点的link字段设置为指向这个新节点。 6 | 3.学会在for,while和do中加入赋值操作语句,使语言更简洁 7 | 4.双联表的头节点。可以在遍历的过程中改变方向。 8 | 5.双向链表插入新节点,新节点的向前和向后的节点都被设置,前一个的节点和后一个节点的 9 | next字段都需要被重新设置。 10 | 6.提炼if语句。 11 | -------------------------------------------------------------------------------- /ch12/p1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node 5 | { 6 | int value; 7 | struct Node *next; 8 | }; 9 | 10 | int get_lenth_of_list( struct Node *head ) 11 | { 12 | int counter = 0; 13 | 14 | while( head != NULL ) 15 | { 16 | counter++; 17 | head = head->next; 18 | } 19 | 20 | return counter; 21 | } 22 | 23 | struct Node *build_list( int value ) 24 | { 25 | struct Node *top = (struct Node *)malloc( sizeof( struct Node ) ); 26 | top->value = value; 27 | 28 | if( top != NULL ) 29 | return top; 30 | else 31 | return NULL; 32 | } 33 | 34 | int destroy_list( struct Node * top ) 35 | { 36 | if( top == NULL ) 37 | return -1; 38 | while( top != NULL ) 39 | { 40 | struct Node *node_ptr = top; 41 | top = top->next; 42 | printf("释放%d结点\n", node_ptr->value ); 43 | free( node_ptr ); 44 | } 45 | } 46 | 47 | int insert_node( struct Node **top, int new_value ) 48 | { 49 | while( *top != NULL && (*top)->value < new_value ) 50 | top = &(*top)->next; 51 | struct Node *temp_node = (struct Node *)malloc( sizeof(struct Node ) ); 52 | 53 | if( temp_node == NULL ) 54 | { 55 | printf("malloc error !\n" ); 56 | return -1; 57 | } 58 | 59 | temp_node->value = new_value; 60 | temp_node->next = *top; 61 | *top = temp_node; 62 | return 1; 63 | } 64 | 65 | void print_list( struct Node *top ) 66 | { 67 | while( top != NULL ) 68 | { 69 | printf("%d\n", top->value ); 70 | top = top->next; 71 | } 72 | } 73 | 74 | 75 | int main(int argc, char const *argv[]) { 76 | struct Node *top = build_list(2); 77 | insert_node( &top, 4); 78 | insert_node( &top, 1); 79 | insert_node( &top, 7); 80 | insert_node( &top, 2); 81 | print_list( top ); 82 | printf("%d\t", get_lenth_of_list( top ) ); 83 | destroy_list( top ); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /ch12/p2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node 5 | { 6 | int value; 7 | struct Node *next; 8 | }; 9 | 10 | 11 | 12 | struct Node *build_list( int value ) 13 | { 14 | struct Node *top = (struct Node *)malloc( sizeof( struct Node ) ); 15 | top->value = value; 16 | 17 | if( top != NULL ) 18 | return top; 19 | else 20 | return NULL; 21 | } 22 | 23 | int destroy_list( struct Node * top ) 24 | { 25 | if( top == NULL ) 26 | return -1; 27 | while( top != NULL ) 28 | { 29 | struct Node *node_ptr = top; 30 | top = top->next; 31 | printf("释放%d结点\n", node_ptr->value ); 32 | free( node_ptr ); 33 | } 34 | } 35 | 36 | // int insert_node( struct Node **top, int new_value ) 37 | // { 38 | // while( *top != NULL && (*top)->value < new_value ) 39 | // top = &(*top)->next; 40 | // struct Node *temp_node = (struct Node *)malloc( sizeof(struct Node ) ); 41 | // 42 | // if( temp_node == NULL ) 43 | // { 44 | // printf("malloc error !\n" ); 45 | // return -1; 46 | // } 47 | // 48 | // temp_node->value = new_value; 49 | // temp_node->next = *top; 50 | // *top = temp_node; 51 | // return 1; 52 | // } 53 | 54 | int insert_node( struct Node *top, int new_value ) 55 | { 56 | while( top->next != NULL ) 57 | top = top->next; 58 | 59 | struct Node *new_node = (struct Node *) malloc( sizeof( struct Node ) ); 60 | 61 | if( new_node == NULL ) 62 | { 63 | printf("malloc errror!\n" ); 64 | return -1; 65 | } 66 | 67 | new_node->value = new_value; 68 | new_node->next = NULL; 69 | top->next = new_node; 70 | return 1; 71 | } 72 | 73 | void print_list( struct Node *top ) 74 | { 75 | while( top != NULL ) 76 | { 77 | printf("%d\n", top->value ); 78 | top = top->next; 79 | } 80 | } 81 | 82 | struct Node *find_node( struct Node *top, int value ) 83 | { 84 | while( top != NULL && top->value != value ) 85 | top = top->next; 86 | 87 | return top; 88 | } 89 | 90 | int main(int argc, char const *argv[]) { 91 | struct Node *top = build_list(2); 92 | insert_node( top, 4); 93 | insert_node( top, 7); 94 | insert_node( top, 2); 95 | print_list( top ); 96 | printf("%d\n", find_node( top, 7)->value ); 97 | destroy_list( top ); 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /ch12/p3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // struct DLL_Node; 5 | // struct DLL_Pointers 6 | // { 7 | // struct DLL_Node *fwd; 8 | // struct DLL_Node *bwd; 9 | // }; 10 | // struct DLL_Node 11 | // { 12 | // struct DLL_Pointers *pointers; 13 | // int value; 14 | // }; 15 | // 16 | // struct DLL_Pointers *bulid_list() 17 | // { 18 | // struct DLL_Pointers * Front_Rear = ( struct DLL_Pointers *)malloc( 2 * sizeof( struct DLL_Pointers ) ); 19 | // 20 | // if( Front_Rear == NULL ) 21 | // { 22 | // printf("malloc error !\n" ); 23 | // return NULL; 24 | // } 25 | // 26 | // Front_Rear->fwd = NULL; 27 | // Front_Rear->bwd = NULL; 28 | // 29 | // (Front_Rear+1)->fwd = NULL; 30 | // (Front_Rear+1)->bwd = NULL; 31 | // 32 | // return Front_Rear; 33 | // } 34 | 35 | 36 | int insert_node( struct Node **frontp, struct Node ** rearp, int value ) 37 | { 38 | struct Node **fwdp; 39 | struct Node *next; 40 | struct Node *new_node; 41 | 42 | if( frontp == NULL || rearp == NULL ) 43 | return 0; 44 | fwdp = frontp; 45 | while( (next = *fwdp ) != NULL ) 46 | { 47 | if( next->value == value ) 48 | return 0; 49 | if( next->value > value ) 50 | break; 51 | fwdp = &next->fwd; 52 | } 53 | 54 | new_node = (struct Node *) malloc( sizeof( struct Node ) ); 55 | if( new_node == NULL ) 56 | { 57 | printf("malloc error !\n" ); 58 | return 0; 59 | } 60 | 61 | new_node->value = value; 62 | 63 | new_node->fwd = next; 64 | *fwdp = new_node; 65 | 66 | if( fwdp != frontp ) 67 | if( next != NULL ) 68 | new_node->bwd = next->bwd; 69 | else 70 | new_node->bwd = *rearp; 71 | if( next != NULL ) 72 | next->bwd = new_node; 73 | else 74 | *rearp = new_node; 75 | 76 | return 1; 77 | } 78 | int main(int argc, char const *argv[]) { 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /ch12/p4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node 5 | { 6 | int value; 7 | struct Node *next; 8 | }; 9 | 10 | 11 | struct Node *build_list( int value ) 12 | { 13 | struct Node *top = (struct Node *)malloc( sizeof( struct Node ) ); 14 | top->value = value; 15 | 16 | if( top != NULL ) 17 | return top; 18 | else 19 | return NULL; 20 | } 21 | 22 | int destroy_list( struct Node * top ) 23 | { 24 | if( top == NULL ) 25 | return -1; 26 | while( top != NULL ) 27 | { 28 | struct Node *node_ptr = top; 29 | top = top->next; 30 | printf("释放%d结点\n", node_ptr->value ); 31 | free( node_ptr ); 32 | } 33 | } 34 | 35 | int insert_node( struct Node **top, int new_value ) 36 | { 37 | while( *top != NULL && (*top)->value < new_value ) 38 | top = &(*top)->next; 39 | struct Node *temp_node = (struct Node *)malloc( sizeof(struct Node ) ); 40 | 41 | if( temp_node == NULL ) 42 | { 43 | printf("malloc error !\n" ); 44 | return -1; 45 | } 46 | 47 | temp_node->value = new_value; 48 | temp_node->next = *top; 49 | *top = temp_node; 50 | return 1; 51 | } 52 | 53 | void print_list( struct Node *top ) 54 | { 55 | while( top != NULL ) 56 | { 57 | printf("%d\n", top->value ); 58 | top = top->next; 59 | } 60 | } 61 | 62 | struct Node *revert_list( struct Node *top ) 63 | { 64 | struct Node *last = NULL; 65 | struct Node *current = NULL; 66 | 67 | while( top != NULL ) 68 | { 69 | current = top; 70 | top = top->next; 71 | current->next = last; 72 | last = current; 73 | } 74 | 75 | return last; 76 | /* 77 | struct NODE *previous; 78 | struct NODE *next; 79 | 80 | for( previous = NULL; current != NULL; current = next ){ 81 | next = current–>link; 82 | current–>link = previous; 83 | previous = current; 84 | } 85 | 86 | return previous; 87 | */ 88 | } 89 | int main(int argc, char const *argv[]) { 90 | struct Node *top = build_list(2); 91 | insert_node( &top, 4); 92 | insert_node( &top, 1); 93 | insert_node( &top, 7); 94 | insert_node( &top, 2); 95 | print_list( top ); 96 | print_list( revert_list( top ) ); 97 | destroy_list( top ); 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /ch12/p5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node 5 | { 6 | int value; 7 | struct Node *next; 8 | }; 9 | 10 | 11 | struct Node *build_list( int value ) 12 | { 13 | struct Node *top = (struct Node *)malloc( sizeof( struct Node ) ); 14 | top->value = value; 15 | 16 | if( top != NULL ) 17 | return top; 18 | else 19 | return NULL; 20 | } 21 | 22 | int destroy_list( struct Node * top ) 23 | { 24 | if( top == NULL ) 25 | return -1; 26 | while( top != NULL ) 27 | { 28 | struct Node *node_ptr = top; 29 | top = top->next; 30 | printf("释放%d结点\n", node_ptr->value ); 31 | free( node_ptr ); 32 | } 33 | } 34 | 35 | int insert_node( struct Node **top, int new_value ) 36 | { 37 | while( *top != NULL && (*top)->value < new_value ) 38 | top = &(*top)->next; 39 | struct Node *temp_node = (struct Node *)malloc( sizeof(struct Node ) ); 40 | 41 | if( temp_node == NULL ) 42 | { 43 | printf("malloc error !\n" ); 44 | return -1; 45 | } 46 | 47 | temp_node->value = new_value; 48 | temp_node->next = *top; 49 | *top = temp_node; 50 | return 1; 51 | } 52 | 53 | void print_list( struct Node *top ) 54 | { 55 | while( top != NULL ) 56 | { 57 | printf("%d\n", top->value ); 58 | top = top->next; 59 | } 60 | } 61 | 62 | struct Node *revert_list( struct Node *top ) 63 | { 64 | struct Node *last = NULL; 65 | struct Node *current = NULL; 66 | 67 | while( top != NULL ) 68 | { 69 | current = top; 70 | top = top->next; 71 | current->next = last; 72 | last = current; 73 | } 74 | 75 | return last; 76 | } 77 | 78 | int delete_node( struct Node ** top, struct Node * node ) 79 | { 80 | // struct Node *pre_node = NULL; 81 | // 82 | // while( *top != NULL ) 83 | // { 84 | // if( *top == node ) 85 | // { 86 | // if( pre_node != NULL ) 87 | // { 88 | // pre_node->next = (*top)->next; 89 | // free(*top); 90 | // } 91 | // else 92 | // top = &(*top)->next; 93 | // return 1; 94 | // } 95 | // pre_node = *top; 96 | // top = &(top->next); 97 | // } 98 | 99 | struct Node *current = NULL; 100 | 101 | while( (current = *top) != NULL && current != node ) 102 | top = ¤t->next; 103 | 104 | if( current == node ) 105 | { 106 | *top = current->next; 107 | free( current ); 108 | return 1; 109 | } 110 | else 111 | return 0; 112 | 113 | } 114 | 115 | 116 | int main(int argc, char const *argv[]) { 117 | struct Node *top = build_list(2); 118 | insert_node( &top, 4); 119 | insert_node( &top, 1); 120 | insert_node( &top, 7); 121 | insert_node( &top, 2); 122 | printf("删除之前的链表\n" ); 123 | print_list( top ); 124 | delete_node( &top, top ); 125 | printf("删除之后的链表\n" ); 126 | print_list( top ); 127 | //print_list( revert_list( top ) ); 128 | destroy_list( top ); 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /ch12/p6.c: -------------------------------------------------------------------------------- 1 | int dll_remove( struct Node *rootp, struct Node *node ) 2 | { 3 | struct Node * pre = NULL; 4 | struct Node *this = rootp; 5 | 6 | if( node == NULL || rootp == NULL ) 7 | return 0; 8 | pre = this; 9 | this = this->next; 10 | 11 | while( this != NULL && this != node ) 12 | { 13 | pre = this; 14 | this = this->next; 15 | } 16 | 17 | if( this == NULL ) 18 | return 0; 19 | else 20 | { 21 | if( this->next == NULL ) 22 | rootp->before = pre; 23 | else 24 | this->next->before = pre; 25 | pre->next = this->next; 26 | free( this ); 27 | return 1; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ch12/q1.c: -------------------------------------------------------------------------------- 1 | while( *linkp != NULL && (*linkp)->value < new_value ) 2 | linkp = &(*linkp)->link; 3 | new_node = malloc( sizeof( Node) ); 4 | if( new_node == NULL ) 5 | { 6 | printf("malloc error !"); 7 | return 0; 8 | } 9 | new_node->value = new_value; 10 | new_node->link = *linkp; 11 | *linkp = new_node;//前一个节点的link字段 12 | renturn 1; 13 | -------------------------------------------------------------------------------- /ch12/q4.c: -------------------------------------------------------------------------------- 1 | 1) Node *root; 2 | root = malloc( sizeof( Node ) - sizeof( ValueType ) ); 3 | 4 | 2)struct DLL_Node; 5 | struct DLL_Pointers 6 | { 7 | struct DLL_Node *fwd; 8 | struct DLL_Node *bwd; 9 | }; 10 | struct DLL_Node 11 | { 12 | struct DLL_Pointers *pointers; 13 | int value; 14 | }; 15 | -------------------------------------------------------------------------------- /ch13/ch13.txt: -------------------------------------------------------------------------------- 1 | 1.int f()[]和int f[]() 为非法声明 2 | 2.int *( *f )() 函数指针 3 | 3.int (* f[] ) () 函数指针,它所指向的是函数的返回值是一个整数 4 | int *(* f[] ) () 函数指针,它所指向的是函数的返回值是一个指向整数的指针 5 | 4.函数指针的应用:回调函数和转移表 6 | 7 | 回调函数:讲一个函数指针作为参数传递给一个函数,则这个函数被称为回调函数 8 | 这样可以创建一个通用型函数,通常将这个函数指针的参数类型设置为void,然后在函数中进行强制类型转换。 9 | 回调函数的使用场景:函数需要执行不同类型的工作或者执行只能够由函数调用者执行的工作,可在函数参数 10 | 中传入函数指针作为回调函数 11 | 一般回调函数参数设置为void类型,在回调函数内部使用参数之前,一定要做强制类型转换 12 | 13 | 转换表:一个函数指针类型的数组,通过下标来调用不同的函数(格式:数组名[下标]参数列表),注意检查 14 | 数组操作是否越界,下标是否合法。 15 | 16 | 5.字符串常量是一个常量指针,指向字符串的第一个字符,和数组名一样可以使用指针表达式和下标表达式 17 | 来使用字符串常量。如下: 18 | "xyz" + 1 表示指向y的指针 19 | *"xyz" 表示x 20 | "xyz"[2] 表示z 21 | 6.argv指向一个序列的字符型指针,该序列以一个NULL指针作为结束标志。 22 | 23 | 7.只有在需要的时候才会使用多层间接访问,否则程序将会变得很很慢并且很难于维护 24 | 25 | 6.声明以个函数指针并不意味着马上可以使用,需要将其初始化使其指向某一个指针,在初始化之前需要有 26 | 目标函数的函数原型 27 | 28 | 7.函数指针的声明与使用: 29 | int f ( int ); 30 | int ( *pf )( int ) = &f;//&可以不使用 31 | int ans; 32 | ans = f( 25 ) 33 | ans = (*pf)( 25 ) 34 | ans = pf( 25 ) 35 | 36 | 8.利用字符串的特性提高效率,例如: 37 | putchar("0123456789ABCDEF"[ value % 16 ]); 38 | printf( "%s\n", "**********" + 10 - n ); 39 | -------------------------------------------------------------------------------- /ch13/q1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int unprint( int ch ) 5 | { 6 | return !isprint( ch ); 7 | } 8 | 9 | int (*test[]) ( int ch ) = { 10 | iscntrl, 11 | isspace, 12 | isdigit, 13 | islower, 14 | isupper, 15 | ispunct, 16 | unprint 17 | }; 18 | 19 | #define COUNT ( sizeof( test ) / sizeof( test[ 0 ] ) ) 20 | 21 | char *label[] = { 22 | "contral", 23 | "whitespace", 24 | "digit", 25 | "lower case", 26 | "upper case", 27 | "punction", 28 | "unprint" 29 | }; 30 | 31 | int value[ COUNT ]; 32 | int total; 33 | 34 | 35 | int 36 | main( int argc, char* argv[] ) 37 | { 38 | int ch; 39 | 40 | while( ( ch = getchar() ) != EOF ) 41 | { 42 | total++; 43 | 44 | for( int i = 0; i < COUNT; i++) 45 | if( test[ i ]( ch ) ) 46 | value[ i ]++; 47 | } 48 | 49 | if( total == 0 ) 50 | printf( "no charactor input \n" ); 51 | else 52 | for( int i = 0; i < COUNT; i++ ) 53 | { 54 | printf( " %0.3f %% of tatal charactor is %s\n ", value[ i ]* 100.0 / total, label[ i ] ); } 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /ch13/q1.md: -------------------------------------------------------------------------------- 1 | 1. `int abc()` 返回值为int类型函数 2 | 2. `int abc[3]` int型数组 3 | 3. `int **abc()` 返回值为“int型指针的指针”的函数 4 | 4. `int (*abc)()` 返回值为int型的函数指针 5 | 5. `int (*abc)[6]` 指向“int型数组”的指针 6 | 6. `int *abc()` 返回值为“int型指针”的函数 7 | 7. `int **(*abc[6])()` 指针“返回值为int型指针的指针的函数”的指针的数组 8 | 8. `int **abc[6]` int型指针的指针数组 9 | 9. `int *(*abc())()` 返回值为“返回值为以int型指针的函数指针”的函数 10 | 10. `int (**(*abc)())()` 返回值为“返回值为int的函数指针的指针”的函数指针 11 | 11. `int (*(*abc)())[6]` 返回值为“指向int型数组的指针”的函数指针 12 | 12. `int *(*(*(*abc)())[6])()` 返回值为“指向‘返回值为int型指针的函数指针’的数组的指针”的函数指针 13 | -------------------------------------------------------------------------------- /ch13/q11.md: -------------------------------------------------------------------------------- 1 | 首先,有些编译器把字符串常量存放在无法进行修改的内存区域,如果你试图对这类字符串常量进行修改,就会导致程序终止,其次,即使一个字符串常量在程序中使用的地方不止一处,有些编译器只保存这个字符串常量的一份拷贝。修改其中一个字符串常量将影响程序中这个字符串常量出现的所有地方,这使得调试工作极为困难,例如,如果一开始执行了下面这条语句: 2 | `strcpy("hello\n","Bye\n")` 3 | 然后再执行下面语句: 4 | `printf("hello\n")` 5 | -------------------------------------------------------------------------------- /ch13/q2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void traverse_list( struct node* head, void (*print_node )( struct node* node ) { 5 | 6 | if ( head == NULL ) 7 | printf("头结点为空"); 8 | else 9 | while( head != NULL ) 10 | { 11 | print_node( head ) 12 | head = head->next; 13 | } 14 | 15 | return; 16 | } 17 | int main( int argc, char* argv[] ) 18 | { 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /ch13/q3.c: -------------------------------------------------------------------------------- 1 | //在不同的情况下执行不同的工作,这些代码必须移到函数中,主要的困难在于提出一个共同的原型来适应不同需要的函数,要包括任何一个函数使用的所有参数,新的函数都要使用这个共同的原型,已经存在的函数要转换来匹配新的原型,大多数函数至少有一个它们不需要的参数结尾,current必须通过指针来使函数修改它 2 | void (Node *list, Node **current, Transaction *trans); 3 | void delete_trans(Node *list, Node **current, Transaction *trans); 4 | void search(Node *list, Node **current, Transaction *trans); 5 | void edit(Node *list, Node **current, Transaction *trans); 6 | 7 | void forword(Node *list, Node **current, Transaction *tran) 8 | { 9 | *current = (*current)->next; 10 | 11 | } 12 | 13 | void backword(Node *list, Node **current, Transaction *tran) 14 | { 15 | *current = (*current)->prev; 16 | 17 | } 18 | 19 | void (*function[])(Node *, Node **, Transaction *) = { 20 | add_new_trans, 21 | delete_trans, 22 | forword, 23 | backword, 24 | search, 25 | edit 26 | 27 | }; 28 | 29 | #define COUNT (sizeof(function) / sizeof(function[0])); 30 | 31 | if(transaction->type >= NEW && transaction <= EDIT) 32 | function[transaction->type](list, ¤t, transaction); 33 | else 34 | printf("Illegal transaction type!\n"); 35 | -------------------------------------------------------------------------------- /ch13/q4.c: -------------------------------------------------------------------------------- 1 | void swap( char* i, char* j, int resize ) 2 | { 3 | char ch; 4 | while( resize-- > 0 ) 5 | { 6 | ch = *i; 7 | *i++ = *j; 8 | *j++ = ch; 9 | } 10 | } 11 | 12 | void sort( char* base, int len, int resize, int (*comp)( char* , char* ) ) 13 | { 14 | //最后一个元素的内存地址 15 | char* last = base+(len-1)*resize; 16 | //注意比较的极限值 17 | for ( char* index1 = 0; index1 < last; index1 += resize ) 18 | for ( char* index2 = index1; index2 <= last; index2 += resize ) 19 | if( comp( index1, index2 ) > 0 ) 20 | swap( index1, index2, resize ); 21 | 22 | return; 23 | } 24 | -------------------------------------------------------------------------------- /ch13/q5.c: -------------------------------------------------------------------------------- 1 | #define TRUE 1 2 | #define FALSE 0 3 | //C语言中'\0'与NULL没有区别 4 | #define NUL '\0' 5 | 6 | enum{ NONE, FLAG, ARG }; 7 | 8 | //判断参数是一个标志还是一个值 9 | int argtype( int ch, char* control ) 10 | { 11 | while ( control != NUL ) 12 | { 13 | if( ch == *control++ ) 14 | return *control == '+'? ARG : FLAG; 15 | } 16 | 17 | return NONE; 18 | } 19 | 20 | //处理参数 21 | char * 22 | do_args( int argc, char *argv[], char* control, void (*do_arg)( int ch, char* value ), void (*illegal_arg)( int ch ) ) 23 | { 24 | char *argvp = NUL; 25 | int skip_arg;//加一个标记变量 26 | int ch; 27 | 28 | while ( ( argvp = *argv ) != NUL && *argvp == '-' ) 29 | { 30 | skip_arg = FALSE; 31 | while ( !skip_arg && ( ch = *++argvp ) != NUL ){ 32 | switch ( argtype( *++argvp, control ) ) 33 | { 34 | case FLAG: 35 | do_arg( ch, control ); 36 | break; 37 | case ARG: 38 | if( *++argvp != NUL || ( argvp = *++argv ) != NUL ) 39 | { 40 | ( *do_arg )( ch, argvp ); 41 | skip_arg = TRUE; 42 | break; 43 | } 44 | ( *illegal_arg )( ch ); 45 | return argv; 46 | 47 | case NONE: 48 | illegal_arg( ch ); 49 | break; 50 | } 51 | } 52 | 53 | } 54 | return argv; 55 | } 56 | -------------------------------------------------------------------------------- /ch13/q7.md: -------------------------------------------------------------------------------- 1 | 优点:处理参数更加容易 2 | 缺点:不属于标准规范,不具有可移植性 3 | 4 | -------------------------------------------------------------------------------- /ch13/q9.md: -------------------------------------------------------------------------------- 1 | 这个数组的大小只能容纳初始值,所以在后面添加任何东西都会使数组内存溢出,可能会覆盖其他变量,这个解决办法要使数组足够大可以包含最长的文件名,一个可能存在问题的地方是strcat,如果这个文件名前缀允许使用若干不同的文件名,在后面连接一个字符串可能不会产生预期的效果 2 | -------------------------------------------------------------------------------- /ch14/ch14.txt: -------------------------------------------------------------------------------- 1 | 1.预处理阶段进行的工作:删除注释、插入被#include指令包含的文件的内容、定义和替换由#define指定 2 | 定义的符号以及确定代码的部分内容是否应该根据一些条件编译指令进行编译 3 | 2.利用相邻的字符串可以被自动连接这个特性编写以下宏定义: 4 | #define DEBUGP_PRINT printf( "File %s line %d:" \ 5 | " x=%d, y=%d, z=%d", \ 6 | __FILE__, __LINE__, \ 7 | x, y, z ); 8 | 3.#define name( parameter-list ) stuff 其中参数列表的左括号必须与name紧邻,否则当做stuff的一部分 9 | 4.所有用于对数值表达式进行求值的宏定义都应该加上多层的括号(以每一个变量为单位增加括号)避免在使用宏时 10 | 由于参数中的操作符或者邻近的操作符之间不可预料的相互作用 11 | 5.在程序中扩展#define定义符号和宏时的步骤: 12 | 1.在调用宏时,首先对参数进行检查,看看是否包含了任何由#define定义的符号。如果是,他们首先被替换 13 | 2.替换文本随后被插入到原来文本的位置,对于宏,参数名被值所替代 14 | 3.最后在对结果文本进行扫描,看看它是否包含任何由#define定义的符号。如果是,重新处理上述过程 15 | 6.将宏参数插入到字符串常量中的两个方法: 16 | 1.利用相邻的字符串可以被自动连接这个特性,例如: 17 | #define PRINT( FORMAT, VALUE ) \ 18 | printf( "The value is " FORMAT "\n", VALUE ) 19 | PRINT( "%d", x + 3 ); 20 | 这种技巧之后当字符串常量作为宏参数给出时才能使用 21 | 2.使用#将一个宏参数转化为一个字符串,例如: 22 | #define PRINT( FORMAT, VALUE ) \ 23 | printf( "The value of " #VALUE \ 24 | " is " FORMAT "\n", VALUE ) 25 | PRINT( "%d", x + 3 ); 26 | 还有##将两边的符号连接成一个符号,但是要保证连接之后的变量是合法的 27 | #和##可以组织宏的递归展开 28 | 7.宏与参数 29 | 宏适合那种执行具体功能的代码数量比较少的场景,因为如果使用函数的话,有可能函数的调用和返回的开销比执行这段功能的开销更大一些;还有一个原因就是函数的参数必须为声明为一个特定的类型,必须适用于特定的类型,也就是说宏与类型无关。例如: 30 | #define MALLOC( n, type ) \ 31 | ( (type *)malloc( (n) * sizeof( type ) ) ) 32 | 8.注意:宏一般都没有分号结尾,分号一般出现在调用宏的语句中 33 | 9.#undef 34 | 10.编译器中命令行中的-U和-D参数,通过在命令行中通过-D对不同的情况下的不同宏进行赋值,可以使用-U忽略使宏定义中设置的值 35 | 11.条件编译:选择一部分代码被使用另一部分代码被忽略,以便选择不同的代码部分 36 | #if constant-experssion 37 | statements 38 | #elif constant-experssion 39 | other statements 40 | #else 41 | other statements 42 | #enfif 43 | 44 | 12.测试是否被定义 45 | #if defined( symbol ) 46 | #ifdef symbol 47 | 48 | #if !defined(symbol) 49 | #ifudef symbol 50 | 13.嵌套指令 51 | #ifdef defined( OS_UNIX ) 52 | #ifdef OPTION1 53 | unix_version_of_option1(); 54 | #endif 55 | #ifdef OPTION2 56 | unix_version_of_option2(); 57 | #endif 58 | #elif denfied( OS_MSDOSC ) 59 | #ifdef OPTION2 60 | msdos_version_of_option2(); 61 | #endif 62 | #endif /*添加defined相关的注释*/ 63 | 14.文件包含 64 | 预处理器删除#include命令,用被包含的头文件替换;如果一个头文件被包含10次,那么它将被编译10次 65 | 使用#include命令会带来一定的开销,但是,这种开销不是很高,而且是编译时的开销,对运行没有影响。 66 | 15.为了避免文件的相互之间重复包含,可以使用如下模式的条件编译: 67 | #ifndef _XXXXXX_H_ 68 | #define _XXXXXX_H_ / #define _XXXXXX_H_ 1 69 | 70 | #endif 71 | 16.为了防止出现表达式中可能与宏有关的错误,应该在宏完整定义的两边加上括号,同样在宏的每个参数两边也需要加上括号 72 | 73 | -------------------------------------------------------------------------------- /ch14/p1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void print_ledger_long( int arg ) 4 | { 5 | printf("print_ledger_long"); 6 | } 7 | 8 | 9 | void print_ledger_detailed( int arg ) 10 | { 11 | printf("print_ledger_detailed"); 12 | } 13 | 14 | void print_ledger_default( int arg ) 15 | { 16 | printf("print_ledger_default"); 17 | } 18 | 19 | void print_ledger( int arg ) 20 | { 21 | #if defined OPTION_LONG 22 | print_ledger_long( arg ); 23 | #elif defined OPTION_DETAILED 24 | print_ledger_detailed( arg ); 25 | #else 26 | print_ledger_default( arg ); 27 | #endif 28 | } 29 | int main( int argc, char* argv[] ) 30 | { 31 | print_ledger( 5 ); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /ch14/q1.md: -------------------------------------------------------------------------------- 1 | 在打印错误信息的时候,文件名和行号很有用,尤其是在调试编译阶段,assert是使用这些来实现的 2 | __DATE__和__TIME__可以把版本信息编译到程序中 3 | __STDC__可以用于在多种类型的编译器中进行编译的条件选择 4 | 5 | 6 | -------------------------------------------------------------------------------- /ch14/q2.md: -------------------------------------------------------------------------------- 1 | 1.增加代码的可读性 2 | 2.改变字面值更容易一些 3 | -------------------------------------------------------------------------------- /ch14/q3.md: -------------------------------------------------------------------------------- 1 | #define DEBUG_PRINT( fmt, expr ) \ 2 | printf( "File %s, line %d : %s = " \ 3 | fmt "\n", \ 4 | __FILE__, __LINE__, \ 5 | #expr, expr ); 6 | -------------------------------------------------------------------------------- /ch14/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //#的作用 4 | #define PRINT(FORMAT, VLALUE) \ 5 | printf( "The value is " FORMAT "\n", VLALUE ) 6 | //##的作用 7 | #define ADD_TO_SUM( sum_number, value ) \ 8 | sum ## sum_number += value 9 | //宏参数的副作用,多次执行同一个命令 10 | #define MAX( a, b ) ( (a) > (b) ? (a) : (b) ) 11 | 12 | 13 | int main( int argc, char *argv[] ) 14 | { 15 | int a = 3; 16 | PRINT( "%d", a + 3 ); 17 | int sum5 = 5; 18 | ADD_TO_SUM( 5, 25 ); 19 | printf( "sum5 = %d\n", sum5 ); 20 | 21 | int x = 5; 22 | int y = 8; 23 | int z = MAX( x++, y++ ); 24 | printf( " x = %d, y = %d, z = %d\n", x, y, z ); 25 | 26 | //测试字符串连接 27 | printf("test1" 28 | "test2\n"); 29 | printf("test3 \ 30 | test4\n"); 31 | 32 | printf("__FILE__ : %s\n", __FILE__ ); 33 | printf("__DATE__ : %s\n", __DATE__ ); 34 | printf("__LINE__ : %d\n", __LINE__ ); 35 | printf("__TIME__ : %s\n", __TIME__ ); 36 | printf("__STDC__ : %d\n", __STDC__ ); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /ch14/宏和函数的不同之处.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch14/宏和函数的不同之处.png -------------------------------------------------------------------------------- /ch14/预定义符号.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch14/预定义符号.png -------------------------------------------------------------------------------- /ch2/ch2.txt: -------------------------------------------------------------------------------- 1 | 1.编译和链接 2 | (1)编译并链接一个C语言的程序时,使用gcc加C语言文件名即可,中间会产生.o的目标文件, 3 | 当链接完成之后就会被删除。 4 | (2)编译并链接几个C语言程序时:使用gcc加几个C语言文件名即可,中间用空格分隔,此时不 5 | 会删除产生的目标文件,这样就可以允许在对某些程序修改之后,只对其中的修改后的程序进行编 6 | 译。 7 | (3)编译一个C语言程序,并把他和目标文件进行链接时,使用gccC语言文件名和目标文件名。 8 | (4)编译一个C语言程序,并产生一个目标文件时,使用gcc -c加C语言文件名 9 | (5)编译几个C语言程序,并分别为每个文件产生一个目标文件时,使用gcc -c加几个C语言文件 10 | 名。 11 | (6)链接几个目标文件,使用gcc加几个目标文件 12 | 2.代替使用注释的方法 13 | #if 0 14 | statement 15 | #endif 16 | 3.三字母词 17 | 三字母词就是用几个字符序列合起来表示李另一个字符 18 | ??( [ ??< ( ??= # 19 | ??) ] ??> ) ??/ \ 20 | ??! | ??' ^ ??- ~ 21 | 4.\r与\n的区别 22 | \r : return 到当前行的最左边。 23 | \n: newline 向下移动一行,并不移动左右。 24 | Linux中\n表示回车+换行; 25 | Windows中\r\n表示回车+换行。 26 | Mac中\r表示回车+换行。 27 | 历史: 28 | 回车和换行这两个概念的来历和区别。在计算机还没有出现之前,有一种叫做电传打字机的玩意, 29 | 每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可 30 | 以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失于是,研制人员 31 | 想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车(return)”, 32 | 告诉打字机把打印头定位在左边界;另一个叫做“换行(newline)”,告诉打字机把纸向下移一行。 33 | 这就是“换行”和“回车”的来历,从它们的英语名字上也可以看出一二。 34 | 5.C\C++的转义字符 35 | 所有的ASCII码都可以用“\”加数字(一般是8进制数字)来表示。而C中定义了一些字母前加"\" 36 | 来表示常见的那些不能显示的ASCII字符,如\0,\t,\n等,就称为转义字符,因为后面的字符, 37 | 都不是它本来的ASCII字符意思了。 38 | 转义字符 意义 ASCII码值(十进制) 39 | \a 响铃(BEL) 007 40 | \b 退格(BS) 008 41 | \f 换页(FF) 012 42 | \n 换行(LF) 010 43 | \r 回车(CR) 013 44 | \t 水平制表(HT) 009 45 | \v 垂直制表(VT) 011 46 | \\ 反斜杠 092 47 | \? 问号字符 063 48 | \' 单引号字符 039 49 | \" 双引号字符 034 50 | \0 空字符(NULL) 000 51 | \ddd 任意字符 三位八进制 52 | \xhh 任意字符 二位十六进制 53 | 注: 54 | 1.\v垂直制表和\f换页符对屏幕没有任何影响,但会影响打印机执行响应操作。 55 | 2.\n其实应该叫回车换行。换行只是换一行,不改变光标的横坐标;回车只是回到行首,不改变光标的纵坐标。 56 | 3.\t 光标向前移动四格或八格,可以在编译器里设置 57 | 4.\' 在字符里(即单引号里)使用。在字符串里(即双引号里)不需要,只要用 ' 即可。 58 | 5.\? 其实不必要。只要用 ? 就可以了(在windows VC6 和tc2 中验证)。 59 | 6.为了防止编译链接时产生多重重定义的错误,可以在每个文件的函数定义的前后加入如下的代码: 60 | #ifndef XXXX 61 | #define XXXX 62 | 函数定义 63 | #endif 64 | -------------------------------------------------------------------------------- /ch2/p1/increment.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | *increment函数接受一个整型参数,返回该参数值加1 5 | * */ 6 | 7 | int increment( int num) 8 | { 9 | return num+1; 10 | } 11 | -------------------------------------------------------------------------------- /ch2/p1/increment.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | *increment函数接受一个整型参数,返回该参数值加1 5 | * */ 6 | 7 | int increment( int num) 8 | { 9 | return num+1; 10 | } 11 | -------------------------------------------------------------------------------- /ch2/p1/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch2/p1/main -------------------------------------------------------------------------------- /ch2/p1/main.c: -------------------------------------------------------------------------------- 1 | #include"negate.h" 2 | #include"increment.h" 3 | 4 | int main() 5 | { 6 | printf("incremnet函数的参数为10时的结果:%d\n", increment( 10 ) ); 7 | printf("incremnet函数的参数为0时的结果:%d\n", increment( 0 ) ); 8 | printf("incremnet函数的参数为-10时的结果:%d\n", increment( -10 ) ); 9 | printf("negate函数的参数为10时的结果:%d\n", negate( 10 ) ); 10 | printf("negate函数的参数为0时的结果:%d\n", negate( 0 ) ); 11 | printf("negate函数的参数为-10时的结果:%d\n", negate( -10 )); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /ch2/p1/negate.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | *negat函数接受一个整型参数,返回它的相反数 5 | * */ 6 | 7 | int negate( int num) 8 | { 9 | return -num; 10 | } 11 | -------------------------------------------------------------------------------- /ch2/p2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch2/p2 -------------------------------------------------------------------------------- /ch2/p2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | stack s; 11 | FILE *file = NULL; 12 | int ch = 0; 13 | 14 | if(!(file = fopen("q3.c", "r"))) 15 | { 16 | cout<<"打开文件失败!!!"< 3 | int main() 4 | { 5 | printf("\"Blunder\?\?!??\"");//使用gcc q3.c编译 6 | printf("\"Blunder??!??\"");//使用gcc -trigraphs q3.c编译 7 | 8 | } 9 | -------------------------------------------------------------------------------- /ch2/q4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch2/q4 -------------------------------------------------------------------------------- /ch2/q4.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main() 3 | { 4 | printf("\40"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /ch3/ch3.txt: -------------------------------------------------------------------------------- 1 | 1.基本数据类型:整型,浮点型,指针和聚合类型(如数组和结构体) 2 | 2.整型分为:字符型,短整型,整型和长整型,他们都分为有符号和无符号两种。 3 | 3.对于char类型,本质上是小整型值。char的默认类型就取决于编译器,为了提 4 | 高程序的可移植性和效率,通常把存储与char类型的值限制在signed char和 5 | unsigned char的交集内。 6 | 4.可以通过查看limits.h文件来查看各个变量的范围 7 | 5.初始化整型常量的时候,可以在数值后面添加后缀来改变缺省的规则,例如:u和L等 8 | 如果一个多字节常量前面出现‘L’则表示一个宽字节常量,例如:L‘X’ 9 | 6.如果一个常量用于确定一个字中的某些特定位的时候,将其写成16进制;如果一个常 10 | 量用于表示一个字符的时候,将这个值表示为字符常量更合适。 11 | 7.枚举类型实际上就是整型,其中每个符号常量可以被赋值。 12 | 8.浮点数在缺省情况下都是double类型,可以在数值的后面跟一个L(表示long 13 | double类型)或者一个f(表示float类型);在声明的时候除了long double 14 | 之外,其余的说明符(short, signed,unsigned)都不可用。 15 | 9.在ANSI C中对字符串常量的修改,其效果是未定义的。 16 | 10.相等的整型声明 17 | 11.如果数组的下标是由那些已知的正确的值计算出来的,则不用进行下标检查,如果是 18 | 从用户输入的数据产生的则需要检查下标是否越界。 19 | 12.使用typedef来创建新类型的名字而不是使用#define,因为后者无法处理指针类型,例如: 20 | #define d_ptr_to_char char* 21 | d_ptr_to_char a,b //其中a为指针类型,b为字符类型 22 | 还可以像如下方式使用: 23 | typedef __int8 int8_t; 24 | typedef unsigned __int8 uint8_t; 25 | 13.指向整型常量的指针:int const *p 26 | 指向整型的常量指针:int *const p 27 | 指向整型常量的常量指针:int const * const p 28 | 14.作用域: 29 | 代码块作用域:在代码块(位于一段花括号之间的所有语句)开始位置声明的标识符 30 | 注意:如果内层代码块有与外层代码快名字相同的表示符,则外层的那个标识符则在 31 | 内层无法访问。 32 | 文件作用域:在代码块之外声明的标识符都具有文件作用域,包括函数名。 33 | 原型作用域:在函数原型中声明的标识符具有原型作用域。 34 | 函数作用域: 35 | 15.链接属性----决定在如何处理不同的文件中出现的相同标识符 36 | 外部属性(external):具有external属性的标识符无论声明了多少次,在不同的源文件 37 | 中表示不同的实体。只要变量不是声明在代码块内部或者函数定义内部(属于文件作用域), 38 | 其在缺省情况下的链接属性就是external;如果声明在代码块内部并且在其前面添加extern 39 | 关键字将使它引用全局变量而非局部变量。同时,就有external链接属性的实体总是有静态存 40 | 储类型。 41 | 内部属性(internal):具有internal属性的标识符在同一个文件中的所有声明指向同一个 42 | 实体,但是位于不同的原文中的不同声明指向不同的实体。 43 | 无属性(none):没有链接属性的标识符每次声明都表示不同的实体。 44 | 16.存储类型----决定变量何时创建,何时销毁和它保存多久,变量的缺省类型取决于声明的位置 45 | 静态(static)变量:在任何代码块之外声明的变量为静态变量,总是存储在静态内存中, 46 | 这样的变量在程序运行之前就创建,在整个程序运行期间都存在,直到程序结束。 47 | 自动(auto)变量:在代码块内部声明的变量为自动变量,存储在堆栈中,在执行到代码块中 48 | 声明变量的时候创建,在代码块执行完毕之后被销毁。 49 | 注意:如果给自动变量前面加上static关键字,则该变量从自动变成静态的。 50 | 寄存器(register)变量:使用关键字register声明的自动变量,创建时间和销毁时间与自 51 | 动变量相同,但是使用寄存器变量的函数在返回之前,原来存储在寄存器中的值必须要恢复,确 52 | 保调用者的寄存器变量未被破坏。 53 | 17.自动变量和静态变量的初始化 54 | 静态变量:在程序加载到内存中之前,将静态变量的值放到程序执行时使用的变量的内存位置,完 55 | 成这个任务并不需要额外的时间和指令,如果静态变量没有初始值,则其缺省值为0. 56 | 自动变量:需要更多的开销。初始化语句相当与一条赋值语句。 57 | (1)初始化语句相当于赋值语句效率并没有提高 58 | (2)初始化语句可以重复执行 59 | (3)可以使用表达式值作为初始化值 60 | (4)除非对自动变量进行显示初始化,否则其值将是垃圾值。 61 | 18.static关键字总结 62 | (1)当其用于函数定义和代码块外部的变量声明时,static关键字修改其链接属性,从external 63 | 变成internal,变量的存储类型和作用域不改变,这样使函数名和变量名只能在该文件中使用。 64 | (2)当其用于代码块内部的变量的声明时,将自动变量改为静态变量,但是变量的链接属性和作用域 65 | 不变。 66 | -------------------------------------------------------------------------------- /ch3/q23.c: -------------------------------------------------------------------------------- 1 | #include 2 | static char b = 2; 3 | void y( void ) 4 | { 5 | } 6 | int a = 1; 7 | void x( void ) 8 | { 9 | int c = 3; 10 | static float d = 4; 11 | } 12 | int main(int argc, char *argv[]) 13 | { 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch4/ch4.txt: -------------------------------------------------------------------------------- 1 | 1.C不具有布尔类型,测试值都是用整型表达式来代替。零为假,非零为真。 2 | 2.break语句用于永久终止循环,continue语句用于终止当前的那次循环。 3 | 当continue语句和break语句出现在嵌套循环的内部的时候,只对最内层 4 | 的循环有用,无法影响外层的循环。 5 | 3.如果执行continue语句,则循环中的剩余部分不执行,开始下一轮循环。 6 | while( (ch = getchar()) != EOF) while( (ch = getchar()) != EOF ) 7 | { { 8 | if(ch < '0' || ch > '9') if( ch < '0' || ch > '9') 9 | continue; { 10 | { statement 11 | statement } 12 | } } 13 | } 14 | 15 | 以上两种方式等价 16 | 4.while( scanf("%f", &value ) == 1) while( scanf("%f", &value) == 1 && value >= 0) 17 | { { } 18 | if( value < 0) break; 19 | } 20 | 以上两种方式等价 21 | 5.while语句执行过程,如图。 22 | 6.for语句执行过程,如图。 23 | 7.do语句执行过程,如图。 24 | 8.switch语句执行时贯穿所有case标签,要想避免这种行为,必须在每个case 25 | 语句面添加一条break语句,default子句用于捕捉表达式的值与所有case标签 26 | 的值不匹配的情况。 27 | 巧用switch语句的情况:考虑一个程序,它计算程序的输入中字符,单词和行的 28 | 个数。每个字符必须计算,但空格和制表符同时也作为单词的终止符使用,所有在 29 | 数到他们的时候,字符计数器和单词计数器都必须加1,另外还有换行符,这是行 30 | 的终止符,同时,也是单词的终止符,当出现换行符的时候,三个计数器的值必须 31 | 都加1。 32 | switch( ch ) 33 | { 34 | case '\n': line++; 35 | case ' ': 36 | case '\t': words++; 37 | default: chars++; 38 | } 39 | 注意:以上switch中没有break语句。 40 | 9.goto语句通常用于跳出多层循环。这种情况下,代替沟通语句的有两种方式, 41 | 第一种方式实在每一层的while语句中添加一个用于检测状态标志的表达式,在 42 | 最内层循环中适当的改变该状态标志,另一种方式通过在将这个多层循环放到一 43 | 个函数中,在最内层循环中使用return语句。 44 | 10.空语句只包含一个;,本身并不执行任何任务。 45 | -------------------------------------------------------------------------------- /ch4/do语句执行过程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch4/do语句执行过程.png -------------------------------------------------------------------------------- /ch4/for语句执行过程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch4/for语句执行过程.png -------------------------------------------------------------------------------- /ch4/p1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define MIN_DIFFER 0.0000000005 5 | 6 | double getSqrt( int n ) 7 | { 8 | double pre_a = 1.00f; 9 | double cur_a = 1.00f; 10 | 11 | do { 12 | pre_a = cur_a; 13 | cur_a = ( n / pre_a + pre_a ) / 2; 14 | // printf("cur_a:%lf\n", cur_a ); 15 | // printf("pre_a:%lf\n", pre_a ); 16 | // printf("abs:%lf\n", fabs( pre_a - cur_a ) ); 17 | } while( fabs( pre_a - cur_a ) >= MIN_DIFFER ); 18 | 19 | return cur_a; 20 | } 21 | int main(int argc, char const *argv[]) { 22 | printf("%lf\n", getSqrt( 4 ) ); 23 | return 0; 24 | } 25 | 26 | /* 27 | 总结: 28 | 求绝对值时,要引入math.h头文件 29 | 针对整型:abs() 30 | 针对浮点型:fabs() 31 | */ 32 | -------------------------------------------------------------------------------- /ch4/p2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | /* 4 | 该方法对1和2两个数数不适用 5 | */ 6 | int isPrime( int n ) 7 | { 8 | int time = (int)(sqrt(n)+1); 9 | int index = 3;//从奇数开始计算,每次都加2 10 | 11 | for(; index < time; index = index + 2 ) 12 | { 13 | if (n % index == 0) { 14 | return 0; 15 | } 16 | } 17 | 18 | return 1; 19 | } 20 | int main(int argc, char const *argv[]) { 21 | int i = 3; 22 | int num = 2; 23 | 24 | printf("2\t"); 25 | 26 | while (i < 101) { 27 | 28 | if( isPrime(i) ) 29 | if( num % 5 != 0 ) 30 | { 31 | printf("%d\t", i); 32 | num++; 33 | }else 34 | { 35 | printf("%d\n", i); 36 | num++; 37 | } 38 | i = i + 2; 39 | } 40 | return 0; 41 | } 42 | /* 43 | 使用的编译命令: 44 | gcc p2.c -lm 45 | */ 46 | -------------------------------------------------------------------------------- /ch4/p3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | 判断输入的三条边能否组成三角形 6 | 1.先给三个边从小到大排序 7 | 2.判断是否有边小于0或者两个小边小于最大边 8 | */ 9 | double* sort( double a, double b, double c) 10 | { 11 | int temp; 12 | double *sideFromMaxToMin = (double *) malloc( sizeof( double ) * 3 ); 13 | /* 14 | 排序,使a最大c最小 15 | */ 16 | if( a < b ) 17 | { 18 | temp = a; 19 | a = b; 20 | b = temp; 21 | } 22 | if ( a < c ) { 23 | temp = a; 24 | a = c; 25 | c = temp; 26 | } 27 | if ( b < c ) { 28 | temp = b; 29 | b = c; 30 | c = temp; 31 | } 32 | 33 | printf("%lf %lf %lf\n", a, b, c); 34 | sideFromMaxToMin[0] = a; 35 | sideFromMaxToMin[1] = b; 36 | sideFromMaxToMin[2] = c; 37 | 38 | return sideFromMaxToMin; 39 | } 40 | 41 | int isTriangle( double *side ) 42 | { 43 | double a = side[0]; 44 | double b = side[1]; 45 | double c = side[2]; 46 | /* 47 | 最小的小于0或者最小的两个边小于第三个边则不能组成三角形 48 | */ 49 | if ( c <= 0 || b + c <= a ) { 50 | return 0; 51 | } 52 | 53 | return 1; 54 | } 55 | 56 | int getKindOfTriangle( double *side ) 57 | { 58 | if( side[0] == side[1] && side[1] == side[2] ) 59 | { 60 | return 1;//等边三角形 61 | } 62 | else if( side[0] == side[1] || side[1] == side[2] ) 63 | { 64 | return 2;//等腰三角形 65 | } 66 | else 67 | { 68 | return 3;//斜三角形 69 | } 70 | } 71 | 72 | int main(int argc, char const *argv[]) { 73 | 74 | 75 | double *side = sort( 5, 5, 5); 76 | if ( isTriangle( side ) ) { 77 | switch ( getKindOfTriangle( side ) ) { 78 | case 1: 79 | printf( "等边三角形\n" ); 80 | break; 81 | case 2: 82 | printf( "等腰三角形\n" ); 83 | break; 84 | case 3: 85 | printf( "普通三角形\n" ); 86 | break; 87 | } 88 | } 89 | else 90 | { 91 | printf( "不能组成三角形\n" ); 92 | } 93 | free( side ); 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /ch4/p4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define NUL '\0' 5 | 6 | 7 | 8 | void copy_n( char dst[], char src[], int n ) 9 | { 10 | int index = 0; 11 | 12 | while ( index < n && src[index] != NUL ) 13 | { 14 | dst[index] = src[index]; 15 | index++; 16 | } 17 | 18 | while ( index < n ) 19 | { 20 | dst[index] = NUL; 21 | index++; 22 | } 23 | 24 | dst[index] = NUL; 25 | } 26 | int main(int argc, char const *argv[]) { 27 | char str[] = "asfsdsdfdsfsdf sdf"; 28 | char dst[30]; 29 | printf("%ld\n", strlen(str) ); 30 | copy_n( dst, str, 10 ); 31 | printf("%s\n", dst ); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /ch4/p5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define BUFFER_MAX 129 6 | #define TRUE 1 7 | #define FALSE 0 8 | 9 | int main(int argc, char const *argv[]) { 10 | FILE *file; 11 | char pre_Buffer[BUFFER_MAX]; 12 | char cur_Buffer[BUFFER_MAX]; 13 | int flag = FALSE; 14 | 15 | if ((file = fopen("test.txt", "r")) == NULL) 16 | { 17 | printf( "打开文件失败!!\n" ); 18 | exit(1); 19 | } 20 | 21 | if( fgets( pre_Buffer, BUFFER_MAX, file) ) 22 | { 23 | while ( fgets( cur_Buffer, BUFFER_MAX , file ) ) 24 | { 25 | if (strcmp(cur_Buffer, pre_Buffer) != 0) 26 | { 27 | strcpy(pre_Buffer, cur_Buffer); 28 | // printf("%s\n", pre_Buffer ); 29 | flag = FALSE; 30 | } 31 | else 32 | { 33 | if (flag == FALSE) 34 | { 35 | printf("%s\n", cur_Buffer); 36 | flag = TRUE; 37 | } 38 | } 39 | } 40 | } 41 | 42 | fclose( file ); 43 | return 0; 44 | } 45 | 46 | // optimization 47 | void func() 48 | { 49 | FILE *file; 50 | char pre_Buffer[BUFFER_MAX]; 51 | char cur_Buffer[BUFFER_MAX]; 52 | int flag = FALSE; 53 | 54 | if ((file = fopen("test.txt", "r")) == NULL) 55 | { 56 | printf("打开文件失败!!\n"); 57 | exit(1); 58 | } 59 | 60 | if (fgets(pre_Buffer, BUFFER_MAX, file)) 61 | { 62 | while (fgets(cur_Buffer, BUFFER_MAX, file)) 63 | { 64 | if (strcmp(cur_Buffer, pre_Buffer) == 0) 65 | { 66 | if (flag == FALSE) 67 | { 68 | printf("%s\n", cur_Buffer); 69 | flag = TRUE; 70 | } 71 | } 72 | else 73 | { 74 | strcpy(pre_Buffer, cur_Buffer); 75 | flag = FALSE; 76 | } 77 | } 78 | } 79 | } 80 | 81 | -------------------------------------------------------------------------------- /ch4/p7.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define CHAR_MAX 1000 6 | #define NUL '\0' 7 | 8 | int isWhite( char ch ) 9 | { 10 | return ch == ' '|| ch == '\r' || ch == '\n' || ch == '\f' || ch == '\t' || ch == '\v'; 11 | } 12 | 13 | void debank( char string[] ) 14 | { 15 | char *src; 16 | char *des; 17 | int ch; 18 | 19 | src = string; 20 | des = string++; 21 | 22 | while ( ( ch = *src++) != NUL ) { 23 | if ( isWhite(ch) ) { 24 | if (src == string || !isWhite( des[-1] )) { 25 | *des++ = ' '; 26 | } 27 | } 28 | else 29 | { 30 | *des++ = ch; 31 | } 32 | } 33 | *des = NUL; 34 | } 35 | 36 | int main(int argc, char const *argv[]) { 37 | char str[60] = "sdf dsf df gdf fsdfsf"; 38 | debank( str ); 39 | printf("%s\n", str ); 40 | return 0; 41 | } 42 | /* 43 | 对于一个指针可以使用[]访问一个数组中的一个元素,也可以使用指针加偏移量访问整个数组。 44 | */ 45 | -------------------------------------------------------------------------------- /ch4/q10.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main( int argc, char *args[]) 3 | { 4 | int line_number = 0; 5 | printf("请输入行数:"); 6 | scanf("%d", &line_number ); 7 | 8 | int index = 0; 9 | for( ; index < line_number; index++ ) 10 | { 11 | printf("%d.\n", index+1 ); 12 | } 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch4/q11.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, char const *argv[]) { 3 | int x, y; 4 | 5 | printf("x=" ); 6 | scanf("%d", &x); 7 | 8 | printf("y=" ); 9 | scanf("%d", &y); 10 | 11 | if( x < y || x == y || x > y ) 12 | { 13 | printf( "WRONG\n" ); 14 | }else 15 | { 16 | printf("RIGHT\n" ); 17 | } 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /ch4/q12.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, char const *argv[]) { 3 | int leap_year; 4 | int year; 5 | 6 | printf("请输入一个年份:\n" ); 7 | scanf("%d", &year); 8 | 9 | if ( (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) ) { 10 | leap_year = 1; 11 | printf( "闰年\n" ); 12 | }else 13 | { 14 | printf( "非闰年\n" ); 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /ch4/q13.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, char const *argv[]) { 3 | 4 | int which_word; 5 | char ch; 6 | 7 | scanf("%d", &which_word ); 8 | // scanf("%c", &ch ); 9 | // printf("%d\n", ch ); 10 | 11 | switch( which_word ) 12 | { 13 | case 1: 14 | printf( "who\n" ); 15 | break; 16 | case 2: 17 | printf( "what\n" ); 18 | break; 19 | case 3: 20 | printf( "when\n" ); 21 | break; 22 | case 4: 23 | printf( "where\n" ); 24 | break; 25 | case 5: 26 | printf( "why\n" ); 27 | break; 28 | default: 29 | printf( "don't know\n" ); 30 | break; 31 | } 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /ch4/q14.c: -------------------------------------------------------------------------------- 1 | while ( hungry() ) { 2 | eat_humberger(); 3 | } 4 | -------------------------------------------------------------------------------- /ch4/q15.c: -------------------------------------------------------------------------------- 1 | do { 2 | eat_humberger(); 3 | } while( hungry() ); 4 | -------------------------------------------------------------------------------- /ch4/q16.c: -------------------------------------------------------------------------------- 1 | void printCurrentWeather(int preciptating, int temperature ) 2 | { 3 | if( preciptating == 1) 4 | { 5 | if( temperature < 32 ) 6 | { 7 | printf( "snowing\n" ); 8 | } 9 | else if( temperature >= 32 ) 10 | { 11 | printf( "raining\n" ); 12 | } 13 | } 14 | else 15 | { 16 | if( temperature < 60 ) 17 | { 18 | printf( "cold\n" ); 19 | } 20 | else if( temperature >= 60 ) 21 | { 22 | printf( "warm\n" ); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ch4/q4.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main( int argc, char* args[]) 4 | { 5 | int i = 9; 6 | /* 7 | 使用空语句 8 | */ 9 | if ( i > 10 ); 10 | else{ 11 | printf("执行空语句之后的else语句\n"); 12 | } 13 | 14 | /* 15 | 使用非运算符 16 | */ 17 | if(! (i > 10) ){ 18 | printf("执行非情况下的语句\n" ); 19 | } 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /ch4/test.txt: -------------------------------------------------------------------------------- 1 | This is first line. 2 | Another line. 3 | And another. 4 | And another. 5 | And another. 6 | And another. 7 | Still more. 8 | Almost done now -- 9 | Almost done now -- 10 | 11 | Another line. 12 | Still more. 13 | Finished! 14 | -------------------------------------------------------------------------------- /ch4/while语句执行过程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch4/while语句执行过程.png -------------------------------------------------------------------------------- /ch5/UU7TH(Q{9])M44@~0HGE]Y1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch5/UU7TH(Q{9])M44@~0HGE]Y1.png -------------------------------------------------------------------------------- /ch5/ch5.txt: -------------------------------------------------------------------------------- 1 | 1.移位操作符:<<和>> 操作数必须是整型 2 | 逻辑移位:左边移入的位用0填充 3 | 算术移位:左边移入的位由原先该值的符号位决定 4 | 逻辑左移与算术左移是相同的,逻辑右移与算术右移是不同的,而且只有操作数为负数时才不一样。 5 | 标准说明无符号数的执行的所有移位操作都是逻辑移位,但是,对于有符号数,采用哪种移位方式 6 | 取决于编译器。有符号值的右移位操作是不可移植的。 7 | 2.位操作符:& | ^ 操作数必须是整型 8 | 把指定位置设置为1:value = value | 1 << bit_number 9 | 把指定位置设置为0:value = value & 1 << bit_number 10 | 对指定位置进行测试:value = value & 1 << bit_number 11 | 3.赋值:赋值也是一种表达式,是表达式就有值 12 | 连续赋值中个变量各类型的长度不一致导致的截取问题。 13 | 复合赋值符:左操作数只求值一次,右操作数在执行复合赋值操作之前即被求值,即使它的优先级 14 | 低于复合赋值操作。 15 | 尽量使用复合赋值符。 16 | 4.单目操作符: 17 | sizeof的操作数既可以是表达式(表达式不进行求值操作),也可以是类型名。 18 | (类型)将强制类型转化放在一个表达式前面只会改变表达式的第一个项目类型。 19 | 抽象地讲,前缀和后缀形式的增值操作都复制一份变量的拷贝,用于周围表达式的值正是这份拷贝。 20 | 对于前缀操作符在复制之前增加变量的值,后缀操作符在进行复制操作之后才增加变量的值。 21 | 5.关系操作符:这些操作符的结果都是整型值。 22 | 推荐使用的判断方式: 23 | if( expression ){ } 24 | if( !expression ){ } 25 | 6.逻辑操作符:&&和|| 26 | 会控制子表达式的求值顺序。 27 | 短路求值。 28 | 7.条件操作符:?: 29 | 优先级非常低,通常与复制操作符一起使用。 30 | 8.逗号操作符, 31 | 逗号操作符将两个或者多个表达式分隔开来,这些表达式自左向右逐个求值,最后一个表达式的值 32 | 就是整个逗号表达式的值。 33 | 9.布尔值 34 | 0是假,任何非零值是真。 35 | #define TRUE 1 36 | #define FALSE 0 37 | 避免混合使用整型值和布尔值。 38 | 10.左值和右值 39 | 左值:标示内存中一个特定的位置的标识。 40 | 右值:不能标示内存中一个特定的位置的标识。 41 | 左值意味一个位置,右值意味一个值,在使用右值的地方也可以使用左值,在需要左值的地方不可 42 | 以使用右值。 43 | 11.优先级和求值顺序 44 | 两个相邻的操作符的执行顺序由他们的优先级决定。如果优先级相同,它们的执行顺序由它们的结 45 | 合性决定。除此之外,编译器可以自由决定使用任何顺序的对表达式进行求值,只要它不违背逗号、 46 | &&和||和?:施加限制。 47 | 48 | -------------------------------------------------------------------------------- /ch5/p1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define INPUT_MAX 129 6 | 7 | int main(int argc, char const *argv[]) { 8 | char input[INPUT_MAX]; 9 | int index = 0; 10 | int length = 0; 11 | 12 | while( fgets(input, INPUT_MAX, stdin )!= NULL ) 13 | { 14 | 15 | for ( index = 0, length = strlen( input ); index < length ; index++) { 16 | input[index] = tolower( input[index] ); 17 | } 18 | printf("%s\n", input ); 19 | } 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /ch5/p2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int encrypt( int ch, int base ) 5 | { 6 | ch -= base; 7 | ch += 13; 8 | ch %= 26; 9 | return ch + base; 10 | } 11 | 12 | int main(int argc, char const *argv[]) { 13 | int ch; 14 | 15 | while ( (ch = getchar()) != EOF ) { 16 | if ( isalpha(ch) ) { 17 | if( ch >= 65 && ch <= 90 ) 18 | ch = encrypt( ch, 'A'); 19 | else if( ch >= 97 && ch <= 122 ) 20 | ch = encrypt( ch, 'a'); 21 | } 22 | putchar(ch); 23 | } 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /ch5/p3.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned int reverse( unsigned int value ) 4 | { 5 | unsigned int answer = 0; 6 | unsigned int i; 7 | 8 | /* 9 | 用i来控制循环的次数,利用位操作,增加程序的可移植性 10 | for( i = 1; i != 0; i <<= 1) 11 | */ 12 | for ( i = 1; i != 0 ; i <<= 1) { 13 | answer <<= 1; 14 | if( value & 1 ) 15 | answer |= 1; 16 | value >>= 1; 17 | } 18 | 19 | return answer; 20 | } 21 | int main(int argc, char const *argv[]) { 22 | printf("%d\n", reverse(25) ); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /ch5/p4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void set_bit( char bit_array[], unsigned int bit_number ) 5 | { 6 | int length = strlen( bit_array ); 7 | if( bit_number < length ) 8 | { 9 | bit_array[length - bit_number - 1] = '1'; 10 | } 11 | } 12 | 13 | void clear_bit( char bit_array[], unsigned int bit_number ) 14 | { 15 | int length = strlen( bit_array ); 16 | if( bit_number < length ) 17 | { 18 | bit_array[length - bit_number - 1] = '0'; 19 | } 20 | } 21 | 22 | void assign_bit( char bit_array[], unsigned int bit_number, int value ) 23 | { 24 | int length = strlen( bit_array ); 25 | if ( bit_number < length ) 26 | { 27 | if ( value == 0) 28 | { 29 | bit_array[length - bit_number - 1] = '0'; 30 | } 31 | else if( value == 1) 32 | { 33 | bit_array[length - bit_number - 1] = '1'; 34 | } 35 | } 36 | } 37 | 38 | int test_bit( char bit_array[], unsigned bit_number ) 39 | { 40 | int length = strlen( bit_array ); 41 | if ( bit_number < length ) 42 | { 43 | if ( bit_array[bit_number] != '0') 44 | { 45 | return 1; 46 | } 47 | else 48 | { 49 | return 0; 50 | } 51 | } 52 | } 53 | int main(int argc, char const *argv[]) { 54 | char str[] = "0000"; 55 | set_bit( str, 1 ); 56 | printf("%s\n", str ); 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /ch5/p5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define INI_BITS ( CHAR_BIT * sizeof(int) ) 5 | /* 6 | 已经经过测试该编译器中规定int为4个字节 7 | */ 8 | 9 | int creat_mask( int starting_bit, int ending_bit ) 10 | { 11 | /*为保证进行逻辑移位而不是算术移位,将掩码声明为无符号类型*/ 12 | unsigned int mask = (unsigned)-1;//强制类型转换 13 | mask >>= INI_BITS - (starting_bit - ending_bit + 1 ); 14 | mask <<= ending_bit; 15 | return mask; 16 | } 17 | 18 | 19 | 20 | int store_bit_field( int original_value, int value_to_store, unsigned starting_bit, unsigned ending_bit ) 21 | { 22 | unsigned int mask = creat_mask( starting_bit, ending_bit ); 23 | original_value &= ~mask; 24 | value_to_store <<= ending_bit; 25 | return original_value | value_to_store & mask; 26 | } 27 | int main(int argc, char const *argv[]) { 28 | int i = 0xffff; 29 | 30 | //printf("%x\n", store_bit_field( i, 0x123, 13, 9) ); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /ch6/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch6/a.out -------------------------------------------------------------------------------- /ch6/ch6.txt: -------------------------------------------------------------------------------- 1 | 1.不能简单地通过检查一个值的位来判断它的类型,类型是通过值的使用方法隐式地确定。 2 | 2.一个变量的值就是分配给这个变量的内存位置所存储的数值。 3 | 3.声明一个指针变量并不会自动分配任何内存。在指针间接访问之前,指针必须初始化, 4 | 或者使它指向现有内存,或者给它动态分配内存。 5 | 4.在对指针进行间接访问操作之前,首先必须要检查指针是否为NULL,对NULL指针执行间 6 | 接访问操作的后果因编译器而异。 7 | 5.偶尔需要使用指针常量,通过将一个整型强制转化为指针类型来创建它。 8 | 6.指针加1将会指向下一个变量,与该变量中在内存中占几个字节大小无关。 9 | 7.指针的算术运算: 指针 +/- 整数 10 | 标准中定义这种形式只适用于指向数组中的某个元素的指针,但是,这种形式页适用于 11 | malloc函数动态分配的内存。 12 | 如果一个指针减去一个整数之后,运算结果产生指针所指向的位置在数组第一个元素之前, 13 | 那么它是非法的;如果指针加上一个整数之后,运算结果产生的指针指向数组最后一个元素 14 | 后面的那个内存位置(但是不对这个指针执行间接访问操作)是合法的,不过在往后就是不 15 | 合法的了。 16 | 8.指针的算术运算: 指针 - 指针 17 | 标准定义这种形式只有当两个指针都指向同一个数组中的元素的情况下才适用。 18 | 两个指针相减的结果表示两个指针在数组中相隔多少个元素。 19 | 9.指针的关系运算: < <= > >= 20 | 标准定义这几种形式只适用于两个指针都指向同一个数组。 21 | 运算结果将会显示哪个指针靠前哪个指针靠后。 22 | 然而任意两个指针都会执行判断相等或者不相等的操作。 23 | 标准允许指向数组元素的指针与数组的最后一个元素后面的那个内存位置的指针进行比较,但 24 | 是不允许与指向数组的第一个元素之前的那个内存位置的指针进行比较。 25 | -------------------------------------------------------------------------------- /ch6/p1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define NUL '\0' 4 | 5 | char const *find_char( char const *source, char const *chars ) 6 | { 7 | char const *temp_source = source; 8 | 9 | while( *chars != NUL ) 10 | { 11 | while ( *temp_source != NUL ) 12 | { 13 | if( *temp_source == *chars ) 14 | { 15 | return temp_source; 16 | } 17 | temp_source++; 18 | } 19 | chars++; 20 | temp_source = source; 21 | } 22 | 23 | return NULL; 24 | } 25 | 26 | int main(int argc, char const *argv[]) { 27 | char *source = "ABCDEF"; 28 | char *chars = "erwtwEt"; 29 | char const *ch = NULL; 30 | 31 | if( (ch = find_char( source, chars ) ) != NULL ) 32 | printf("%c\n", *ch ); 33 | else 34 | printf("NULL \n" ); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /ch6/p2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define NUL '\0' 4 | 5 | int del_substr( char *str, char const *substr ) 6 | { 7 | char *pstr = NULL; 8 | char const *psubstr = NULL; 9 | 10 | while( *str != NUL ) 11 | { 12 | if( is_substr( str, substr) ) 13 | break; 14 | str++; 15 | } 16 | if ( *str != NUL ) 17 | { 18 | pstr = str; 19 | psubstr = substr; 20 | while ( *substr != NUL ) 21 | { 22 | str++; 23 | substr++; 24 | } 25 | } 26 | else 27 | return 0; 28 | while ( *pstr++ = *str++ ); 29 | return 1; 30 | } 31 | 32 | /* 33 | 判断一个字符串是否与另一个字符串的开始匹配 34 | */ 35 | int is_substr( char *str, char const *substr ) 36 | { 37 | if ( str != NULL && substr != NULL ) 38 | { 39 | while ( *str != NUL && *substr != NUL ) 40 | { 41 | if ( *str++ != *substr++ ) 42 | return 0; 43 | } 44 | if( *substr == NUL ) 45 | return 1; 46 | else if ( *substr != NUL ) 47 | return 0; 48 | } 49 | else 50 | return 0; 51 | } 52 | 53 | 54 | int main(int argc, char const *argv[]) { 55 | char str[] = "sdfsfsfesfrttreyyr";//声明为数组而非指针 56 | printf("%s\n", str ); 57 | 58 | if ( del_substr( str , "sfe") ) { 59 | printf("%s\n", str ); 60 | }else{ 61 | printf("sdgfg\n" ); 62 | } 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /ch6/p3.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define NUL '\0' 4 | 5 | void reverse_string( char *string ) 6 | { 7 | char *last_string = string; 8 | char *pre_string = string; 9 | char temp_ch = 0; 10 | 11 | while ( *last_string++ != NUL ); 12 | last_string -= 2; 13 | 14 | while ( pre_string < last_string ) { 15 | temp_ch = *pre_string; 16 | *pre_string++ = *last_string; 17 | *last_string-- = temp_ch; 18 | } 19 | } 20 | 21 | int main(int argc, char const *argv[]) { 22 | char str[] = "abcdefghi"; 23 | reverse_string( str ); 24 | printf("%s\n", str ); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /ch6/p4.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define TRUE '1' 4 | #define FALSE '0' 5 | 6 | int main(int argc, char const *argv[]) { 7 | char num[1001]; 8 | int index = 0; 9 | char *pstr = NULL; 10 | 11 | for(; index <= 1000; index++ ) 12 | { 13 | num[index] = TRUE; 14 | } 15 | pstr = num; 16 | 17 | for( index = 2; index <= 1000; index++ ) 18 | { 19 | if ( num[index] == TRUE ) { 20 | int temp = index+1; 21 | for( ; temp <= 1000; temp++ ) 22 | { 23 | if( num[temp] == TRUE && temp % index == 0 ) 24 | { 25 | num[temp] = FALSE; 26 | } 27 | } 28 | } 29 | } 30 | 31 | int number = 0; 32 | for( index = 2; index <= 1000; index++) 33 | { 34 | if( num[index] == TRUE ) 35 | { 36 | if( number % 5 == 0) printf( "\n" ); 37 | printf("%d\t", index ); 38 | number++; 39 | } 40 | } 41 | printf("\n"); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /ch6/p5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define MAX_VALUE 1000 5 | #define MAX_BIT_NUMBER ( (MAX_VALUE - 3) / 2) 6 | #define SIZE ( MAX_BIT_NUMBER / CHAR_BIT + 2) 7 | /* 8 | 对字符数组的位操作 9 | */ 10 | unsigned bit_offset( unsigned bit_number ) 11 | { 12 | return bit_number % CHAR_BIT; 13 | } 14 | 15 | unsigned character_offset ( unsigned bit_number ) 16 | { 17 | return bit_number / CHAR_BIT; 18 | } 19 | /* 20 | 测试指定位为1还是为0 21 | */ 22 | int test_bit( char bit_array[], unsigned int bit_number ) 23 | { 24 | return ( bit_array[ character_offset( bit_number ) ] & 1 << bit_offset( bit_number )) != 0; 25 | } 26 | 27 | /* 28 | 置位 29 | */ 30 | void set_bit( char bit_array[], unsigned int bit_number ) 31 | { 32 | bit_array[ character_offset( bit_number ) ] |= 1 << bit_offset( bit_number ); 33 | } 34 | 35 | /* 36 | 清零 37 | */ 38 | void clear_bit( char bit_array[], unsigned int bit_number ) 39 | { 40 | bit_array[ character_offset( bit_number )] &= ~(1 << bit_offset( bit_number )); 41 | } 42 | 43 | 44 | int main(int argc, char const *argv[]) { 45 | char sieve[ SIZE ]; 46 | int number; 47 | int bit_number; 48 | char *sp; 49 | /* 50 | 初始化 51 | */ 52 | for( sp = &sieve[0]; sp < &sieve[ SIZE ]; ) 53 | *sp++ = 0xff;//使用16进制初始化字符变量 54 | 55 | 56 | for( number = 3; number <= MAX_VALUE; number += 2 ) 57 | { 58 | bit_number = ( number - 3 ) / 2;//偶数 59 | if( !test_bit(sieve, bit_number) ) 60 | continue; 61 | while ( (bit_number += number) <= MAX_BIT_NUMBER ) 62 | { 63 | clear_bit( sieve, bit_number ); 64 | } 65 | /*以上部分代码可以这样写 66 | if( test_bit(sieve, bit_number) ) 67 | { 68 | while ( (bit_number += number) <= MAX_BIT_NUMBER ) 69 | { 70 | clear_bit( sieve, bit_number ); 71 | } 72 | } 73 | */ 74 | } 75 | 76 | /* 77 | 输出 78 | */ 79 | printf("2\t" ); 80 | for(bit_number = 0, number = 3; number <= MAX_VALUE; bit_number +=1, number += 2 ) 81 | { 82 | if( test_bit( sieve, bit_number )) 83 | printf("%d\t", number); 84 | } 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /ch6/p6.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define MAX_VALUE 1000 4 | 5 | int main(int argc, char const *argv[]) { 6 | int n_primes = 1; 7 | int limits = 1000; 8 | int bit_number; 9 | int number; 10 | 11 | for( number = 3, bit_number = 0; number <= MAX_VALUE; number += 2, bit_number += 1 ) 12 | { 13 | if( number > limits ) 14 | { 15 | printf("%d-%d:%d\n", limits-1000, limits, n_primes ); 16 | n_primes = 0; 17 | limits += 1000; 18 | } 19 | if ( test_bit( sieve, bit_number )) { 20 | n_primes++; 21 | } 22 | } 23 | printf("%d-%d:%d\n", limits-1000, limits, n_primes ); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /ch7/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch7/a.out -------------------------------------------------------------------------------- /ch7/ch7.txt: -------------------------------------------------------------------------------- 1 | 1.通过两种方式向编译器提供关于函数的信息: 2 | 1)在同一个源文件的开始出现函数定义。 3 | 2)在文件的开始提供函数原型,函数的参数的名字不是必须的。 4 | 2.将函数原型放在一个文件中,这样函数原型具有文件作用域,消除了多份原型拷贝的不一致性。 5 | 3.一个没有参数的函数原型应该写成如下的形式: int *func( void ) 其中void应该表示没有参数。 6 | 4.如果编译器无法看到一个函数的任何声明,那么编译器假定函数返回一个整型值,对于那些返回值不是 7 | 整型的函数,在调用之前对他们进行声明是很重要的,可以避开由于不可预测的类型转换导致的错误;并 8 | 且对于没有函数原型的函数,传递给函数的实参要进行缺省参数提升,char和short类型的实参转换成为 9 | int类型,float类型的实参被转换成double类型。 10 | 5.函数的参数是通过传值方式进行传递,实际是传递实参的一份拷贝。 11 | 6.递归的两个条件: 12 | 1)存在限制条件,当符合这个条件时在不执行递归 13 | 2)每次递归之后越来越来接近这个限制条件 14 | 7.黑盒技术 15 | 8.如果递归函数的内部执行的最后一条语句是调用自身的时候(称为尾部递归),可以很容易的改写成循环( 16 | 迭代)的形式,通常效率更高。 17 | 9.在可变参数列表中,普通参数必须以某种方式向函数传递实际参数的数量,当参数列表中可变部分的参数传 18 | 递给函数时,要经历缺省参数提升。 19 | 10.当使用数组作为函数参数的时候,数组并没有办法判断数组的长度,所以可以在参数中显示的传递数组的 20 | 参数。 21 | -------------------------------------------------------------------------------- /ch7/factorial.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | long factorial ( int n ) 4 | { 5 | long result = 1; 6 | while ( n > 1 ) { 7 | result *= n--; 8 | } 9 | return result; 10 | } 11 | int main(int argc, char const *argv[]) { 12 | printf("%ld\n", factorial( 4 )); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch7/fibonacci.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | long fibonacci ( int n ) 4 | { 5 | long result = 1; 6 | long pre_result = 1; 7 | long temp_result = 0; 8 | 9 | while ( n-- > 2) 10 | { 11 | temp_result = result; 12 | result += pre_result; 13 | pre_result = temp_result; 14 | } 15 | 16 | return result; 17 | } 18 | int main(int argc, char const *argv[]) { 19 | printf("%ld\n", fibonacci( 5 ) ); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /ch7/p1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int hermite( int n, int x ) 4 | { 5 | if ( n <= 0 ) 6 | { 7 | return 1; 8 | } 9 | else if ( n == 1 ) 10 | { 11 | return 2 * x; 12 | } 13 | return 2 * x *hermite( n-1, x ) - 2 * (n-1) * hermite( n-2, x ); 14 | } 15 | int main(int argc, char const *argv[]) { 16 | printf("%d\n", hermite( 3, 2 )); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /ch7/p2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 辗转相除法求最大公约数*/ 4 | /* 5 | 用递归计算M和N的最大公约数 6 | 输入: 7 | m,n(m和n之间大小无所谓) 8 | 输出: 9 | int类型的最大公约数 10 | */ 11 | int gcd( int m, int n ) 12 | { 13 | int r; 14 | if( m <= 0 || n <= 0 ) return 0; 15 | r = m % n; 16 | return r > 0 ? gcd( n, r ) : n; 17 | } 18 | 19 | 20 | /* 21 | 用迭代计算M和N的最大公约数 22 | 输入: 23 | m,n 24 | 输出: 25 | 26 | */ 27 | int gcd2( int m, int n ) 28 | { 29 | int r; 30 | 31 | if ( m <= 0 || n <= 0 ) 32 | { 33 | return 0; 34 | } 35 | 36 | do { 37 | r = m % n; 38 | m = n; 39 | n = r; 40 | } while( r > 0 ); 41 | 42 | return m; 43 | } 44 | 45 | 46 | int main(int argc, char const *argv[]) { 47 | printf("%d\n", gcd2( 5, 12 ) ); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /ch7/p3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define NUL '\0' 5 | 6 | int ascii_to_integer( char *string ) 7 | { 8 | int result = 0; 9 | 10 | while( *string != NUL ) 11 | { 12 | if( isdigit( *string ) )//判断字符是否为数字 13 | { 14 | result *= 10; 15 | result += *string - '0'; 16 | string++; 17 | } 18 | else 19 | { 20 | result = 0; 21 | break; 22 | } 23 | } 24 | 25 | return result; 26 | } 27 | int main(int argc, char const *argv[]) { 28 | char str[] = "1235"; 29 | printf("%d\n", ascii_to_integer( str ) ); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /ch7/p4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int max_list( int first_num, ... ) 5 | { 6 | int max = first_num; 7 | va_list var_arg;//1 8 | 9 | if( first_num >= 0 ) 10 | { 11 | int temp_arg; 12 | 13 | va_start( var_arg, first_num );//2 14 | 15 | while ( (temp_arg = va_arg( var_arg , int )) > 0 )//3 16 | { 17 | if ( temp_arg > max ) 18 | { 19 | max = temp_arg; 20 | } 21 | } 22 | 23 | va_end( var_arg );//4 24 | } 25 | 26 | return max; 27 | } 28 | 29 | int main(int argc, char const *argv[]) { 30 | printf("%d\n", max_list( 6, 1, 12, 234, 56, 344, 45, -1 )); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /ch7/p5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define NUL '\0' 5 | void print_int( int n ) 6 | { 7 | printf("%d\n", n ); 8 | } 9 | 10 | void print_float( double n ) 11 | { 12 | printf("%lf\n", n ); 13 | } 14 | 15 | int my_printf( char *format , ... ) 16 | { 17 | int num = 0; 18 | char ch; 19 | char *str; 20 | va_list var_list; 21 | 22 | va_start( var_list , format ); 23 | 24 | while ( (ch = *format++ ) != NUL ) 25 | { 26 | if ( ch != '%') { 27 | putchar( ch ); 28 | continue; 29 | } 30 | 31 | switch ( *format != NUL ? *format++ : NUL )//使用条件表达式 32 | { 33 | case 'd': 34 | print_int( va_arg( var_list , int ) ); 35 | break; 36 | case 'f': 37 | print_float( va_arg( var_list , double ) ); 38 | break; 39 | case 's': 40 | str = va_arg( var_list, char * );//可以使用任何类型 41 | while ( *str != NUL ) { 42 | putchar( *str++ ); 43 | } 44 | break; 45 | case 'c': 46 | num--; 47 | break; 48 | } 49 | num++; 50 | } 51 | 52 | va_end( var_list ); 53 | 54 | return num; 55 | } 56 | int main(int argc, char const *argv[]) { 57 | int d = 14; 58 | printf("%d\n", my_printf("%d===%f sdfds %f%e%f", d, 3.34, 4.55555, 67868, 89.99) ); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /ch7/p6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define BUFFER_LENGTH 1024 6 | #define CHARS_LENGTH 12 7 | 8 | static char *number[] = {"", 9 | "one ", "two ", "three ", "four ", "five ", 10 | "six ", "seven ", "eight ", "nine ","ten ", 11 | "elven ", "twelve ", "thirteen ", "fourteen ", "fifteen ", 12 | "sixteen ", "seventeen ", "eighteen ", "nineteen " 13 | }; 14 | static char *degree[] = {"", "thousand ", "million ", "billion " }; 15 | static char *tens[] = {"", 16 | "", "twenty ", "thirty ", "forty ", "fifty ", 17 | "sixty ", "seventy ", "eighty ", "ninety " 18 | }; 19 | 20 | static void do_one_group( unsigned int amount, char *buffer, char **degree ) 21 | { 22 | int value; 23 | 24 | value = amount / 1000; 25 | if( value > 0 ) 26 | do_one_group( value, buffer, degree + 1 ); 27 | amount %= 1000; 28 | 29 | value = amount / 100; 30 | if ( value > 0 ) { 31 | strcat( buffer, number[ value ]); 32 | strcat( buffer, "hundred "); 33 | } 34 | value = amount % 100; 35 | 36 | if ( value >= 20 ) 37 | { 38 | strcat( buffer, tens[ value/10 ]); 39 | value %= 10; 40 | } 41 | 42 | if( value > 0 ) 43 | { 44 | strcat( buffer, number[ value ]); 45 | } 46 | if ( amount > 0 ) 47 | { 48 | strcat( buffer, *degree ); 49 | } 50 | 51 | } 52 | 53 | void written_amount( unsigned int amount, char *buffer ) 54 | { 55 | if ( amount == 0 ) { 56 | strcpy( buffer, "zero"); 57 | } 58 | else 59 | { 60 | //*buffer = '\0'; 61 | do_one_group( amount, buffer, degree ); 62 | } 63 | } 64 | 65 | int main(int argc, char const *argv[]) { 66 | char buffer[BUFFER_LENGTH]; 67 | memset( buffer, 0, sizeof(buffer) );//声明数组时使用memset将数组置空 68 | 69 | int value = 10245; 70 | written_amount( value, buffer ); 71 | printf("%s\n", buffer ); 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /ch8/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch8/a.out -------------------------------------------------------------------------------- /ch8/ch8.txt: -------------------------------------------------------------------------------- 1 | 1.只要有可能,函数的指针形式尽量声明成const 2 | 2.数组名是指针常量,只有在两种情况下,数组名不表示指针常量: 3 | 1)数组名当做sizeof的参数的时候,返回整个数组的长度而不是指针长度。 4 | 2)数组名当做&操作符的时候,返回一个指向数组第一个元素的指针。 5 | 3.下标绝对不会比指针更有效率,但指针有时候会笔下标更有效率。 6 | 4.数组和指针都可以与下标引用和间接访问操作符同时使用。除了优先级不同,[]和 7 | *相同,ap[1]与*(ap+1)等价 8 | 5.优化程序关键是要先确定程序中哪些代码段占用了绝大部分的运行时间,然后集中 9 | 精力于那部分代码上进行修改。 10 | 6.声明数组时,为数组的元素分配内存;声明指针时,只为指针本身分配内存。 11 | 7.数组形参既可以声明为数组也可以声明为指针,这两种形式在做函数的参数时等价, 12 | 当在一个哈函数中调用sizeof求函数的形参数组的长度时,返回指针的大小,因为数 13 | 组的元素本身没有在此函数作用域中分配内存,所以。通常在函数的形参中添加数组长 14 | 度作为参数。 15 | 8.静态初始化只初始化一次,在文件载入到内存中准备执行时,初始化后的数组值和程 16 | 序指令一样被载入到内存中,当程序执行时,静态初始化已经初始化完毕。 17 | 9.不完整初始化只允许省略最后几个值。 18 | 10.多维数组中的元素根据行主序进行存储,也就是最右边的下标率优先变化。 19 | 11.多维数组名的值是一个指向它第一个元素的指针,是一个指向数组的指针,对该数 20 | 组名进行运算时根据数组长度对操作数进行调整。 21 | 12.当一个一维数组名作为参数传递给函数时,必须指明第二维和接下去所有维的长度, 22 | 只有第一维的长度会被自动计算。 23 | -------------------------------------------------------------------------------- /ch8/p1.c: -------------------------------------------------------------------------------- 1 | #include 2 | /*通过注释来区别每一行的位置*/ 3 | static char char_value[3][6][4][5] = { 4 | {/*0*/ 5 | {/*0,0*/ 6 | { 0 }, 7 | } 8 | }, 9 | {/*1*/ 10 | {/*1,0*/ 11 | { 0 } 12 | }, 13 | {/*1,1*/ 14 | {/*1,1,0*/ 15 | 0 16 | }, 17 | {/*1,1,1*/ 18 | 0, ' ' 19 | } 20 | }, 21 | {/*1,2*/ 22 | {/*1,2,0*/ 23 | 0 24 | }, 25 | {/*1,2,1*/ 26 | 0 27 | }, 28 | {/*1,2,2*/ 29 | 0,0,0,'A' 30 | }, 31 | {/*1,2,3*/ 32 | 0, 0, 0, 0, 'x' 33 | } 34 | }, 35 | {/*1,3*/ 36 | {/*1,3,0*/ 37 | 0 38 | }, 39 | {/*1,3,1*/ 40 | 0 41 | }, 42 | {/*1,3,2*/ 43 | 0,0,0xf3 44 | } 45 | }, 46 | {/*1,4*/ 47 | {/*1,4,0*/ 48 | 0 49 | }, 50 | {/*1,4,1*/ 51 | 0 52 | }, 53 | {/*1,4,2*/ 54 | 0, 0, 0, '\n' 55 | } 56 | } 57 | }, 58 | {/*2*/ 59 | {/*2,0*/ 60 | { 0 } 61 | }, 62 | {/*2,1*/ 63 | {/*2,1,0*/ 64 | 0 65 | }, 66 | {/*2,1,1*/ 67 | 0, 0, 0320 68 | }, 69 | {/*2,1,2*/ 70 | 0 71 | } 72 | }, 73 | {/*2,2*/ 74 | {/*2,2,0*/ 75 | 0 76 | }, 77 | {/*2,2,1*/ 78 | 0, '0' 79 | }, 80 | {/*2,2,2*/ 81 | 0, 0, '\'' 82 | }, 83 | {/*2,2,3*/ 84 | 0, '\121' 85 | } 86 | }, 87 | {/*2,3*/ 88 | 0 89 | }, 90 | {/*2,4*/ 91 | {/*2,4,0*/ 92 | 0 93 | }, 94 | {/*2,4,2*/ 95 | 0 96 | }, 97 | {/*2,4,3*/ 98 | 0, 0, '3', 3 99 | } 100 | }, 101 | {/*2,5*/ 102 | {/*2,5,0*/ 103 | 0 104 | }, 105 | {/*2,5,1*/ 106 | 0 107 | }, 108 | {/*2,5,2*/ 109 | 0 110 | }, 111 | {/*2,5,3*/ 112 | 0, 0, 0, 0, 125 113 | } 114 | } 115 | } 116 | }; 117 | 118 | int main(int argc, char const *argv[]) { 119 | int a, b, c, d; 120 | for ( a = 0 ; a < 3; a++ ) 121 | { 122 | for ( b = 0 ; b < 6; b++ ) 123 | { 124 | for( c = 0 ; c < 4; c++ ) 125 | { 126 | for(d = 0 ; d < 5; d++ ) 127 | { 128 | printf("%d:%d:%d:%d: ==== %d\n", a, b, c, d, char_value[a][b][c][d] ); 129 | } 130 | } 131 | } 132 | } 133 | 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /ch8/p2.c: -------------------------------------------------------------------------------- 1 | /* 2 | 看到这到题第一个想法就是使用多个if语句进行判断,然后再分别采用公式进行计算。 3 | 但是,本题的答案采用另一种方法解决,通过用数组来存储数据来进行计算。 4 | */ 5 | #include 6 | 7 | 8 | static double income_limits[] = { 0, 23350, 56550, 117950, 256500 }; 9 | 10 | static float base_tax[] = { 0, 3502.5, 12798.5, 31832.5, 81710.5 }; 11 | 12 | static float percentage[] = { 0.15, 0.28, 0.31, 0.36, 0.396 }; 13 | 14 | float single_tax( float income ) 15 | { 16 | int category = 1; 17 | for( ; income > income_limits[category] ; category++ ); 18 | category--; 19 | //printf("%d\n", category ); 20 | 21 | return base_tax[category] + ( income- income_limits[category] ) * percentage[ category ]; 22 | } 23 | 24 | int main(int argc, char const *argv[]) { 25 | printf("%f\n", single_tax( 23360 ) ); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /ch8/p3.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | int identity_matrix( int (*matrix)[10], int size ) 5 | { 6 | int x, y; 7 | for( x = 0, y = 0; x < size; x++,y++ ) 8 | { 9 | //printf("x = %d, y = %d\n", x , y ); 10 | if( matrix[x][y] != 1 ) 11 | return 0; 12 | } 13 | return 1; 14 | } 15 | int main(int argc, char const *argv[]) { 16 | int matrix[10][10] = { 17 | { 1}, 18 | { 0, 1}, 19 | { 0, 0, 1}, 20 | { 0, 0, 0, 1}, 21 | { 0, 0, 0, 0, 1}, 22 | { 0, 0, 0, 0, 0, 1}, 23 | { 0, 0, 0, 0, 0, 0, 1}, 24 | { 0, 0, 0, 0, 0, 0, 0, 1}, 25 | { 0, 0, 0, 0, 0, 0, 0, 0, 1}, 26 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} 27 | }; 28 | if ( identity_matrix( matrix, 10 ) ) { 29 | printf( "该矩阵是单位矩阵\n" ); 30 | } 31 | else 32 | printf("该矩阵不是单位矩阵\n"); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /ch8/p4.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | int identity_matrix( int (*matrix)[10], int size ) 5 | { 6 | int x, y; 7 | for( x = 0, y = 0; x < size; x++,y++ ) 8 | { 9 | //printf("x = %d, y = %d\n", x , y ); 10 | if( matrix[x][y] != 1 ) 11 | return 0; 12 | } 13 | return 1; 14 | } 15 | int main(int argc, char const *argv[]) { 16 | int matrix[10][10] = { 17 | { 1}, 18 | { 0, 1}, 19 | { 0, 0, 1}, 20 | { 0, 0, 0, 1}, 21 | { 0, 0, 0, 0, 1}, 22 | { 0, 0, 0, 0, 0, 1}, 23 | { 0, 0, 0, 0, 0, 0, 1}, 24 | { 0, 0, 0, 0, 0, 0, 0, 1}, 25 | { 0, 0, 0, 0, 0, 0, 0, 0, 1}, 26 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} 27 | }; 28 | if ( identity_matrix( matrix, 10 ) ) { 29 | printf("\n" ); 30 | } 31 | else 32 | printf("dfgdddddddddddddd\n"); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /ch8/p5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void matrix_multiply( int *m1, int *m2, int *r, int x, int y, int z) 5 | { 6 | int num_m1 = x * y; 7 | int num_m2 = y * z; 8 | int line_m1, line_m2, row_m1, row_m2; 9 | int temp_result = 0; 10 | //第一个数组的横坐标 11 | for( line_m1 = 0; line_m1 < x; line_m1++ ) 12 | { 13 | //第二个数组的纵坐标 14 | for( row_m2 = 0; row_m2 < z; row_m2++ ) 15 | { 16 | //第一个数组的纵坐标和第二个数组的横坐标同时变化 17 | for ( row_m1 = 0, line_m2 = 0; row_m1 < y; row_m1++, line_m2++ ) 18 | { 19 | r[line_m1*z + row_m2] += m1[line_m1*y + row_m1] * m2[line_m2*z + row_m2]; 20 | } 21 | } 22 | } 23 | } 24 | 25 | 26 | /*答案代码如下,通过指针进行访问*/ 27 | 28 | void matrix_multiply( int *m1, int *m2, int *r, int x, int y, int z ) 29 | { 30 | register int *m1p; 31 | register int *m2p; 32 | register int k; 33 | int row; 34 | int column; 35 | 36 | for( row = 0; row < x; row++ ) 37 | { 38 | for( column = 0; column < z; column++ ) 39 | { 40 | m1p = m1 + row * y; 41 | m2p = m2 + column; 42 | *r = 0; 43 | 44 | for( k = 0; k < y; k++ ) 45 | { 46 | *r += *m1p * *m2p; 47 | m1p += 1; 48 | m2p += z; 49 | } 50 | 51 | r++; 52 | } 53 | } 54 | 55 | } 56 | int main(int argc, char const *argv[]) { 57 | int m1[] = { 2, -6, 3, 5, 1, -1}; 58 | int m2[] = { 4, -2, -4, -5, -7, -3, 6, 7}; 59 | int r[12]; 60 | int index_x, index_y; 61 | 62 | memset( r, 0, sizeof(r) ); 63 | matrix_multiply( m1, m2, r, 3, 2, 4); 64 | for( index_x = 0; index_x < 3; index_x++ ) 65 | { 66 | for( index_y = 0; index_y < 4; index_y++ ) 67 | printf("%d\t", r[index_x*4+index_y]); 68 | printf("\n" ); 69 | } 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /ch8/p6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int array_offset( int arrayinfo[], ... ) 5 | { 6 | va_list var_arg; 7 | int n = 0; 8 | int loc = 0; 9 | 10 | va_start( var_arg, arrayinfo ); 11 | 12 | for( ; n < arrayinfo[0]*2 ; n += 2 ) 13 | { 14 | int temp = va_arg( var_arg, int ); 15 | // 进行下标检测 16 | if ( temp >= arrayinfo[n+1] && temp <= arrayinfo[n+2] ) { 17 | loc *= arrayinfo[n+2] - arrayinfo[n+1] + 1; 18 | loc += temp - arrayinfo[n+1]; 19 | } 20 | else 21 | { 22 | return -1; 23 | } 24 | } 25 | 26 | va_end( var_arg ); 27 | 28 | return loc; 29 | } 30 | 31 | int main(int argc, char const *argv[]) { 32 | int arrayinfo[] = { 3, 4, 6, 1, 5, -3, 3 }; 33 | 34 | printf("%d\n", array_offset( arrayinfo, 4, 2, -3 )); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /ch8/p7.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int array_offset( int arrayinfo[], ... ) 5 | { 6 | va_list var_arg; 7 | int n = arrayinfo[0]*2; 8 | int loc = 0; 9 | int temp_index[10], index = 0; 10 | 11 | va_start( var_arg, arrayinfo ); 12 | 13 | while( index < arrayinfo[0] ) 14 | { 15 | temp_index[index++] = va_arg( var_arg ,int ); 16 | } 17 | 18 | for( ; n > 0 ; n -= 2 ) 19 | { 20 | // 进行下标检测 21 | if ( temp_index[--index] >= arrayinfo[n-1] && temp_index[index] <= arrayinfo[n] ) { 22 | loc *= arrayinfo[n] - arrayinfo[n-1] + 1; 23 | loc += temp_index[index] - arrayinfo[n-1]; 24 | } 25 | else 26 | { 27 | return -1; 28 | } 29 | } 30 | 31 | va_end( var_arg ); 32 | 33 | return loc; 34 | } 35 | 36 | 37 | int main(int argc, char const *argv[]) { 38 | int arrayinfo[] = { 3, 4, 6, 1, 5, -3, 3 }; 39 | 40 | printf("%d\n", array_offset( arrayinfo, 4, 1, -1 )); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /ch8/p8.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int chessboard[8][8]; 4 | 5 | //判断能否攻击其他棋子 6 | int attack_other( int row, int column ) 7 | { 8 | int i ; 9 | 10 | for ( i = 0; i < 8 && i != row ; i++ ) 11 | { 12 | if ( chessboard[i][column] || chessboard[row][i] ) 13 | return 1; 14 | if ( chessboard[i][column-(row-i)] && chessboard[i][column+(row-i)] ) 15 | return 1; 16 | } 17 | 18 | return 0; 19 | } 20 | 21 | void print_chessboard() 22 | { 23 | int row, column; 24 | for( row = 0; row < 8; row++ ) 25 | { 26 | for( column = 0; column < 8; column++ ) 27 | { 28 | printf("%d\t", chessboard[row][column]); 29 | } 30 | printf( "\n" ); 31 | } 32 | } 33 | 34 | int conflicts( int row, int column ) 35 | { 36 | int i; 37 | for( i = 1; i < 8; i += 1 ) 38 | { 39 | if( row - i >= 0 && chessboard[ row - i ][ column ] ) 40 | return 1; 41 | if( column - i >= 0 && chessboard[ row ][ column - i ] ) 42 | return 1; 43 | if( column + i < 8 && chessboard[ row ][ column + i ] ) 44 | return 1; 45 | 46 | if( row - i >= 0 && column - i >= 0 && chessboard[ row - i ][ column - i ] ) 47 | return 1; 48 | if( row - i >= 0 && column + i < 8 && chessboard[ row - i ][ column + i ] ) 49 | return 1; 50 | } 51 | return 0; 52 | } 53 | void place_chess( int row ) 54 | { 55 | int column; 56 | 57 | for ( column = 0; column < 8; column++ ) 58 | { 59 | chessboard[row][column] = 1; 60 | 61 | if ( row == 0 || !conflicts( row, column ) ) 62 | { 63 | if( row < 7 ) 64 | { 65 | place_chess( row+1 ); 66 | } 67 | else 68 | { 69 | //print_chessboard(); 70 | } 71 | } 72 | 73 | chessboard[row][column] = 0; 74 | } 75 | 76 | 77 | } 78 | 79 | int main(int argc, char const *argv[]) { 80 | 81 | printf("%d\n", attack_other( 1, 2) ); 82 | place_chess(0); 83 | print_chessboard(); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /ch8/q19.c: -------------------------------------------------------------------------------- 1 | for( kwp = keyword_table; **kwp != '\0'; kwp++ ) 2 | -------------------------------------------------------------------------------- /ch8/q4.c: -------------------------------------------------------------------------------- 1 | char buffer[SIZE] 2 | char *front, *rear; 3 | ... 4 | front = &buffer[0]; 5 | rear = &buffer[SIZE] - 1; 6 | while ( front < rear ) { 7 | if( *front++ != *rear++ ) 8 | break; 9 | } 10 | if ( front >= rear ) { 11 | printf("It is a palindrome\n" ); 12 | } 13 | -------------------------------------------------------------------------------- /ch9/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stephan14/Pointers_On_C/03369201531b9261728efbdeb3cdff4173ed6833/ch9/a.out -------------------------------------------------------------------------------- /ch9/ch9.txt: -------------------------------------------------------------------------------- 1 | 1.使用字符分类和转换函数可以提高函数的移植性。 2 | 2.在表达式中使用无符号数可能导致不可预料的结果。 3 | 如果表达式中同时包含有符号数和无符号数,可能会产生 4 | 奇怪的结果,可以其强制转换成int进行使用。 5 | 3.不受限制的字符串函数:通过字符串参数结尾的NUL字节来判断字符串长度。 6 | strcpy、strcat和strcmp函数的字符串参数必须必须以一个NUL字节结尾, 7 | 必须保证目标字符串数组剩余的空间足以保存整个源字符串,否则,将会覆盖 8 | 原先的数组后面的内存空间。如果src和dst的位置发生重叠,其结果是未定义 9 | 的。 10 | 4.长度受限的字符串函数:这些函数接受一个显示长度的参数。 11 | strncpy:如果src的长度小于len,dst用NU字节填充到len长度;如果src 12 | 长度大于或等于len,只有len个字符复制到dst中。注意:它的结果将不会以 13 | NUL字节结尾。 14 | strncat:n从源字符串复制过来的最大数目。其结果始终以NUL字节结尾。 15 | strncmp: 16 | 5.字符串查找: 17 | strchr:查找一个字符串中某个字符第一次出现的位置。 18 | strrchr:查找一个字符串中某个字符最后一次出现的位置。 19 | strpbrk:在一个字符串中查找一个指定字符集中字符任意字符第一次出现的位置。 20 | strstr:在一个字符串中查找另一个字符串第一次出现的位置。 21 | 6.高级字符串查找: 22 | strspn:计算一个字符串的起始部分匹配一个指定字符集中任意字符的字符数量。 23 | strcspn:计算一个字符串的起始部分不匹配一个指定字符集中任意字符的字符数量。 24 | strtok:把一个字符串分割成几个字符。 25 | 7.内存操作:类似于字符串函数的能力,但是可以处理包含NUL字节在内的任意字节, 26 | 都接受一个长度参数。 27 | memmove能够正确处理源参数和目标参数出现重叠的情况。 28 | -------------------------------------------------------------------------------- /ch9/p1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char const *argv[]) { 5 | int ch; 6 | int n_cntrl = 0; 7 | int n_space = 0; 8 | int n_number = 0; 9 | int n_lower = 0; 10 | int n_upper = 0; 11 | int n_punct = 0; 12 | int n_not_print = 0; 13 | int total = 0; 14 | 15 | while ( (ch = getchar() ) != EOF ) {//用ctrl+D结束文本输入 16 | total++; 17 | if ( iscntrl( ch ) ) n_cntrl++; 18 | if ( isspace( ch ) ) n_space++; 19 | if ( isdigit( ch ) ) n_number++; 20 | if ( islower( ch ) ) n_lower++; 21 | if ( isupper( ch ) ) n_upper++; 22 | if ( ispunct( ch ) ) n_punct++; 23 | if ( !isprint( ch ) ) n_not_print++; 24 | } 25 | 26 | if( total == 0 ) 27 | printf("没有输入\n" ); 28 | else 29 | { 30 | printf("控制字符占总字符比例为%%%3.0f\n", n_cntrl * 100.0 / total ); 31 | printf("空白字符占总字符比例为%%%3.0f\n", n_space * 100.0 / total ); 32 | printf("数字字符占总字符比例为%%%3.0f\n", n_number * 100.0 / total ); 33 | printf("小写字符占总字符比例为%%%3.0f\n", n_lower * 100.0 / total ); 34 | printf("大写字符占总字符比例为%%%3.0f\n", n_upper * 100.0 / total ); 35 | printf("标点字符占总字符比例为%%%3.0f\n", n_punct * 100.0 / total ); 36 | printf("不可打印字符占总字符比例为%%%3.0f\n", n_not_print * 100.0 / total ); 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /ch9/p10.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int palindrome( char *string ) 6 | { 7 | char *end_string = string + (int)strlen( string ) - 1; 8 | 9 | while( string < end_string ) 10 | { 11 | if( isalpha( *string ) && isalpha( *end_string )) 12 | { 13 | if( tolower(*string++) != tolower(*end_string--) ) 14 | { 15 | //string++; 16 | //end_string--; 17 | return 0; 18 | } 19 | } 20 | else if( !isalpha( *string ) ) 21 | string++; 22 | else if( !isalpha( *end_string ) ) 23 | end_string--; 24 | } 25 | 26 | return 1; 27 | } 28 | 29 | int main(int argc, char const *argv[]) { 30 | char str[10] = "abc,ba"; 31 | if( palindrome( str ) ) 32 | printf( "是回文串。\n" ); 33 | else 34 | printf( "不是回文串。\n"); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /ch9/p11.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define INPUT_MAX 101 4 | 5 | 6 | int main(int argc, char const *argv[]) { 7 | char buffer[INPUT_MAX]; 8 | char whitespace[] = " \t\n\r\v\f"; 9 | int counts = 0; 10 | 11 | while( fgets( buffer, INPUT_MAX, stdin ) ) 12 | { 13 | char *word; 14 | for ( word = strtok( buffer, whitespace ); 15 | word != NULL; 16 | word = strtok( NULL, whitespace ) ) 17 | { 18 | if( strcmp( word, "the" ) == 0 ) 19 | counts++; 20 | } 21 | } 22 | 23 | printf("%d\n", counts ); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /ch9/p12.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define KEY_LENGTH 27 6 | #define NUL '\0' 7 | 8 | int prepare_key( char *key ) 9 | { 10 | char *p_key = NULL; 11 | char *dup = NULL; 12 | int character; 13 | 14 | if( *key == NUL ) 15 | return 0; 16 | 17 | for( p_key = key; ( character = *p_key ) != NUL; p_key++ ) 18 | { 19 | if( !islower( character ) ) 20 | { 21 | if( !isupper( character ) ) 22 | return 0; 23 | *p_key = tolower( character ); 24 | } 25 | } 26 | //检查一个字符串中是否有重复字符 27 | for( p_key = key; ( character = *p_key ) != NUL; ) 28 | { 29 | dup = ++p_key; 30 | while ( (dup = strchr( dup, character )) != NULL ) 31 | strcpy( dup, dup+1 );//复制字符串 32 | } 33 | 34 | for( character = 'a'; character <= 'z'; character++ ) 35 | { 36 | if( strchr( key, character ) == NULL ) 37 | { 38 | *p_key++ = character; 39 | *p_key = NUL;//重点 40 | } 41 | } 42 | } 43 | 44 | 45 | int main(int argc, char const *argv[]) { 46 | char str[KEY_LENGTH] = "trailblazers"; 47 | //如果声明成char str[KEY_LENGTH] = "trailblazers";编译后显示 48 | //*** stack smashing detected ***: ./a.out terminated 49 | prepare_key( str ); 50 | printf( "%s\n", str ); 51 | printf( "%u", strlen( str ) ); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /ch9/p13.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define KEY_LENGTH 27 6 | #define NUL '\0' 7 | 8 | int prepare_key( char *key ) 9 | { 10 | char *p_key = NULL; 11 | char *dup = NULL; 12 | int character; 13 | 14 | if( *key == NUL ) 15 | return 0; 16 | 17 | for( p_key = key; ( character = *p_key ) != NUL; p_key++ ) 18 | { 19 | if( !islower( character ) ) 20 | { 21 | if( !isupper( character ) ) 22 | return 0; 23 | *p_key = tolower( character ); 24 | } 25 | } 26 | //检查一个字符串中是否有重复字符 27 | for( p_key = key; ( character = *p_key ) != NUL; ) 28 | { 29 | dup = ++p_key; 30 | while ( (dup = strchr( dup, character )) != NULL ) 31 | strcpy( dup, dup+1 );//复制字符串 32 | } 33 | 34 | for( character = 'a'; character <= 'z'; character++ ) 35 | { 36 | if( strchr( key, character ) == NULL ) 37 | { 38 | *p_key++ = character; 39 | *p_key = NUL;//重点 40 | } 41 | } 42 | } 43 | 44 | void encrypt( char *data, char const *key ) 45 | { 46 | while( *data != NUL ) 47 | { 48 | if( isalpha( *data ) ) 49 | { 50 | if( isupper( *data ) ) 51 | *data = toupper( *( key + *data - 'A') ); 52 | else 53 | *data = *( key + *data - 'a' ); 54 | } 55 | data++; 56 | } 57 | } 58 | int main(int argc, char const *argv[]) { 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /ch9/p14.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define KEY_LENGTH 27 6 | #define NUL '\0' 7 | 8 | int prepare_key( char *key ) 9 | { 10 | char *p_key = NULL; 11 | char *dup = NULL; 12 | int character; 13 | 14 | if( *key == NUL ) 15 | return 0; 16 | 17 | for( p_key = key; ( character = *p_key ) != NUL; p_key++ ) 18 | { 19 | if( !islower( character ) ) 20 | { 21 | if( !isupper( character ) ) 22 | return 0; 23 | *p_key = tolower( character ); 24 | } 25 | } 26 | //检查一个字符串中是否有重复字符 27 | for( p_key = key; ( character = *p_key ) != NUL; ) 28 | { 29 | dup = ++p_key; 30 | while ( (dup = strchr( dup, character )) != NULL ) 31 | strcpy( dup, dup+1 );//复制字符串 32 | } 33 | 34 | for( character = 'a'; character <= 'z'; character++ ) 35 | { 36 | if( strchr( key, character ) == NULL ) 37 | { 38 | *p_key++ = character; 39 | *p_key = NUL;//重点 40 | } 41 | } 42 | } 43 | 44 | void encrypt( char *data, char const *key ) 45 | { 46 | while( *data != NUL ) 47 | { 48 | if( isalpha( *data ) ) 49 | { 50 | if( isupper( *data ) ) 51 | *data = toupper( *( key + *data - 'A' ) ); 52 | else 53 | *data = *( key + *data - 'a' ); 54 | } 55 | data++; 56 | } 57 | } 58 | 59 | void decrypt( char *data, char const *key ) 60 | { 61 | while( *data != NUL ) 62 | { 63 | if( isalpha( *data ) ) 64 | { 65 | if( isupper( *data ) ) 66 | *data = strchr( key, *data ) - key + 'A'; 67 | else 68 | *data = strchr( key, *data ) - key + 'a'; 69 | } 70 | data++; 71 | } 72 | } 73 | 74 | int main(int argc, char const *argv[]) { 75 | char key[KEY_LENGTH] = "cde"; 76 | char str[] = "sdfsfsfs"; 77 | prepare_key( key ); 78 | 79 | printf("%s\n", key); 80 | 81 | encrypt( str, key ); 82 | 83 | printf("%s\n", str ); 84 | 85 | decrypt( str, key ); 86 | 87 | printf("%s\n", str ); 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /ch9/p15.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define NUL '\0' 4 | 5 | /* 6 | 用指针操作字符数组 7 | */ 8 | void dollars( char *dest, char const *src ) 9 | { 10 | int len; 11 | //判断指针是否为空,养成必要的习惯 12 | if( dest == NULL || src == NULL ) 13 | return ; 14 | 15 | *dest++ = '$'; 16 | len = strlen( src ); 17 | 18 | if( len >= 3 ) 19 | { 20 | int i; 21 | for( i = len - 2; i > 0; ) 22 | { 23 | *dest++ = *src++; 24 | if( --i > 0 && i % 3 == 0 ) 25 | *dest = ','; 26 | } 27 | } 28 | else 29 | *dest++ = '0'; 30 | 31 | *dest++ = '.'; 32 | *dest++ = len < 2? '0' : *src++; 33 | *dest++ = len < 1? '0' : *src; 34 | *dest = NUL; 35 | } 36 | 37 | int main(int argc, char const *argv[]) { 38 | char src[] = "111"; 39 | char dest[10]; 40 | dollars( dest, src ); 41 | printf( "%s", dest ); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /ch9/p2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define NUL '\0' 4 | 5 | size_t my_strnlen( char const *string , int size ) 6 | { 7 | int length = 0; 8 | for( ; length <= size; length++ ) 9 | if ( *string++ == NUL ) break; 10 | return length; 11 | } 12 | int main(int argc, char const *argv[]) { 13 | char string[10] = "sf"; 14 | printf("%ld\n", my_strnlen( string, 10 ) ); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch9/p3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define NUL '\0' 4 | 5 | char *my_strcpy( char * dst, char const *src, int size ) 6 | { 7 | strncpy( dst, src, size ); 8 | *(dst+size-1) = NUL; 9 | return dst; 10 | } 11 | int main(int argc, char const *argv[]) { 12 | char string[5] = "sdf"; 13 | char dst[10]; 14 | printf("%s\n", my_strcpy( dst, string, 10) ); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch9/p4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define NUL '\0' 4 | 5 | size_t my_strnlen( char const *string , int size ) 6 | { 7 | int length = 0; 8 | for( ; length <= size; length++ ) 9 | if ( *string++ == NUL ) break; 10 | return length; 11 | } 12 | 13 | int my_strcat( char *dst, char const *src, int size ) 14 | { 15 | int length = size-- - (int) my_strnlen( src, size ); 16 | if ( length > 0 ) 17 | { 18 | strncat( dst, src, length ); 19 | //dst[length] = NUL; 20 | } 21 | return length; 22 | } 23 | 24 | 25 | int main(int argc, char const *argv[]) { 26 | char dst[10] = "sfsds"; 27 | char src[2] = "sf"; 28 | 29 | printf("%u\n", my_strcat( dst, src, 10) ); 30 | printf("%s\n", dst ); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /ch9/p5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void my_strncat( char *dest, char *src, int dest_len ) 5 | { 6 | int length = (int) strlen( dest ); 7 | dest_len -= length + 1; 8 | if ( dest_len > 0 ) 9 | { 10 | strncat( dest, src, dest_len ); 11 | } 12 | } 13 | int main(int argc, char const *argv[]) { 14 | char dest[10] = "sdfdsf"; 15 | char src[2] = "ww"; 16 | my_strncat( dest, src, 10 ); 17 | printf("%s\n", dest ); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /ch9/p6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define NUL '\0' 4 | 5 | char *my_strcpy_end(register char *dest, register char *src ) 6 | { 7 | while ( (*dest++ = *src++ ) != NUL ); 8 | return dest--; 9 | } 10 | 11 | int main(int argc, char const *argv[]) { 12 | char dest[10] = "qwr"; 13 | char src[3] = "rew"; 14 | printf("%s\n", my_strcpy_end( dest, src )-strlen() ); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch9/p7.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define NUL '\0' 3 | char *my_strrchr( char *str, int ch ) 4 | { 5 | char *pre_answer = NULL; 6 | while( *str != NUL ) 7 | { 8 | if( *str == ch) 9 | pre_answer = str; 10 | str++; 11 | } 12 | return pre_answer; 13 | } 14 | 15 | int main(int argc, char const *argv[]) { 16 | char str[13] = "wqerwr"; 17 | int ch = 'w'; 18 | printf("%s\n", my_strrchr( str, ch ) ); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /ch9/p8.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define NUL '\0' 3 | 4 | char *my_strnchr( char *str, int ch, int which ) 5 | { 6 | int times = 0; 7 | 8 | while ( *str != NUL ) 9 | { 10 | if( *str == ch ) times++; 11 | if( times == which ) return str; 12 | str++; 13 | } 14 | 15 | return NULL; 16 | } 17 | 18 | int main(int argc, char const *argv[]) { 19 | char str[15] = "qerwwrwdsg"; 20 | char ch = 'w'; 21 | printf("%s\n", my_strnchr( str, ch, 3) ); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /ch9/p9.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int count_chars( char const *str, char const *chars ) 5 | { 6 | int counts = 0; 7 | 8 | while( ( str = strpbrk( str, chars ) ) != NULL ) 9 | { 10 | counts++; 11 | str++; 12 | } 13 | 14 | return counts; 15 | } 16 | 17 | int main(int argc, char const *argv[]) { 18 | char str[10] = "wqretwt"; 19 | char chars[3] = "qrr"; 20 | printf("%d\n", count_chars( str, chars ) ); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /ch9/test9.6.1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | int main(int argc, char const *argv[]) { 5 | int len1, len2; 6 | char buffer[] = "25,142,330,Smith,J,239-4123"; 7 | char *ptr = buffer + strspn( buffer, "\n\r\f\t\v"); 8 | len1 = strspn( buffer, "1" ); 9 | len2 = strcspn( buffer, "1" ); 10 | 11 | printf("len1 = %d, len2 = %d\n", len1, len2 ); 12 | printf("%s\n", ptr ); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch9/test9.6.2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void print_tokens( char *line ) 5 | { 6 | static char whitespace[] = " \t\f\r\v\n"; 7 | char *token; 8 | 9 | for( token = strtok( line, whitespace ) ; 10 | token != NULL; 11 | token = strtok( NULL, whitespace ) ) 12 | printf("%s\n", token ); 13 | } 14 | int main(int argc, char const *argv[]) { 15 | char str[] = "sdf sdfs sfe ewrwe\n dfgdg"; 16 | print_tokens( str ); 17 | return 0; 18 | } 19 | --------------------------------------------------------------------------------