数组与指针

Posted geziyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组与指针相关的知识,希望对你有一定的参考价值。

1、数组元素的指针

  一个变量有地址, 一个数组包含若干元素,每个 数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一一个指针变量中)。所谓数组元索的指针就是数组元素的地址。引用数组元素可以用下标法(如a[3]),也可以用指针法,即通过指向数组元素的指针找到所需的元素。使用指针法能使目标程序质量高(占内存少,运行速度快)。

int a[10];//定义a为包含10个整型数据的数组
int *p;//定义p为指向整型变量的指针变量 
p=&a[0];//把a[0]元素的地址给指针变量p,也就是p执行数组a的第0号元素

  应当注意,如果数组为int型,则指针变量的基类型也为int型,C语言规定数组名代表数组中首元素,下面两个语句是等价的:

p=&a[0];
p=a;//注意数组名a不代表整个数组,上述“p=a;”的作用是把a数组的首元素的地址赋给指针变量p,而不是把数组a各元素的值赋给p。

2、通过指针引用数组元素

  假设p已定义为一个指向整型数据的指针变量,并已给它赋了一个整型数组元素的地址,使它指向某一个数组元素。如果有这样赋值语句:*p=1;  表示将1赋给p当前所指向的数组元素。按C语言的规定:如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素,而不是将p的值(地址)简单地加1。例如,数组元素是float型,每个元素占4个字节,则p+1意味着使p的值(是地址)加4个字节,以使它指向下一元素。p十1所代表的地址实际上是p+1Xd,d是一个数组元素所占的字节数。如果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或ati所指向的数组元素,即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数组,整型,有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;
} 

  可以通过改变指针变量的值指向不同的元素,比如上面第三种方法,用指针变量p来指向元素,用p++使p的值不断的改变从而指向不同的元素,这是合法的。如果不用p而使用数组名a变化(例如:a++)行不行呢?

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

  这样是不行的,因为数组名 a代表数组首元素的地址,它是一个指针常量,它的值在程序运行期间是固定不变的。既然a是常量,a++是无法实现的。同时也要注意指针变量的当前值,比如下面的例子:

//通过指针变量输出a数组的10个元素
#include<stdio.h>
int main(){
    int *p,i,a[10];
    p=a;
    for(i=0;i<10;i++)
        scanf("%d",p++);
    printf("
");
    for(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

//修改后
#include<stdio.h>
int main(){
    int *p,i,a[10];
    p=a;
    for(i=0;i<10;i++)
        scanf("%d",p++);
    printf("
");
    p=a;
    for(i=0;i<10;i++,p++)
        printf("%d ",*p);
    printf("
");
    return 0;
} 
  注意指针变量的运算。如果先使p指向数组a的首元素(即p=a),请分析:
  (i) p++(或p+=1)。使p指向下一元素,即a[1]。若再执行* p,则得到下一个元素a[1]的值。
  (i)*p++.由于十+和*同优先级,结合方向为自右而左,因此它等价于*(p++)。作用是先得到P指向的变量的值(即*p),然后再使p+1→p。
上例中最后一个程序中最后一个for语句:
for(i=0;i<10;i++,p++)
printf("%d", *p);
可以改写为
for(i=0;i<10;i++)
printf("%d", *p++);
  作用完会一样。它们的作用都是先输出*p的值。然后使p值加1.这样下次循环时,*P就是下一个元素的值。
  (i) * (p++)与* (++p)作用不同。前者是先取* p值,然后使p加1。后者是先使p加1,再取* p。若p初值为a(即&a[0]),则* (p++)为a[0],而* (++p)为a[1]。
 (ii)++( * p)表示p所指向的元素值加1,如果p=a,则++( * p)相当于++a[0]。若a[0]=3,则在执行十十( * p)(即++ a[0])后,a[0]的值为4。注意:是元素值a[0]加1,而不是指针p的值加1。
 (iii)如果p当前指向a数组中第1个元素,则:*(p--)相当于a[i--],先对p进行“*”运算,再使p自减。* (++p)相当于a[++i],先使p自加,再作*运算。* (--p)相当于a[--i],先使p自减,再作*运算。将++和--运算符用于指针变量十分有效,可以使指针变量自动向前或向后移动,指向上一个或下一个数组元素
//想输出a数组的100个元素,可以用下面的方法:
p=a;
while(p<a=100)
    printf("%d ",*p++);
//或者:
p=a;
while(p<a+100){
    printf("%d ",*p);
    p++; 
}

3、用数组名作函数参数

 

 

 

  

 







以上是关于数组与指针的主要内容,如果未能解决你的问题,请参考以下文章

在第6731次释放指针后双重免费或损坏

指针与数组

指针与数组

Go语言切片

指针与一维数组和二维数组以及字符串指针数组的学习笔记

c语言中如何通过二级指针来操作二维数组