一、编程技巧:
1.为了避免在需要比较时误用了赋值符号,可以将条件判断语句if(i==3)
改写成if(3==i)
,并将之保持下去。
2.宏最好只用于命名常量,并为一些适当的结构提供简捷的记法。宏名应该大写。
3.实参char* s与形参const char *p
是相容的,但实参char **argv与形参const char **p
是不相容的。
4.关键字const
并不能把变量变成常量。它最有用之处就是用来限定函数的形参,这样该函数将不会修改实参指针所指的数据,但其他的函数却可能会修改它。
5.const
和*
的组合通常只用于在数组形式参数中模拟传值调用。它表示“我给你一个指向它的指针,但你不能修改它”。
6.当执行算术运算时,操作数的类型如果不同,就会发生转换。数据类型一般朝着浮点精度更高、长度更长的方向转换,整型数如果转换为signed
不会丢失信息,就转换为signed
,否则转换为unsigned
。
7.尽量不要在你的代码中使用无符号类型。
8.ACSII
字符中零的位模式被称为NUL
。表示哪里也不指向的特殊的指针值则是NULL
。
9.当想要让某个类型全局可见时,应当采用显式的手段。
10.当sizeof
的操作数是个类型名时,两边必须加上括号,但操作数如果是变量则不必加括号。
11.如果觉得C语言的优先级规则比较麻烦的话,可以牢记两个优先级就够了:乘法和除法先于加法和减法,在涉及其他操作符时一律加上括号。
12.在函数调用中,各个参数的计算顺序是不确定的。
13.由于gets()
函数在读入字符时并不检查缓冲区的空间,所以是极其不安全的。强烈建议使用fgets()
函数彻底取代gets()
的使用。
14.函数和数组的一些声明:
- 函数的返回值允许是一个函数指针,如:
int(*fun())()
; - 函数的返回值允许是一个指向数组的指针,如:
int(*foo())[]
; - 数组里边允许有函数指针,如:
int(*fun[])()
; - 数组里边允许有其他数组,如:
int foo[][]
;
15.一般情况下,建议将变量的声明与类型的声明分开,以便后期维护。
16.很少有什么事只能靠枚举来完成而用#define
不能解决。但枚举有一个优点,#define
定义的名字一般在编译时被丢弃,而枚举名字则通常一直在调试器中可见,可以在调试代码时使用它们。
17.简单的C语言声明优先级规则:
- A.声明从它的名字开始读取,然后按照优先级顺序依次读取。
- B.优先级从高到低依次为:
b1.声明中被括号括起来的那部分
b2.后缀操作符:
括号()
表示这是一个函数,而方括号[]
表示这是一个数组。
b3..前缀操作符:*
表示“指向…的指针”。 - C.如果
const
和volatile
关键字的后面紧跟类型说明符(如int),那么它作用于类型说明符。其他情况下,const
和volatile
关键字作用于它左边紧邻的指针星号。
18.typedef(存储类型说明符)
和宏的区别:
- 可以用其他类型说明符对宏类型名进行扩展,但对
typedef
所定义的类型名却不能这样做。 - 在连续几个变量的声明中,用
typedef
定义的类型能够保证声明中所有的变量均为同一种类型,而用#define
定义的类型则无法保证。
19.不要为了方便起见对结构使用typedef
(因为struct
这个关键字可以为我们提示更多信息 )。它一般用在数组、结构、指针以及函数的组合类型,或者为了满足代码的可移植性。
20.声明相当于普通的声明:它所说明的并非自身,而是描述其他地方的创建的对象。定义相当于特殊的声明:它为对象分配内存。
21.当在一个文件中定义数组,而在另一个文件将其声明为指针时,指针和数组严格区分,两者不能混为一谈。
22.初始化指针所创建的字符串常量被定义为只读,不允许修改。与指针相反,由字符串常量初始化的数组是可以修改的。
23.不要让程序中的任何符号成为全局的,除非有意把它作为程序的接口之一。
24.如果想要返回一个指向函数内部定义的变量的指针时,要把那个变量声明为static
。
25.所有作为函数参数的数组名总是可以通过编译器转换为指针。当一个数组名出现在一个表达式中时,它会被转换为一个指向该数组第一个元素的指针。
其他还有很多需要注意的地方,在此不一一列出,如果对C语言的基础知识还存在疑惑,可以随时call我。