数组与指针
Posted geziyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组与指针相关的知识,希望对你有一定的参考价值。
1、数组元素的指针
一个变量有地址,一个数组包含若干元素,每个数组元紫都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素(把某元素的地址放到一个指针变量中)。所谓数组元索的指针就是数组元素的地址。引用数组元素可以用下标法(如a[3]),也可以用指针法,即通过指向数组元素的指针找到所需的元素。使用指针法能使目标程序质量高(占内存少,运行速度快)。
/*定义一个指向数组元素的指针变量的方法*/ int a[10]; //定义a为包含10个整型数据的数组 int *p; //定义p为指向整型变量的指针变量 /*应当注意:如果数组为int型,则指针变量的基类型也为int型,下面对该指针变量赋值*/ p=&a[0]; //把a[0]元素的地址赋给指针变量p /*C语言规定,数组名代表数组中首元素的地址*/ p=&a[0] <=> p=a //等价关系 /*注意数组名a不代表整个数组,上述p=a的作用是把a数组元素的首地址赋给指针变量p,而不是将数组a各元素的值赋给p*/
2、通过指针引用数组元素
假设p已定义为一个指向整型数据的指针变量,并已给它赋了一个整型数组元素的地址,使它指向某一个数组元素。如果有赋值语句:*p=1; 表示将1赋给ρ当前所指向的数组元素。按C语言的规定:如果指针变量p已指向数组中的一个元素,则p+1指向同数组中的下一个元素而不是将P的值(地址)简单地加1。例如,数组元素是float型,每个元素占4个字节,则p+1意味着使p的值(是地址)加4个字节,以使它指向下一元素。p+1所代表的地址实际上是p+1*d,d是一个数组元素所占的字节数(在TurboC++中,对int型,d=2;对float和long型,d=4;对char型,d=1。在VisualC++ 6. 0中,对int.long和float型,d=4;对char型,d=1)。
如果p的初值为&.a[0],则:
(1) p+i和a+i就是a[i]的地址或者说,它们指向a数组的第i个元素,这里需要特别注意的是a代表数组首元素的地址,a+i也是地址,它的计算方法同p+i,即它的实际地址为a+iXd。例如,p+9 和a+9的值是&a[9],它指向a[9]。
(2) *(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的首元素的地址为1000,设数组为float 型,则a[3]的地址是这样计算的:1000+3X4= 1012,然后从1012地址所指向的float型单元取出元素的值,即a[3]的值。可以看出,[ ]实际上是变址运算符,即将a[i]按a+i计算地址,然后找出此地址单元中的值。
(3) 指向数组的指针变量也可以带下标,如:p[i]与*(p+i)等价。引用一个数组元素有两种方法, ①. 下标法,如a[i]形式。②. 指针法,如*(a+i)或*(p+i)。其中a是数组名,p是指向数组元素的指针变量,其初值:p=a。
//输出数组中的全部元素 /*假设有一个a数组,整型,有10个元素。要输出各元素的值有以下三种方法:*/ //1、下标法 #include<stdio.h> int main(){ int a[10]; for(int i=0;i<10;i++) scanf("%d",&a[i]); printf(" 下标法输出: "); for(int i=0;i<10;i++) printf("%d ",a[i]); printf(" "); return 0; } //通过数组名计算数组元素地址,找出元素的值 #include<stdio.h> int main(){ int a[10]; for(int i=0;i<10;i++) scanf("%d",&a[i]); printf(" "); for(int i=0;i<10;i++) printf("%d ",*(a+i)); return 0; } //用指针变量指向数组元素 #include<stdio.h> int main(){ int a[10]; int *p; for(int i=0;i<10;i++) scanf("%d",&a[i]); for(p=a;p<a+10;p++) printf("%d ",*p); return 0; }
(1) 对上述的第①和第②种方法执行效率是相同的。C编译系统是将a[i]转换为*(a+i)处理的,即先计算元素地址。因此用第①和第②种方法找数组无素费时较多。
(3) 用下标法比较直观,能直接知道是第几个元素。例如,[5]是数组中序号为5的元素(注意序号从0算起)。用地址法或指针变量的方法不直观,难以很快地判断出当前处理的是哪一个元素。例如,上述第③种方法所用的程序,要仔细分析指针变量p的当前指向,才能判断当前输出的是第几个元素。
① 可以通过改变指针变量的值指向不同的元素。例如,上述第③种方法是用指针变量p来指向元素,用p+ +使p的值不断改变从而指向不同的元素,这是合法的。如果不用p而使数组名a变化(例如,用a++)行不行呢?假如将上述第③种方法中的程序的最后两行改为:
for(p=a;a<(p+ 10);a+ +) printf("%d", *a);
//通过指针变量输出a数组的10个元素 #include<stdio.h> int main(){ int *p,a[10]; p=a; for(int i=0;i<10;i++) scanf("%d",p++); printf(" "); for(int i=0;i<10;i++,p++) printf("%d ",*p); printf(" "); return 0; }
运行结果如下:
显然输出的数值并不是a数组中各元素的值。原因是指针变量的初始值为a数组首元素(即a[0])的地址,但经过第一个for循环读人数据后,p已指向a数组的末尾,因此,在执行第二个for循环时,p的起始值不是&a[0]了,而是a+10。由于执行第二个for 循环时,每次要执行p++,因此p指向的是a数组下面的10个元素,而这些存储单元中的值是不可预料的。解决这个问题的办法,只要在第二个for循环前加上一个赋值语句:p=a; 使p的初始值回到&a[0],这样结果就对了,程序如下:
#include<stdio.h> int main(){ int *p,a[10]; p=a; for(int i=0;i<10;i++) scanf("%d",p++); printf(" "); p=a; //使p回到初始值 for(int i=0;i<10;i++,p++) printf("%d ",*p); printf(" "); return 0; }
运行结果如下:
③ 从上例可以看到,虽然定义数组时指定它包含10个元素,并用p指向某一数组元素,但是实际上指针变量p可以指向数组以后的内存单元。如果引用数组元素a[10],C编译程序并不认为非法,系统把它按*(a+10)处理,即先找出(a+10)的值(是一个地址),然后找出它指向的单元的内容。这样做虽然是合法的(在编泽时不出错),但应避免出现这样的情况,这会使程序得不到预期的结果。这种错误比较隐蔽,初学者往往难以发现。在使用指针变量指向数组元索时,应切实保证指向数组中有效的元素。注意:*(p++)与*(+ +p)作用不同。前者是先取*p值,然后使p加1。后者是先使p加1,再取*p。若p初值为a(即&a[0]),则*(p++)为a[0],而*(++p)为a[1]。++(* p)表示P所指向的元素值加1,如果p=a,则++(*p)相当于++a[0]。若a[0]=3,则在执行++(*p)(即++a[0])后,a[0]的值为4。注意:是元素值a[0]加1.而不是指针p的值加1。
3、用数组名作函数参数
以上是关于数组与指针的主要内容,如果未能解决你的问题,请参考以下文章