首页 > 代码库 > C和指针 (pointers on C)——第六章:指针(上)

C和指针 (pointers on C)——第六章:指针(上)

第六章 指针


这一章,就明显触痛初学者敏感之处了。我也是在一段时间不用C以后就会对这一部分生疏,好吧,其实是对高级指针那块生疏。
当然这一部分总有很多借鉴之处,比如数组范围的问题等,要不我也不会大夏天的这么虐自己看这种书。


总结:
指针变量的值并非它所指向的内存位置所存储的值,而是保存了指向的变量的地址。需要通过间接访问符*来访问指向的变量的值。
单单声明一个指针,而并不进行初始化,是不会分配内存的。所以在指针执行间接访问之前,指针必需进行初始化。
要么指向某个变量、要么去malloc一个内存。
NULL指针就是不指向任何东西的指针。除了NULL指针之外,再也没有任何内建的记法标识指针常量。除非是用 volatile 0x00...这么命名,这在现在PC系统看来是不可想象的。在极少见的情况下,我们偶尔需要用到指针常量。
指针可以作为一个左值来用,因为指针标识了一个特定内存位置。
比如: ptr = ¶  
          *ptr = para;
在指针值上可以执行一些有限的算术运算。你可以把一个整型值加到一个指针上,也可以从一个指针减去一个整型值。在这两种情况下,这个整型值会进行调整,原值将乘以指针目标类型的长度。
需要注意的是,指针的大小就是一个字节,因此对一个指针加1,让它指向下一个空间,这与该指向的变量是float double没有半毛钱的关系。
指针间的相互运算,只有用于数组之中其结果才是可以预测的,对于那些非数组元素的运算,最好不要去用,肯定是非法的,只不过IDE没有报错。
当减法的时候,如果指针指向数组首元素之前的位置,非法。
当加法的时候,如果指针指向数组末元素之后的一个位置,合法,但再往后,非法。一般不要触碰这个底线。
如果两个指针都指向同一个数组的元素,它们可以相减,表示数组中相隔多少个元素。
如果两个指针不指向同一个数组,那么它们相减是错误的。
关于关系运算,最简单最常见的是测试它们相等或者不相等。
如果两个指针都指向同一个数组的元素,那么它们还可以用>=,>,<,<=这几个元素。


警告:
1、错误地对一个未初始化的指针变量进行解引用。
int *a;
...
*a = 12;
a指向一个位置量,如果a是静态的,那么它会被初始化为0,如果a是自动的,那么它不会被初始化,无论哪种情况,仅仅声明一个指针变量是不会开辟一个内存空间。
window比较温柔,一般就是终止程序,倒霉的时候会产生保护性异常(General Protection Exception)。unix里面管其叫做 memeory fault,它提示程序试图访问一个未分配给程序内存的位置。
一定要注意,在调用指针时候,确保它们已经被初始化。
2、错误地对一个NULL指针进行解引用。
int *a;
a = NULL;
temp = *a; //wrong!
3、向函数错误地传递NULL指针。  
这种错误纯属活该,在传递之前,必需检测函数的有效性。
4、未检测到指针表达式的错误,从而导致不可预料的结果。
比如:当声明一个指针的时候,如果已经知道被初始化什么地址了,就初始化,否则就初始化为NULL,这是个好事,大大节省调试时间。
5、对一个指针进行减法运算,使它非法地指向了数组第一个元素的前面的内存位置。
见上!


编程提示:
1、一个值应该只具有一种意思。
2、如果指针并不指向任何有意义的东西,就把它设置为NULL。


问题?
5、 int i[10];
      int *p = & i[0];
      int offset;
      p += offset ; (a)
      p += 3;         (b)
a/b区别是什么?
答:求值过程没有区别,但是a多一步数组越界的检查。
6、int array[ARRAY_SIZE];
     int *pi;
     for( pi = &array[0]; pi < &array[ARRAY_SIZE];)
*++pi = 0;
错误在哪?
答:目的是将array数组清零,但是array[0]没有清零,因为++前缀了。同时,多清了一个零,array[ARRAY_SIZE-1]后面一个内存空间也被清零了。