C语言 通过指针引用数组元素

1.引用一个数组元素有两种方法:

(1)下标法,如a[i]的形式;
(2)指针法,如*(a+i)*(p+i)。其中a是数组名,p是指向数组元素的指针变量,其初值p=a。

【例】有一个整数数组a,有0个元素,要求输出数组中的全部元素
【分析】:引用数组中各元素的值有3中方法:(1)下标法,如a[3];(2)通过数组名计算元素地址,找出元素的值;(3)用指针变量指向数组元素
(1)下标法:

int main()
{
	int a[10];
	printf("输入10个数字:");
	for (int i = 0; i<10;i++)
		scanf("%d",&a[i]);
	for (int i = 0;i<10;i++)
		printf("%d ", a[i]);//数组元素用数组名和下标表示
	return 0;
}

(2)通过数组名计算元素地址,找出元素的值:

int main()
{
	int a[10];
	printf("输入10个数字:");
	for (int i = 0; i < 10; i++)
		scanf("%d", &a[i]);
		//scanf("%d", a+i);
	for (int i = 0; i < 10; i++)
		printf("%d ", *(a + i));//通过数组名和元素序号计算元素地址,在找到该元素
	return 0;
}

(3)用指针变量指向数组元素:

int main()
{
	int a[10];
	int* p = &a[0];
	printf("输入10个数字:");
	for (int i = 0; i < 10; i++)
		scanf("%d", &a[i]);
	/*for (int p = a; p < (a+10); p++)
		scanf("%d", p);	*/	//用指针变量表示当前元素的地址
	for (p=a; p< (a+10);p++)
		printf("%d ", *p);//用指针指向当前的数组元素
	return 0;
}

3种方法的比较:

第(1)和第(2)种方法执行效率相同。C编译系统是将a[i]转换成*(a+i)处理的,即先计算元素的地址。因此用(1)、(2)两种方法找数组元素费时较多。

第(3)种方法比第(1)和第(2)种方法快,用指针变量直接指向该元素,不必每次都重新计算地址,像p++这样的自加操作是比较快的。

用下标法比较直观,能直接知道是第几个元素。用地址法或指针变量的方法不直观,难以很快判断出当前处理的是哪一个元素。

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

(1)可以通过改变指针变量的值指向不同的元素。例如,当用指针变量p指向数组中的某一元素,用p++使p的值不断改变从而指向不同的元素。
如果不用p变化的方法而用数组名a变化的方法(例如,用a++)是不行的。因为数组名a代表数组首元素的地址,它是一个指针型常量,所以a++是无法实现的。

(2)要注意指针变量的当前值。具体看下面的例子。

【例】通过指针变量输出整型数组a的10个元素。
【解题思路】用指针变量p指向数组元素,通过改变指针变量的值,使p先后指向a[0]~a[9]各元素。
【程序代码】

int main()
{
	int a[10];
	int* p = a;
	printf("输入10个数字:");
	for (int i = 0; i < 10; i++)
		scanf("%d", p++);
	for (int i = 0; i < 10; i++, p++)
		printf("%d ", *p);
	return 0;
}

【运行结果】
请添加图片描述
【结果分析】
(1)输出的数值并不是a数组中各元素的值。
(2)造成这个结果的原因是指针变量p的指向有问题。
指针变量p的初始值为a数组首元素的地址,经过第一个for循环读入数据之后,p已指向该数组的末尾。因此在执行第二个for循环时,p的起始值就不是&a[0]了,而是a+10。由于执行第二个for循环时,每次都要执行p++,因此p指向的是a数组下面的10个存储单元,而这些存储单元的值是不可预测的。如下图所示:
C语言 通过指针引用数组元素_第1张图片
【改正以上代码】
解决办法:在第二个for循环之前加上一个赋值语句:p=a;,使p的初始值重新等于&a[0],这样结果就对了,代码如下:

int main()
{
	int a[10];
	int* p = a;
	printf("输入10个数字:");
	for (int i = 0; i < 10; i++)
		scanf("%d", p++);
	p = a;
	for (int i = 0; i < 10; i++, p++)
		printf("%d ", *p);
	return 0;
}

【运行结果】
请添加图片描述

总结

1.从上例可以看出,虽然定义数组时指定它包含10个元素,并用指针变量p指向某一数组元素,但是实际上指针变量p可以指向数组以后的存储单元。 如果在上例的程序中我们引用数组元素a[10],虽然并不存在这个元素,但是C编译程序并不认为它非法。系统把它按*(a+10)处理,即先找出(a+10)的值(是一个地址),然后找出它指向的单元(*(a+10))的内容。这样做虽然在编译时不出错,但是运行结果却不是预期的,应该避免出现这样的情况。在使用指针变量指向数组元素时,应该切实保证指向数组中的有效元素。

2.指向数组元素的指针变量也可以带下标,如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]。

3.利用指针引用数组元素,比较方便灵活,有不少技巧。主要分析下面几种情况(设p开始指向数组a的首元素(即p=a))。
(1)

p++;
*p;

p++使p指向下一元素a[1]。然后若再执行*p,则得到下一个元素a[1]的值。
(2)*p++;
由于++和*同优先级,结合方向为自右向左,因此*p++;等价于*(p++);。先引用p的值,实现*p的运算,然后再使p自增1。
上例程序中的第二个for语句

for (int i=0;i<10;i++,p++)
	printf("%d ",*p);

可以改写为

for(int i=0;i<10;i++)
    printf("%d ",*p++);

作用完全一样。它们的作用都是先输出*p的值,然后使p值加1,这样下一次循环时,*p就是下一个元素的值。

(3)*(p++)*(++p)作用不相同。
*(p++)是先取*p的值,然后使p+1。
*(++p)是先使p+1,再取*p。
若p初值为a(即&a[0]),若输出*(p++),得到a[0]的值,而输出*(++p),得到a[1]的值。

(4)++(*p)
表示p所指向的元素值加1,如果p=a,则++(*p)相当于++a[0],若a[0]的值为3,则执行++(*p)(即++a[0])之后,a[0]的值为4。注意:是元素a[0]的值加1,而不是指针p的值加1。

(5)如果p当前指向a数组中第i个元素a[i],则:
*(p--)相当于a[i--],先对p进行*运算(求p所指向的元素的值),再使p自减。
*(++p)相当于a[++i],先使p自加,再进行*运算。
*(--p)相当于a[--i],先使p自减,再进行*运算。

【注意】
在用*p++形式的运算时,一定要十分小心,弄清楚先对p进行*运算还是先使p自增或自减。

你可能感兴趣的:(C语言,c语言,算法,c++)