- 指针:计算机内存中的每个位置都由一个地址标识。通常,临近的内存位置合成一组,这样就允许存储更大范围的值,指针变量就是它的值表示内存地址的变量。
- 声明变量:
int a = 112, b = -1;
float c = 3.14;
int *d = &a;
float *e = &c;
变量d和e声明为指针变量,并用其他变量的地址予以初始化。d和e的内容是地址而不是整型或浮点型数值。从图中可以看出d的内容与a的存储地址一致,而e的内容与c的存储地址一致,这是我们对这两个指针进行初始化时所期望的结果。
注意:不能简单的认为由于d和e是指针,所以它们能自动获得存储于位置100和108的值(即112和3.14),因为变量的值就是分配给该变量的内存位置所存储的数值(即100和108),即使是指针变量也不例外,只不过变量d所指向的位置(100)所存储的值是112,同理e也一样。
- 未初始化的指针
int *a;
*a = 100;
在声明指针变量a时未对其进行初始化,那么无法预测100这个值将会存储于什么地方。如果a的初始值是个非法的地址,那么这条赋值语句辉直接报错从而终止程序;如果a指向的是一个合法的地址,那么这条复制语句将会改变那个地址的指,这可能会导致程序的运行结果不是按照预想的结果运行,这将会很难去排查到问题所在。因此务必要注意的时,在对指针进行访问之前,确保指针已被初始化。
-
NULL指针
NULL指针是一个特许的指针变量,表示不指向任何东西。要使一个指针变量为NULL,可以给它赋值为0。
NULL指针表示某个特定的指针目前并未指向任何东西。例如,一个用于在某个数组中查找某个特定值的函数可能返回一个指向查找到的数组元素的指针。如果该数组不包含指定条件的值,函数就会返回一个NULL指针。
注:对NULL指针进行解引用将发生报错并终止程序。 -
指针常量
假定变量a存储于位置100,则下面语句的作用是什么?
*100 = 25;
/*这条语句看起来是把25赋值给变量a,因为a是位置100所存储的变量。
**但是这条语句实际上是非法的,因为字面值100的类型是整型,而间接访问操作只能作用于指针类型表达式。
**如果确实想把25存储于位置100,则必须使用强制类型转换*/
*(int *)100 = 25; //强制类型转换把值100从整型转换为“指向整型的指针”,此时该语句才是把25赋值给变量a
- 指针运算
当一个指针和一个整数执行算术运算时,整数在执行加法运算前始终会根据合适的大小进行调整。这个“合适的大小”是指针所指向类型的大小,“调整”是把整数值和“合适的大小”相乘。指针运算结果如下:
数组中的元素存储与连续的内存位置中,对一个指针加1使它向右移动1个元素,把一个指针减1使它向左移动1个元素。对指针进行加减法之后如果结果指针所指的位置在第一个元素前面或在数组最后一个元素的后面,那么其结果是未定义的。让指针指向数组最后一个元素后面的那个位置是合法的,但是对这个指针进行间接访问可能会失败;指向数组第一个元素前面的那个位置就是非法的。
只有当两个指针都指向同一个数组中的元素时,才允许从一个指针减去另一个指针。减法运算的值时两个指针在内存中的距离(以数组元素的长度为单位,而不是以字节为单位,因为结果将除以数组元素类型的长度)。
#define NUM 5
int values[NUM];
int *vp;
for(vp = &values[0]; vp < &values[NUM];)//从前往后对数组的每个元素清0
*vp++ = 0;
for(vp = &values[NUM]; vp > &values[0];)//从后往前对数组的每个元素清0
*--vp = 0;
标准允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针进行比较,但不允许与指向数组第一个元素之前的那个内存位置的指针进行比较(虽然在大多数C编译器中最后能正常运行,但是尽量避免)。
- 注意点
(1)错误地对一个未初始化的指针变量进行解引用
(2)错误地对一个NULL指针进行解引用
(3)向函数错误地传递NULL指针
(4)未检测到指针表达式的错误,从而导致不可预料的结果
(5)对一个指针进行减法运算,使它非法的指向了数组第一个元素的前面的内存位置
该文引用《C和指针》。