1、数组指针
所谓的数组指针是指数组的起始地址,数组元素的指针是数组元素的地址。
1.1、指向数组元素的指针
一个数组是由连续的一块内存单元组成的。数组名就是这块连续内存单元的首地址。一个数组也是有各个数组元素组成的。每个数组元素按其类型不同占有几个连续的内存单元。一个数组元素的首地址也是指它所占有的几个内存单元的首地址。
定义一个指向数组元素的指针变量的方法:
int a[10];//int类型数组
int *p=null;//定义p为指向整型变量的指针
p=&a[0];//对指针变量赋值,p指向a数组的第0号元素
在c语言中,数组名代表数组的首地址,也就是第0号元素的地址,因此上例中的赋值语句也可写成:p=a;
在定义指针变量时也可以赋给初值:int *p=a;
由此可得,p、a、&a[0]均指向同一单元,是数组a的首地址,也是0号元素a[0]的首地址。但p是变量,a和&a[0]是常量。
如果指针变量p已经指向数组中的一个元素,则p+1指向同一数组的下一个元素,可得如下结论:
1)、p+i和a+i就是a[i]的首地址,即指向a数组的第i个元素;
2)、*(p+i)或*(a+i)就是p+i或a+i所指向的数组元素,即a[i]。如*(p+5)或*(a+5)与a[5]相等;
3)、指向数组的指针变量也可以带下标,如p[i]与*(p+i)等价。
main()
{
int a[10],i,*p=a;
for(i=0;i<10;i++)
{
*p++=i;/*给数组赋值,++与*同优先级,结合方向自右相左,等价*(p++)*/
}
p=a;/*因为经过上面的循环后,p!=a,即p不是指向数组a的首地址*/
for(i=0;i<10;i++)
{
printf("a[%d]=%d/n",i,*(p++));
}
}
1.2、数组名作函数参数
数组名作函数的实参和形参。如:
fArray(int arr[],int n)
{/*arr作形参数组名*/
......
}
main()
{
int array[10];
......
fArray(array,10);/*array作实参数组名*/
......
}
数组名是数组的首地址,实参向形参传送数组名实际是传送数组的地址,形参得到地址后也指向同一数组。同样指针变量的值也是地址,也可以作为函数的参数使用。
fAve(int *p,int n)
{
int i,total=0;
for(i=0;i<n,i++)
{
total+=*p++;
}
return total/n;
}
main()
{
int arr[5]={45,26,85,47,92};
int i,*p=arr;
printf("该数组的平均值是:",fAve(p,5));
}
1.3、指向多维数组的指针和指针变量
以二维数组为例
1.3.1、多维数组的地址
整型二维数组:int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};
在C语言中允许把一个二维数组分解为多个一维数组处理,则数组a可分解为:a[0]、a[1]、a[2],每个一维数组又含有四个元素,即:
a[0]={0,1,2,3};
a[1]={4,5,6,7};
a[2]={8,9,10,11};
数组及数组元素的地址可表示为:
a是二维数组名,a代表整个二维数组的首地址,也是二维数组0行的首地址,而a+i代表第i行的首地址。
a[0]是第一个一维数组的数组名和首地址,即*(a+0)或*a与a[0]是等效的,表示一维数组a[0]的0号元素的首地址。&a[0][0]是二维数组a的0行0列元素的首地址,因此,a、a[0]、*(a+0)、*a、&a[0][0]是相等的。
*(a+i)+j 表示数组a的第i行第j列元素的首地址。
*(*(a+i)+j) 表示数组a的第i行第j列元素,即a[i][j]。
main(){
int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
printf("%d,",a);
printf("%d,",*a);
printf("%d,",a[0]);
printf("%d,",&a[0]);
printf("%d/n",&a[0][0]);
printf("%d,",a+1);
printf("%d,",*(a+1));
printf("%d,",a[1]);
printf("%d,",&a[1]);
printf("%d/n",&a[1][0]);
printf("%d,",a+2);
printf("%d,",*(a+2));
printf("%d,",a[2]);
printf("%d,",&a[2]);
printf("%d/n",&a[2][0]);
printf("%d,",a[1]+1);
printf("%d/n",*(a+1)+1);
printf("%d,%d/n",*(a[1]+1),*(*(a+1)+1));
}
1.3.2、指向多维数组的指针变量
把二维数组a分解为一维数组a[0],a[1],a[2]之后,设p为指向二维数组的指针变量。可定义为:
int (*p)[4];
p=a;
表示p是一个指针变量,它指向包含4个元素的一维数组。p+i指向一维数组a[i]。则*(p+i)+j是二维数组i行j列的元素的地址。
二维数组指针变量说的一般形式是:类型说明符 (*指针变量名)[长度]
其中“类型说明符”为所指数组的数据类型;“*”表示其后的变量是指针类型;“长度”表示二维数组分解为多个一维数组时,一维数组的长度,即二维数组的列数。注意两边的括号不可少,如缺少则表示是指针数组。
2、指针数组
一个数组的元素值为指针则是指针数组。指针数组是一组有序的指针集合。指针数组的所有元素都必须是具有相同存储类型和指向相同数据类型的指针变量。
指针数组的一般说明形式为:类型说明符 *数组名[长度];
其中“类型说明符”为指针值所指向的变量的类型。
例子:
main(){
int a[3][3]={1,2,3,4,5,6,7,8,9};
int *pa[3]={a[0],a[1],a[2]};/*pa是一个指针数组,三个元素分别指向二维数组a的各行*/
int *p=a[0];
int i;
for(i=0;i<3;i++)
printf("%d,%d,%d/n",a[i][2-i],*a[i],*(*(a+i)+i));/*其中*a[i]表示i行0列元素值;*(*(a+i)+i)表示i行i列的元素值*/
for(i=0;i<3;i++)
printf("%d,%d,%d/n",*pa[i],p[i],*(p+i));/*其中*(p+i)表示0行i列的值*/
}
注意指针数组和二维数组指针变量的区别。这两者虽然都可用来表示二维数组,但是其表示方法和意义是不同的。
二维数组指针变量是单个的变量,其一般形式中"(*指针变量名)"两边的括号不可少。而指针数组类型表示的是多个指针(一组有序指针)在一般形式中"*指针数组名"两边不能有括号。
例如:
int (*p)[3];
表示一个指向二维数组的指针变量。该二维数组的列数为3或分解为一维数组的长度为3。
int *p[3]
表示p是一个指针数组,有三个下标变量p[0],p[1],p[2]均为指针变量。
指针数组也常用来表示一组字符串,这时指针数组的每个元素被赋予一个字符串的首地址。指向字符串的指针数组的初始化更为简单。如char *name[]={"Zhang San","Li Si"];
2.1、指针数组作函数参数。
#include"string.h"
main()
{
void sort(char *name[],int n);
void print(char *name[],int n);
static char *name[]={ "CHINA","AMERICA","AUSTRALIA","FRANCE","GERMAN"};/*把这些字符数组的首地址放在一个指针数组中*/
int n=5;
sort(name,n);
print(name,n);
}
void sort(char *name[],int n)
{
char *pt;
int i,j,k;
for(i=0;i<n-1;i++)
{
k=i;
for(j=i+1;j<n;j++)
if(strcmp(name[k],name[j])>0) k=j;/*strcmp函数允许参与比较的字符串以指针方式出现*/
if(k!=i)
{
pt=name[i];
name[i]=name[k];
name[k]=pt;/*交换指针数组相应两元素的内容(地址),与普通的排序方法(逐个比较之后交换字符串的位置)相比,效率大大提高*/
}
}
}
void print(char *name[],int n)
{
int i;
for (i=0;i<n;i++) printf("%s/n",name[i]);
}