3.通过指针引用数组
3.1什么是数组元素的指针
所谓数组元素的指针就是数组元素的地址。可以用一个指针变量指向一个数组元素。例如:
int a[10]={1,2,4,5,6,7,8,9};
int *p;
p=&a[0];
在C语言中,数组名代表数组中首元素的地址。因此,下面两个语句等价:
p=&a[0];
p=a;
程序中的数组名不代表整个数组,只代表数组首元素的地址。上述“p=a”的作用是把a数组的首元素的地址赋给指针变量p
。
3.2 引用数组元素时指针的运算
在一定条件下允许对指针进行加和减的运算,但是没有乘除。
那么,在什么情况下需要而且可以对指针进行加和减的运算呢?回答是:当指针指向数组元素的时候。
例如,指针变量p指向数组元素a[0],我们希望用p+1表示指向下一个元素a[1]。
在指针已指向一个数组元素时,可以对指针进行一下运算:
加一个整数(用+或+=),如p+1;
减一个整数,如p-1;
自加运算,如p++,++p;
自减运算。
两个指针相减,如p1-p2(只有p1和p2都指向同一数组中的元素时才有意义)。
如果指针变量已指向数组中的一个元素,则p+1指向同一数组中的下一个元素,p-1指向同一数组中的上一个元素。注意:
执行p+1时并不是将p的值(地址)简单地加1,而是加上一个数组元素所占用的字节数。
例如,数组元素是float型,每个元素占4个字节,则p+1意味着使p的值(是地址)加4个字节,以使它指向下一元素。
*(p+i)是p+i所指向的数组元素,即a[i]。
注意:[]实际上是变址运算符,即将a[i]按a+i计算地址,然后找出此地址单元中的值。
可以p1-p2,但是不可以p1+p2,这样是无意义的。例如,p2-p1的结果是两个地址之差除以数组元素的长度。p2-p1=(2020-2012)/4=2
3.3 通过指针引用数组元素
- 下标法,如a[i]形式;
- 指针法,如*(a+i)或*(p+i)。其中a是数组名,p是指向数组元素的指针变量,其初值p=a。
例1、有一个整型数组a,有10个元素,要求输出数组中的全部元素。
#include <stdio.h>
int main()
{
int a[10];
int i;
printf("please enter 10 integer numbers:");
for(i=0;i<10;i++)
scanf("%d",&a[i]); //&a[i]也可以改用(a+i)表示。
for(i=0;i<10;i++)
printf("%d",a[i]);
//printf("%d",*(a+i)); //通过数组名和元素序号计算元素地址,再找到该元素
printf("\n");
return 0;
}
//用指针变量指向数组元素
#include <stdio.h>
int main()
{
int a[10];
int *p,i;
printf("please enter 10 integer numbers:");
for(p=a;p<(a+10);p++)
scanf("%d",p);
for(p=a;p<(a+10);p++)
printf("%d",*p);
printf("\n");
return 0;
}
用指针变量表示数组,提高了执行效率,速度更快。
#include <stdio.h>
int main()
{
int i,a[10],*p=a;
printf("please enter 10 integer numbers:");
for(i=0;i<10;i++)
scanf("%d",p++);
p=a;
for(i=0;i<10;i++,p++)
printf("%d",*p);
printf("\n");
return 0;
}
3.4 用数组名作函数参数
实参数组名代表该数组首元素的地址,而形参是用来接收从实参传递过来的数组首元素地址的。
因此,形参应该是一个指针变量(只有指针变量才能存放地址)。
所以,函数fun的形参是写成数组形式的:
fun(int arr[],int n)
但在程序编译时是将arr按指针变量处理的,相当于将函数fun的首部写成
fun(int *arr,int n)
此时,*(arr+i)和arr[i]是无条件等价的。
从应用的角度看,用户可以认为有一个形参数组,它从实参数组那里得到起始地址,因此形参数组与实参数组共占同一段
内存单元,在调用函数期间,如果改变了形参数组的值,也就是改变了实参数组的值。
注意:实参数组名代表一个固定的地址,或者说是指针常量,但形参数组名并不是一个固定的地址,而是按指针变量来处理。
在函数执行期间,形参的值就是实参数组首元素的地址,它可以再被赋值。例如:
void fun(int arr[],int n)
{
printf("%d\n",*qrr);
arr=arr+3;
printf("%d\n",*qrr);
}
例2、将数组a中n个整数按相反顺序存放,用函数实现。
#include <stdio.h>
int main()
{
void fun(int *p);
int a[6]={0,3,5,6,7,4},i;
for(i=0;i<6;i++)
printf("%d ",a[i]);
printf("\n");
fun(a);
for(i=0;i<6;i++)
printf("%d ",a[i]);
}
void fun(int *p)
{
int temp,i;
for(i=0;i<6/2;i++)
{
temp=*(p+i);
*(p+i)=*(p+5-i);
*(p+5-i)=temp;
}
}
例3、用指针方法对10个整数按由大到小顺序排序。
#include <stdio.h>
int main()
{
void sort(int x[],int n);
int i,*p,a[6];
p=a;
for(i=0;i<6;i++)
{
scanf("%d",p++);
}
p=a;
sort(a,6);
for(i=0;i<6;i++)
{
printf("%d ",*p);
p++;
}
printf("\n");
return 0;
}
void sort(int x[],int n)
{
int i,j,t;
for(i=0;i<n-1;i++)
for(j=0;j<n-i-1;j++)
if(x[j]<x[j+1])
{
t=x[j];
x[j]=x[j+1];
x[j+1]=t;
}
}
*3.5通过指针引用多维数组
要掌握的是,a,a+i,a[i],*(a+i)+j,a[i]+j都是地址。而*(a[i]+j)和*(*(a+i)+j)是二维数组元素a[i][j]的值。
int (*p)[n]是定义指向包含n个元素的一维数组的指针变量中
用指针变量作形参,以接受实参数组名传递来的地址。可以有两种方法:
- 用指向变量的指针变量;
- 用指向一维数组的指针变量。
例如:
void ave(int *p,int n)
对应实参是
ave(*a,12)
void sort(int (*p)[4],int n) //这里的p是指向具有4个元素的一维数组的指针
对应实参是
sort(a,2)
详细说明请查阅谭浩强的C语言程序设计第五版P244~P253。