第6章 指针
6.1 简介
6.2 收获
6.2.1 指针的图形表示方法
1 | int a = 112, b = -1; |
6.2.2 严禁向未初始化的指针变量赋值
1 | // 这是非法的 |
6.2.3 关于空指针NULL
为了测试一个指针变量是否为NULL
,你可以将它与零值进行比较。之所以选择零这个值是因为一个源代码约定。就机器内部而言,NULL指针的实际值可能与此不同。在这种情况下,编译器将负责零值和内部值之间的翻译转换。
尽管这个技巧在C程序中极为常用,但它违背了软件工程的原则,用一个单一的值表示两种不同的意思是件危险的事,因为将来很容易无法弄清哪个才是它真正的用意。在大型程序中,这个问题更加严重,因为你不可能在头脑中对整个设计一览无余。一种更为安全的策略是让函数返回两个独立的值:首先是个状态值,用于提示查找是否成功;其次是个指针,当状态值提示查找成功时,它所指向的就是查找到的元素。
不要对空指针NULL
进行间接访问
6.2.4 指针、间接访问和变量的一些事
1 | *&a = 25; //没意义的代码,a = 25 |
不要指针!和整数运算!混用!!!!!
1 | *d = 10 - *d; //合法,但不要这样用! |
6.2.5 嘿嘿嘿,编译器,错误和警告
当我们实际使用的变量类型和应该使用的变量类型不一致时,编译器会发出抱怨,帮助我们判断这种情况。这些警告和错误信息是我们的朋友,编译器通过产生这些信息向我们提供帮助。尽管被迫处理这些信息是我们很不情愿干的事情,但改正这些错误(尤其是那些不会中止编译过程的警告信息)确实是个好主意。在修正程序方面,让编译器告诉你哪里错了比你以后自己调试程序要方便得多。调试器无法像编译器那样准确地查明这些问题。
6.2.6 指针的指针
1 | int a = 12; |
1 | int a = 12; |
6.2.7 指针表达式
运算的左值和右值
左值需要一个存储的地址,要求多
右值
一些操作:
fig1: 指针变量
fig2: 取地址符
fig3: 间接访问符
fig4:
*
的优先级高于+
,先执行间接访问操作,我们就可以得到它的值,再加1,得到最终结果为字符'b'
fig5: 先地址加1,再间接访问
fig6: 先地址加1,再将更新后的地址赋给左值。表达式的结果是增值后的指针的一份拷贝。这份拷贝的存储位置并未清晰定义,所以它不是一个合法的左值。
fig7: 它先返回cp值的一份拷贝然后再增加cp的值
fig8: 增加间接访问符后,左值就合法了。间接访问操作符作用于增值后的指针的拷贝上,所以它的右值是ch后面那个内存地址的值,而它的左值就是那个位置本身
fig9:
++
操作符的优先级高于*
。1)++操作符产生cp的一份考本;2)然后++操作符增加cp的值;3)最后,在cp的拷贝上执行间接访问操作。
fig10: 在这个表达式中,由于这两个操作符的结合性都是从右向左,所以首先执行的是间接访问操作,然后,cp所指向的位置的值增加1,表达式的结果是这个增值后的值的一份拷贝。
6.2.8 指针运算
算术运算
第一种:指针 ± 整数
标准定义这种形式只能用于指向数组中某个元素的指针,并且这类表达式的结果类型也是指针。这种形式也适用于使用malloc
函数动态分配获得的内存。
第二种:指针 - 指针
只有两个指针都指向同一个数组中的元素时,这才是允许的。返回两个指针之间的距离。
关系运算
<
<=
>
>=
使用关系操作符的前提,它们都指向同一个数组中的元素
6.2.9 警告的总结
- 不要对一个未初始化的指针变量进行解引用
- 不要对一个NULL指针进行解引用
- 不要向函数错误地传递NULL指针
- 未检测到指针表达式的错误,会导致不可预料的结果
- 对一个指针进行减法运算,使它非法地指向了数组第1个元素的前面的内存位置。
6.2.10 编程好习惯
- 一个值应该只具有一种意思
- 如果指针并不指向任何有意义的东西,就把它设置为NULL