(三)知识准备
C语言数组和指针的关系极其密切。通过指针访问数组元素的机制是C语言特有的。一个变量有地址,一个数组包含多个元素,每个数组元素在内存中当然都有相应的地址。指针变量可以指向变量,也可以指向数组元素(把数组的一个元素的地址存放到一个指针变量中)。数组元素的指针就是数组元素的地址。
以上程序使指针p指向数组a的第0号元素,如图8-21所示。
图8-21 指针p指向数组
引用数组元素可以使用下标法(如a[0]、a[1]、a[2]、a[3]、a[4]),也可以使用指针法,即通过指向数组元素的指针找到所需的元素。使用指针法能够使程序质量更高,占用内存少,运算速度快。
在C语言中,数组名(比如上面的数组名a)代表数组中首个元素的地址(即第0号的元素a[0]的地址)。
因此,下面两个语句等价:
语句p = a;的作用是:把数组的首个元素的地址,即a[0]的地址赋给指针变量p。
1.指针变量加减整数
当指针已经指向一个数组元素时,可以对指针进行以下运算:
① 加一个整数,比如p + 1;。
② 减一个整数,比如p-1;。
③ 自加运算,比如p + + ;, + + p;。
④ 自减运算,比如p-- ;,-- p;。
⑤ 两个指针相减,比如p1 – p2(只有指向同一个数组的元素时,才有实际意义)
假设:
int a[10] = {1,2,3,4,5,6,7,8,9,10}; /*定义int数组*/
int *p; /*定义int型指针变量p*/
p = &a[2]; /*把a[2]的地址赋给p,p指向a[2]*/
说明如下:
① 以上程序使指针p指向数组a的元素a[2],则p + 1指向该数组a中的下一个元素,即a[3];p-1指向该数组a中的上一个元素,即a[1]。
注意:执行p + 1,不是将p的值(一个地址)简单地加1,而是加上一个数组元素所占内存的字节数。在上述程序中,数组a的元素是int类型,在Keil中,int型元素占2个字节,所以,p + 1就是p的值(一个地址)加2个字节,使p指向下一个元素,如图8-22所示。
指针的自加运算(p + + ;, + + p;)的执行过程类似于p + 1;。
指针的自减运算(p-- ;,-- p;)的执行过程类似于p-1;。
② 如果指针p指向数组的首元素a[0],则p + j和a + j都是数组元素a[j]的地址,即p + j和a + j指向数组a中序号为j的元素,如图8-23所示。
图8-22 指针p指向数组a
图8-23 指针p、数组名a指向数组a
注意:a代表数组首元素的地址,即a[0]的地址。
③ *(p + j)、*(a + j)是p + j、a + j所指向的数组元素a[j]。例如,*(p + 5)、*(a + 5)就是a[5]。
④ 如果指针变量p1和p2都指向同一数组中的元素,执行p2-p1,表示p2所指向的元素与p1所指向的元素之间相差的元素个数。
例如:
注意:两个地址不能相加,如p2 + p1没有实际意义。
2.通过指针引用一维数组元素
通过指针引用一维数组元素需要一个指向数组元素的指针变量,它的基类型与数组元素的类型相同。
通过指针引用数组元素是C语言提供的一种高效数组访问机制。
假设指针p指向数组a某元素的地址,则:
*p = 5;将对应数组元素赋值5。
p + 1或(p + + )也是指针,指向数组下一个元素。
p + 5指向p所指元素之后第五个元素。
p-1指向p所指元素的前一个元素。
指针有效范围必须满足数组空间的限制,避免越界访问。这个问题与数组下标越界问题的控制同样重要。
当指针p指向s数组的首地址时,表示数组元素s[i]的表达式也可以是p[i]。实际上,p不一定要指向s的首地址,如果p = &s[2];,即p指向s[2],则p + 3指向s[5],p[3]引用的数组元素是s[5]。
至此,有5种表示s数组元素s[i]的方法:
● s[i]
● *(s + i)
● *(p + i)
● p[i]
● p指向s[i],使用*p表示s[i]
3.数组名和地址关系
数组名在C语言中被处理成一个地址常量,也就是数组所占连续存储单元的起始地址,一旦定义,数组名永远是数组的首地址,在其生存期不会改变。
不能给数组名重新赋值,但可以用在数组名后加一个整数的办法,依次表达数组中不同元素的地址。
例如:
a与&a[0]是等价的,a[1]的地址是a + 1,可用&a[1]表示。
对数组元素a[3],可以用*(a + 3)来引用,也可以用*&a[3]来引用。