1. 内存中的每个位置都由一个独一无二的地址标识;
2. 内存中的每个位置都包含一个值。
3. 变量名字与内存位置之间的关联并不是硬件来提供,而是由编译器为我们实现的。变量给了我们一种更方便的方法记住地址----硬件仍然通过地址访问内存位置。
4. 指针的初始化时用&操作符完成的,该操作数用于产生操作数的内存地址。
5. 通过一个指针访问它所指向的地址的过程称为间接访问或解引用指针。这个用于执行间接访问的操作符是单目运算符*。
6. 指针变量和其他变量并无区别,如果变量是静态的,它会被初始化为0;如果变量是自动的,它根本不会被初始化。无论哪种情况,声明一个指向整型的指针都不会“创建”用于存储整型值的内存空间。因此,在对指针进行间接访问前必须非常小心,确保它们已被初始化。
7. NULL指针。标准定义了NULL指针,它作为一个特殊的指针变量,表示不指向任何东西。要使一个指针变量为NULL,可以给它赋一个零值。为了测试一个指针变量是否为NULL,可以将它与零值进行比较。
8.对指针变量进行间接访问表示我们应该访问指针所指向的位置。
9. 将一个整型数(或者浮点数)存储于一个指针变量中,是非法的。
10. *100 = 25;(100是一个地址,但是该语句是非法的,因为间接访问只能作用于指针类型表达式,而字面值100的类型是整型)。 *(int *)100 = 25;(这样的表达才是合法的,强制类型转换把100从整型转换为指向整型的指针)。
11. 指针的指针
int a = 12;
int *b = &a;
int **c = &b;
指针变量和其他变量一样,占据内存中某个特定的位置,所以用&操作符取得它的地址是合法的。
12. 指针运算
指针 ± 整数
对指针执行加法或者减法运算之后,如果结果指针所指的位置在数组第1个元素的前面或者在数组最后一个元素的后面,那么其效果就是未定义的。让指针指向数组最后一个元素后面的那个位置是合法的,但是对这个指针执行间接访问可能会失败。
指针 - 指针
只有当两个指针都指向同一个数组中的元素时,才允许从一个指针减去另一个指针。减法运算的值时两个指针在内存中的距离,以数组元素的长度为单位,而不是以字节为单位。如果两个指针所指向的不是同一个数组中的元素,那么它们之间相减的结果是未定义的。
越界指针和指向未知值的指针是两个常见的错误根源。使用指针运算时,必须非常小心,确信运算的结果将指向有意义的东西。
关系运算
对指针执行关系运算也是有限制的,可以用 < <= > >= 对两个指针值进行比较。不过前提是它们都指向同一个数组中的元素。根据所使用的操作符,表达式将告诉你哪个指针指向数组中更靠前或者更靠后的元素。标准并未定义如果两个任意指针进行比较时会产生什么结果。
标准允许指向数组元素的指针与指向数组元素后面的哪个内存位置的指针进行比较,但不允许与指向数组第一个元素之前的那个内存位置的指针进行比较。
数组与指针
数组下标问题:如果可以互换地使用指针表达式和下标表达式,那么应该怎么选择?假定这两种方法都是正确的,下标绝不会比指针更有效率,但指针有时会比下标更有效率。如下例子:
int array[10], a;
for(a = 0;a < 10;a += 1)
array[a] = 0;
int array[10], *ap;
for(ap = array;ap < array + 10;ap ++)
*ap = 0;
对下标表达式求值,取得a的值,并把它与整型的长度(也就是4)相乘,这个乘法需要花费一定的时间和空间。初始地址+整形长度*a,也就是说每次都会需要一个加法和一个乘法运算。
在指针表达中,每次地址增加的长度是固定的,就是一个整型长度,它只需要一个加法运算。