1. = 不同于 ==
2. & 和 | 不同于 && 和 ||
3. 编译器将程序分解成符号的方法是,从左到右一个一个读,直到读入的字符组成的字符串已不在可能组成一个有意义的符号,贪心的处理程序。如a --- b编译器就会认为是 a-- - b,而不是认为a - --b。
4. 整数常量,如果一个整型常量第一个字符是0,那么该变量会被认为是8进制数。
5. 单引号引起的一个字符实际上代表一个整数,‘a’与0141和97是严格一致的。双引号引起的字符创代表的是一个指向无名数组其实字符的指针,该数组被双引号之间的字符以及一个额外的‘\0’初始化。一个代表整数一个代表指针,所以混用编译器会报错。
6. 任何C变量的声明都由两部分组成,类型以及一组类似表达式的声明符。
7. 运算符优先级问题,解决办法就是加括号。但最好是记住c语言中运算符的优先级。
(1) 任何一个逻辑运算符优先级均低于一个关系运算符。
(2) 移位运算符的优先级比算术运算符优先级要低,但比关系运算法优先级要高。
8. 注意作为语句结束符的分号 ;
9. Switch语句,case后一定要写break; 否则它会一直执行下去。
10. 调用函数的时候,即使没有参数后面也要有括号。如f();
11. Else语句始终与同一括号内最近未匹配的if相结合。所以如果if和else使用的时候要注意添加大括号。
12. 指针与数组,C语言中只有一位数组,而且数组的大小必须在编译器就作为一个常数确定下来。我们只能做两件事,确定该数组的大小和获得指向该数组下标为0的元素的指针。任何一个数组下标的运算都等同于一个对应的指针运算。
Calendar[month][day] = 0;
*(*(Calendar + month) + day) = 0;
//上述二者其实是等价的
int month;
for (month = 0 ; month < 12 ; month ++)
{
int day;
for (day = 0 ; day < 31 ; day ++)
{
calendar[month][day] = 0;
}
}
int (*monthp)[31];
for (monthp = calendar ; monthp < &calendar[12] ; monthp ++)
{
int *dayp;
for (dayp = *monthp ; dayp < &(*monthp)[31] ; dayp ++)
{
*dayp = 0;
}
}
//上述二者其实是等价的
13. 非数组指针
//将s和t两个字符串合并为一个字符串r
char *r,*malloc();
r = malloc(strlen(s) + strlen(t) + 1);
if(!r){complain();exit(1);}
strcpy(r , s);
strcat(r , t);
……//一段时间之后进行释放
free(r);
14. 作为参数的数组声明,实际上数组名会被转换成指向该数组的第一个元素的指针进行传递。
15. 当指针相互赋值的时候,实际上传递的是这个数组的首地址,也就是说两个指针指向内存中同一地址。改变其中一个指针时另外一个也会改变,因为他们是指向相同地址。
16. 空指针并非空字符串
17. 仔细计算边界,C语言中数组的下标是从0开始计算。用第一个入界点和第一个出界点来表示一个数值范围。
18. 求值顺序,C语言只有四个运算符(&&、||、?: 、,)存在规定的求值顺序,运算符&&和||首先对左侧操作数求值,只有需要时才对右侧操作数求值。运算符a?b:c中操作数a首先被求值,根据a的值再求操作数b或者c的值。而逗号运算符首先对左侧操作数求值,然后该值被丢弃再对右侧操作数求值。
19. 运算符&&、||、和!
对操作数的处理方式是将其视作要么为真要么为假,通常视0为假,而非0为真。
运算符&、| 和 ~
对操作数的处理方式是将其视为一个二进制的位序列,分别对其每个位进行操作。
20. 整数溢出,在无符号数中是没有溢出的概念的,只有两个操作数都为有符号整数时,溢出才有可能发生。可以将其都转换为无符号数来运算。
21. 为函数main提供返回值,返回值为0则代表程序运行成功,返回值为非0则表示程序执行失败。
22. 连接
一个C程序可能有多个分别编译的部分组成,这些不同的部分通过连机器的程序组成一个整体。
Lint这个程序就是检查连接过程中错误的程序应该重视,并且善加利用。
23. C语言中一个重要思想就是分别编译,即若干的源程序可以在不同的时候单独进行编译,然后在恰当的时候整合在一起。编译器会生成若干的目标模块,连接器通常将目标模块看成一组外部对象组成的。每个外部对象代表着及其内存中的某个部分,并通过一个外部名称来识别,连接器的输入是一组目标模块和库文件,连接器的输出是一个载入模块,因为连接器对C语言知之甚少,所以有很多错误不能被检测出来,lint程序一定要使用。
24. 声明和定义
int a;//定义a的变量
extern int a;//实际上是一个声明,对外部变量a的引用
每个外部变量最只定义一次,因为定义多次引用会出错。
25. 命名冲突与static修饰符
static int a;将a的作用域限制在一个源文件中,对于其他源文件来说a是不可见的。因此如果若干个函数需要共享一组外部对象,可以将这些函数放在一个源文件中,把它们需要用到的对象也都在一个源文件中以static修饰符声明。同样static不仅适用于变量,也适用于函数。有了static之后就不用担心多个源文件中有相同函数名了。
26. 形参、实参与返回值
任何函数都有一个形参列表,列表中的每一个参数都是一个变量,该变量调用过程中被初始化。对于某些函数来说形参列表为空,函数调用时将实参列表传递给被调用的函数。
如果一个函数在被定义和声明之前被调用,那么它的返回类型默认为整型。
27. 检查外部类型
假设我们有一个C程序,它由两个源文件组成,一个文件中包含外部变量n的声明 extern int n;另一个文件中包含 long n;这是一个无效的程序,但是有的C编译器可能检测不出这种问题。
28. 头文件
每个外部对象只在一个地方声明,这个声明的地方一般就在一个头文件中,需要用到该外部对象的所有模块都应该包含这个头文件,一定要注意定义该外部对象的模块也应该包含这个头文件。
29. 返回整数的getchar函数
一般情况下返回的是标准输入文件中的下一个字符,无输入时返回EOF。
30. 读写操作不能同时
如果想同时读写,那么必须在其中插入fseek函数的调用。
fseek(文件指针,从起始位置跳过多少字节,起始位置)
31. 缓存输出与内存分配
程序的输出有两种方式,一种是即时处理,另一种是先暂存起来,然后再大块写入。
setbuf(stdout,buf);语句将通知输入/输出库,所有写入到stdout的输出都应该使用buf作为输出缓冲区,直到缓冲区满或者调用fflush的时候才将文件实际写入stdout中。缓冲区的大小有头文件stdio.h中的BUFSIZ定义。
将buf数组定义为静态,或者放在main函数之外,再或者使用动态分配setbuf(stdout,malloc()); main函数结束之后,C运行时库会进行清理工作,如果设置为普通数组,main结束之后就被释放了,当运行时库再次释放的时候就会报错。
32. 库函数signal
作为捕捉异步事件的一种方式,要是用该库函数需要在源文件中加上#include<signal.h>要处理一个特定的信号,可以这样调用
signal(signal type,handler function);
signal type代表要捕捉的信号类型
handler function当事件发生时,将要加以调用的事件处理函数
信号非常棘手,尽量让处理函数简单,我们可以很容易修改。
33. 宏定义中的空格
#define f (x) ((x)-1)代表的意思就是,f等价于(x) ((x)-1),所以空格神马的一定要注意,这一点不适用于宏调用,只对宏定义适用。
正确的定义方式#define f(x) ((x)-1)
34. 宏不是函数
宏定义中的括号它们的作用是预防引起与优先级有关的问题。
35. 宏不是语句
考虑一下assert宏,它的参数是一个表达式,如果该表达式为0,则使程序终止执行,并给出一条出错信息。定义之后可以将其还原带程序中,看其是否有问题。
36. 宏并不是类型定义
#define FOOTYPE struct foo
FOOTYPE a;
FOOTYPE b,c;
这样的用法有一个优点就是可移植性,但最好还是使用类型定义
typedef struct foo FOOTYPE;
37. 字符是有符号数还是无符号数
使用语句(unsigned char)c,一个unsigned char类型的字符可以直接转换为无符号数。
38. 移位运算符
如果被移位的对象长度是n位,那么移位计数必须大于或等于0,而严格小于n。因此不肯那个做到在单次操作中将某个数值的所有位都移出,加上这个限制条件,我们就能在硬件上更高效的实现移位运算。
39. 内存位置0
null指针并不指向任何对象,因为有的机器不允许读内存为0的地方,而有的机器可以读内存为0的地方,所以就导致程序移植到另一台机器就会出现问题。
40. 首先释放,然后重新分配
大多数C语言实现都为使用者提供了3个内存分配函数:malloc、realloc、free。调用malloc(n)将返回一个指针,指向一个新分配的可以容纳n个字符串的内存,将malloc返回的指针作为参数传入free的时候,就释放了这块内存。调用realloc函数的时候,需要把指向已分配内存指针以及这块内存新的大小作为参数传入,就可以调整这块新区域的内存大小了。
原文地址:http://blog.csdn.net/djd1234567/article/details/45312281