首页 理论教育 C语言程序设计:一维数组元素指针的应用

C语言程序设计:一维数组元素指针的应用

时间:2023-10-29 理论教育 版权反馈
【摘要】:如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。如果指针变量p1和p2都指向同一数组,如执行p2-p1,结果是两个地址之差除以数组元素的数据类型的长度。假设p2指向整型数组元素a[5],p2的值为2020;p1指向a[3],其值为2012,则p2-p1的结果是/4=2。这个结果是有意义的,表示p2所指的元素与p1所指的元素之间差2个元素。第一个for循环语句结束后,p已经指向了a数组末尾。

C语言程序设计:一维数组元素指针的应用

p、a、&a[0]均指向同一单元,它们是数组a的首地址,也是0号元素a[0]的首地址。p+1、a+1、&a[1]均指向1号元素a[1]。类推可知p+i、a+i、&a[i]指向i号元素a[i]如图7.7。应该说明的是p是变量,而a、&a[i]都是常量。

(1)如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。

需要注意:执行p+1时并不是将p的值(地址)简单地加1,而是加一个数组元素所占用的字节数。如果数组元素是int型,每个元素占4个字节,则p+1意味着使p的值(是地址)加4个字节,以使它指向下一元素。p+1所代表的地址实际上是p+1×d,d是一个数组元素所占的字节数,若p的值是2000,则p+1的值不是2001,而是2004。

(2)如果指针变量p的初值为&a[0],则p+i和a+i就是数组元素a[i]的地址,或者说,它们指向a数组的第i个元素。这里需要注意的是a代表数组首元素的地址,a+i也是地址,它的计算方法同p+i,即它的实际地址为a+i×d。

例如:

p+9和a+9都指向a[9],或者说它们的值都是&a[9]。

(3)*(p+i)或*(a+i)是p+i或a+i所指向的数组元素,即a[i]。

例如:

*(p+5)或*(a+5)就是a[5],也就是说*(p+5)、*(a+5)和a[5]三者等价。

实际上,在编译时,对数组元素a[i]就是按*(a+i)处理的,即按数组首元素的地址加上相对位移量得到要找的元素的地址,然后找出该单元中的内容。若数组a的首元素的地址为2000,设数组为int型,则a[3]的地址是这样计算的:2000+3×4=2012。然后从2012地址所指向的float型单元取出元素的值,即a[3]的值。可以看出,[]实际上是变址运算符,即将a[i]按a+i计算地址,然后找出此地址单元中的值。

(4)如果p原来指向a[0],执行++p后p的值改变了,在p的原值基础上加d,这样p就指向数组的下一个元素a[1]。

(5)如果指针变量p1和p2都指向同一数组,如执行p2-p1,结果是两个地址之差除以数组元素的数据类型的长度。假设p2指向整型数组元素a[5],p2的值为2020;p1指向a[3],其值为2012,则p2-p1的结果是(2020-2012)/4=2。这个结果是有意义的,表示p2所指的元素与p1所指的元素之间差2个元素。这样就不需要具体地知道p1和p2的值,然后去计算它们的相对位置,而是直接用p2-p1就可知道它们所指元素的相对距离。两个地址不能相加,如p1+p2是无实际意义的。

假设指针p已经指向了数组a,如果要访问数组a的第k个元素或第k个元素的地址,则可以使用下标法、地址法和指针法。

表7-1 元素标记一览表

【例7.5】用下标法输出数组中的全部元素。

程序内容如下:

1 #include<stdio.h>

2 int main()

3 {

4  int a[10],i;

5  for(i=0;i<10;i++)

6   a[i]=i;

7  for(i=0;i<10;i++)

8  printf("a[%d]=%d\n",i,a[i]);

9  return 0;

10 }

【例7.6】输出数组中的全部元素(通过数组名计算元素的地址,找出元素的值)。

程序内容如下:

1 #include<stdio.h>

2 int main()

3 {

4  int a[10],i;

5  for(i=0;i<10;i++)

6   *(a+i)=i;

7  for(i=0;i<10;i++)

8   printf("a[%d]=%d\n",i,*(a+i));

9  return 0;

10 }

【例7.7】输出数组中的全部元素(用指针变量指向元素)。

程序内容如下:

1 #include<stdio.h>

2 int main()

3 {

4  int a[10],i,*p;

5  p=a;

6  for(i=0;i<10;i++)

7   *(p+i)=i;

8  for(i=0;i<10;i++)

9   printf("a[%d]=%d\n",i,*(p++));

10  return 0;

11 }

上述三个例子的输出是相同的,程序结果如图7.8所示:

图7.8 例7.5、7.6、7.7程序结果图

