1.编辑器设计者的金科玉律:效率(几乎)就是一切
2.阅读ANSIC标准 , 寻找乐趣和裨益
具体的ANSI C标准的规定我都不说了,从中看出 char * 类型是可以作为参数专递的,但是char** 是不行的,所以我们
传递多维数组的时候要表明确前n-1维的下标
3.容易混乱的const
int main(int argc, char* argv[]) { //定义基本类型的const变量,const 位置在哪儿都可以 const int x = 2,y = 3; //两个常量 //定义一个非const变量 int z = 3; //一个普通变量 //定义一个指向常的指针 const int* pc = &x; //指向常量的指针 //定义一个常指针 int* const cp = &z; //常指针 //定义一个非const指针 int* pp = &z; //int 型指针 pc = &z; //可以,pc是一个指向常量的指针,不能通过该指针去修改指针所指向的内存空间的值,但是,该指针可以指向别的变量 // *pc = 10; //不可以,*pc所指向的地址为const变量,其值不可更改 pc是一个指向常量的指针,不能通过该指针去修改指针所指向的内存空间的值 pc = pp; //可以,pc为指针,其值可被改变 pc是一个指向常量的指针,pp是一个普通指针,用一个普通指针给一个指向常量的指针赋值是可以的 // pp = pc; //用一个指向常量的指针,赋值给一个普通指针,不可以。如果可以,那么就可以通过普通的指针去修改内存的值 *cp = x; //可以,通过常指针去修改指针所指向变量的值是可以的 // cp = &x; //不可以,cp为常指针,指针的值不能被修改,给常指针赋值是错误的 // pp = &x; //不可以,pp是非const指针,原则上来讲给它赋值是可以的,在不同的编译器下有不同的结果 // pp = pc; //不可以,指向常量的指针不能赋值给一个普通的指针 pp = cp; //可以,常指针可以赋值给一个普通指针 const int * const pp = &a; //双const 既保护指针又保护内存变量 return 0; }
4.ASINC 手册重新编写了有关内容整型升级和寻常算数转换
注意: #define TOTAL_ELEMENTS ( int )( sizeof(array) / sizeof(array[0]) ) 必须加上(int)强制转换,不然运算的结果是个 unsigned int 类型,在程序中与有符号数运算时会发生意想不到结果
5. 错误断言
无论什么时候遇见 malloc(strlen(str)) 都是错误的
而 malloc(strlen(str) + 1) 是正确的
因为字符串处理包含了一个额外的空间,用于容纳字符串结尾的‘\0’
6. 一个‘L’的NUL 和 两个 ‘L’的NULL
7. switch 中case 后面不用break 97%都是错误的,而且default这单词如果写错的话,编译器是不检测的。
8. 在字符串数组在初始化的时候,如果不小心漏掉了一个逗号,编译器不会发出错误信息,而是悄无声息地把两个字符串合起来
#include<stdio.h> #include<string.h> #define TOTAL_ELEMENTS (int)(sizeof(str)/sizeof(str[0])) int main() { char *str[] = { "aaa", "bbb", "ccc", "ddd" "eee", }; printf("the length of the array is %d\n",TOTAL_ELEMENTS); for(int i = 0; i < TOTAL_ELEMENTS; i++) puts(str[i]); return 1; }
结果:
9. 使一段代码第一次执行的行为与以后执行时间不同(函数中申请静态变量)
10. i = 1, 2; 的结果是i 为多少呢?
赋值运算符的优先级高于逗号,所以 实际情况为: (i = 1), 2 , 所以i 最终的值为1
而 i = (1 ,2);的结果i 为2;
11.计算的次序
12 理解C的优先级规则
13 typedef 一些用法
14 typedef int x[10] 和 #define x int[10]的区别
a.用其他类型对宏类型名进行扩展,但typedef所定义类型名不能
#define peach int
unsigned peach i; // /* 没问题 */
typedef int banana
unsigned banana i; /*错误! 非法*/
b. 连续几个变量的声明中,用typedef定义的类型能够保证声明中所有的变量均为同一类型,而用#define定义的类型则无法保证.
#define int_ptr int *;
int_ptr chalk, cheese;
经过宏展开,变为 int * chalk , chese;// 发现chalk 和 chese 不是同一类型。
15
根据上面的思路写的解析声明的算法
#include<stdio.h> #include<string.h> #include<ctype.h> #include<stdlib.h> #define MAXTOKENS 100 #define MAXTOKENLEN 64 enum type_tay { IDENTIFIER, QUALIFIER, TYPE }; struct token { char type; char string[MAXTOKENLEN]; }; int top = -1; struct token stack[MAXTOKENS]; struct token this; #define pop stack[top--] #define push(s) stack[++top]= s enum type_tay classify_string() /*判断标示符类型*/ { char *s = this.string; if(!strcmp(s,"const")) { strcpy(s,"read-only"); return QUALIFIER; } if(!strcmp(s, "volatile")) return QUALIFIER; if(!strcmp(s, "void")) return TYPE; if(!strcmp(s, "char")) return TYPE; if(!strcmp(s, "signed")) return TYPE; if(!strcmp(s, "unsigned")) return TYPE; if(!strcmp(s, "short")) return TYPE; if(!strcmp(s, "int")) return TYPE; if(!strcmp(s, "long")) return TYPE; if(!strcmp(s, "float")) return TYPE; if(!strcmp(s, "double")) return TYPE; if(!strcmp(s, "struct")) return TYPE; if(!strcmp(s, "union")) return TYPE; if(!strcmp(s, "enum")) return TYPE; return IDENTIFIER; } void gettoken() /* 读取下一个标记到 "this" */ { char *p = this.string; /*略过空白字符*/ while((*p = getchar()) == ' '); if(isalnum(*p))/* 读入的标示符A-Z,0-9*/ { while(isalnum(*++p = getchar())); ungetc(*p,stdin); *p = '\0'; this.type = classify_string(); return; } if(*p == '*') { strcpy(this.string, "pionter to"); this.type = '*'; return; } this.string[1] = '\0'; this.type = *p; return; } /*理解所有分析过程的代码*/ void read_to_first_identifier() { gettoken(); while(this.type != IDENTIFIER) { push(this); gettoken(); } printf("%s is ", this.string); gettoken(); } void deal_with_arrays() { while(this.type == '[') { printf("array"); gettoken(); /* 数字或']'*/ if(isdigit(this.string[0])) { printf("0..%d ", atoi(this.string) - 1 ); gettoken(); /* 读取']'*/ } gettoken(); /* 读取']'之后的再一个标记*/ printf("of "); } } void deal_with_function_args() { while(this.type != ')') { gettoken(); } gettoken(); printf("function returning "); } void deal_with_pointers() { while(stack[top].type == '*') { printf("%s ",pop.string); } } void deal_with_declarator() { /*处理标识符之后可能存在的数组/函数*/ switch(this.type) { case '[': deal_with_arrays(); break; case '(': deal_with_function_args();break; } deal_with_pointers(); /*处理在读入到标识符之前压入到堆栈中的符号*/ while(top >= 0) { if(stack[top].type == '(') { pop; gettoken(); /* 读取')'之后的符号 */ deal_with_declarator(); } else { printf("%s ",pop.string); } } } int main() { /* 将标记压入堆栈中, 知道遇到标示符*/ read_to_first_identifier(); deal_with_declarator(); printf("\n"); return 0; }