数组与指针

2021-06-23 21:05

阅读:597

标签:表数   实现   相同   改变   引用   ima   width   原因   color   

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、下标法
#includeint main(){
    int a[10];
    for(int i=0;i10;i++)
        scanf("%d",&a[i]);
    printf("\n下标法输出:\n");
    for(int i=0;i10;i++)
        printf("%d ",a[i]);
    printf("\n");
    return 0;
} 
//通过数组名计算数组元素地址,找出元素的值 
#includeint main(){
    int a[10];
    for(int i=0;i10;i++)
        scanf("%d",&a[i]);
    printf("\n");
    for(int i=0;i10;i++)
        printf("%d ",*(a+i));
    return 0; 
} 
//用指针变量指向数组元素
#includeint main(){
    int a[10];
    int *p;
    for(int i=0;i10;i++)
        scanf("%d",&a[i]);
    for(p=a;p10;p++)
        printf("%d ",*p);
    return 0;
} 
 对3种方法的比较:
  (1) 对上述的第①和第②种方法执行效率是相同的。C编译系统是将a[i]转换为*(a+i)处理的,即先计算元素地址。因此用第①和第②种方法找数组无素费时较多。
  (2) 第③种方法比第①、第②方法快,用指针变量直接指向元素,不必每次都重新计算地址,像p+ +这样的自加操作是比较快的。这种有规律地改变地址值(p+ +)能大大提高执行效率。
  (3) 用下标法比较直观,能直接知道是第几个元素。例如,[5]是数组中序号为5的元素(注意序号从0算起)。用地址法或指针变量的方法不直观,难以很快地判断出当前处理的是哪一个元素。例如,上述第③种方法所用的程序,要仔细分析指针变量p的当前指向,才能判断当前输出的是第几个元素。
在使用指针变量指向数组元索时,有以下几个问题要注意:
  ① 可以通过改变指针变量的值指向不同的元素。例如,上述第③种方法是用指针变量p来指向元素,用p+ +使p的值不断改变从而指向不同的元素,这是合法的。如果不用p而使数组名a变化(例如,用a++)行不行呢?假如将上述第③种方法中的程序的最后两行改为:
for(p=a;a10);a+ +)
  printf("%d", *a);
是不行的。因为数组名a代表数组首元素的地址,它是一个指针常量,它的值在程序运行期间是固定不变的。既然a是常量,所以a+ +是无法实现的。
  ② 要注意指针变量的当前值,比如下面的例子:
//通过指针变量输出a数组的10个元素
#includeint main(){
    int *p,a[10];
    p=a;
    for(int i=0;i10;i++)
        scanf("%d",p++);
    printf("\n");
    for(int i=0;i10;i++,p++)
        printf("%d ",*p);
    printf("\n");
    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],这样结果就对了,程序如下:

#includeint main(){
    int *p,a[10];
    p=a;
    for(int i=0;i10;i++)
        scanf("%d",p++);
    printf("\n");
    p=a; //使p回到初始值
    for(int i=0;i10;i++,p++)
        printf("%d ",*p);
    printf("\n");
    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、用数组名作函数参数

 
 
 
 
 
 
 
 
 
 
 
 
 

 

数组与指针

标签:表数   实现   相同   改变   引用   ima   width   原因   color   

原文地址:https://www.cnblogs.com/geziyu/p/9670237.html


评论


亲,登录后才可以留言!