【例题中关键问题说明】

三种方法的比较:

(1)例7.5和例7.6这两种方法的执行效率是相同的。编译系统将a[i]转换为*(a+i)来处理,也就是说要先计算元素的地址,故采用这两种方法表示数组元素时速度较慢。

(2)例7.7是用指针变量直接指向了元素,不用每次都重新计算地址,而且像p++这样的自加操作执行速度较快,所以大大提高了执行效率。

(3)用下标法的优点是直观,可以直接知道是第几个元素。用地址法或指针变量的方法的缺点是不直观,难以快速地判断出当前处理的是哪一个元素。

【例7.8】找出下面程序中的错误

程序内容如下:

1 #include<stdio.h>(www.xing528.com)

2 int main()

3 {

4  int*p,i,a[10];

5  p=a;

6  for(i=0;i<10;i++)

7   *p++=i;

8  for(i=0;i<10;i++)

9   printf("a[%d]=%d\n",i,*p++);

10  return 0;

11 }

程序结果如图7.9所示:

图7.9 例7.8程序结果图

【例题中关键问题说明】

(1)从程序运行结果上,可以看出:输出的数值并不是我们所期望的各数组元素的值。问题出在哪儿呢?

(2)仔细分析一下程序,可以发现问题就出在指针变量p的指向上。第一个for循环语句结束后,p已经指向了a数组末尾(即最后一个元素后的地址)。执行第二个for循环时,p的起始值已经不再是a[0]的地址了,而是a+10。解决办法见例7.9。

【例7.9】例7.8的正确程序。

程序内容如下:

1 #include<stdio.h>

2 int main()

3 {

4  int*p,i,a[10];

5  p=a;

6  for(i=0;i<10;i++)

7   *p++=i;

8  p=a;         //使指针变量p重新指向a[0]

9  for(i=0;i<10;i++)

10   printf("a[%d]=%d\n",i,*p++);

11  return 0;

12 }

程序结果如图7.10所示:

图7.10 例7.9程序结果图

【例题中关键问题说明】

(1)从以上例子可以看出,虽然定义数组时指定它包含10个元素,但指针变量可以指到数组以后的内存单元,系统并不认为非法。尽管这样做是合法的,但程序得不到预期的结果,应避免出现这样的情况。

(2)*p++,由于“++”和“*”同优先级,结合方向自右向左,等价于*(p++)。*(p++)与*(++p)作用不同。若p的初值为a,则*(p++)等价于a[0],*(++p)等价于a[1],而(*p)++表示p所指向的元素值加1。

(3)如果p当前指向a数组中的第i个元素,则*(p--)相当于a[i--],*(++p)相当于a[++i],*(--p)相当于a[--i]。

【例7.10】使用指针法输出数组中的全部元素。

程序内容如下:

1 #include<stdio.h>

2 void main()

3 {

4  int a[10],i,*p;

5  p=a;

6  for(i=0;i<10;i++)

7   *(p+i)=i;

8  for(i=0;i<10;i++)

9   printf("a[%d]=%d\n",i,*(p++));

10 }

程序结果如图7.11所示:

图7.11 例7.10程序结果图

在使用指针变量指向数组元素时,有以下几个问题要注意:

(1)可以通过改变指针变量的值指向不同的元素。如用指针变量p来指向元素,用p++使p的值不断改变从而指向不同的元素。使用a++是不行的,因为数组名a代表数组首元素的地址,它是一个指针常量,它的值在程序运行期间是固定不变的。既然a是常量,所以a++是无法实现的。

(2)要注意指针变量的当前值,即指针变量当前指向哪一个元素,尤其要注意其起始值。

(3)虽然定义数组时指定它包含10个元素,并用指针变量p指向某一数组元素,但是实际上指针变量p可以指向数组以后的内存单元。如果在程序中引用数组元素a[10],虽然并不存在这个元素(最后一个元素是a[9]),但C编译程序并不认此为非法。系统把它按*(a+10)处理,即先找出(a+10)的值(是一个地址),然后找出它指向的单元的内容。

(4)指向数组的指针变量也可以带下标,如p[i]。带下标的指针变量是什么含义呢?在程序编译时,对下标的处理方法是转换为地址的,对p[i]处理成*(p+i),如果p是指向一个整型数组元素a[0],则p[i]代表a[i]。但是必须弄清楚p的当前值是什么?如果当前p指向a[3],则p[2]并不代表a[2],而是a[3+2],即a[5]。

(5)虽然利用指针引用数组元素比较方便灵活,但首先应当注意程序的正确性和易读性,要尽量减少容易使人混淆的用法。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