一.数组指针和指向数组的指针变量
一个变量有一个地址,一个数组包含若干个元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。所谓数组的指针是指数组的起始地址,数组元素的指针是指数组元素的地址。
一个数组是由连续的一块内存单元组成的,数组名就是这款连续内存单元的首地址。
例:
int a[10]; //定义a为包含10个int型数据的数组
int *p; //定义p为指向int型变量的指针
//下面两个语句是等价的
p=&a[0];
p=a;
因为数组是int型,所以指针变量也应为指向int型的指针变量。
p,&a[0],a均指同一内存单元,它们都是数组a的首地址,也是0号元素a[0]的首地址,a,&a[0]都是常量,p是指向数组的指针变量。
例:
int a[10];
int *p = a;
p++; //合法,p是指向数组的指针变量
a++; //非法,a是数组名,是数组的首地址,是常量。
二.通过指针访问数组元素
如果指针变量p已经指向数组中的一个元素,则p+1指向同一数组的下一个元素。
有数组 int [10]; int *p=&a[0]; 则:
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)等价。
引用一个数组元素可以用:
1.下标法,即用a[i]形式访问数组元素。
2.指针法,即采用*(a+i)或*(p+i)的形式,用间接访问的方法来访问数组元素,其中a是数组名,p是指向数组的指针变量。
例:
//通过指针法为数组赋值并打印
int *p,i,a[10];
p=a;
for(i=0;i<10;i++)
*p++=i;
//注意此处应该加上p=a上面p的值已经不是数组的起始地址a了
for(i=0;i<10;i++)
printf("a[%d]=%d\n",i,*p++);
指针变量可以指导到数组以后的内存,系统不认为非法。
*p++等价于*(p++)
*(p++)与*(++p)不同,前者等价a[0],后者等价a[1]
(*p)++表示p所指向的元素值加1,a[0]++
如果p当前指向a数组中的第i个元素,则
*(p--)相当于a[i--]
*(++p)相当于a[++i]
*(p++)相当于a[i++]
三.指针加减算数运算
1.对于指向数组的指针变量,可以加上或减去一个整数n。设pa是指向数组a的指针变量,则pa+n,pa-n,pa++,++pa,pa--,--pa都是合法的。指针变量加减一个整数n的意义是把指针指向的当前位置(指向某数组元素)向前或向后移动n个位置。应当注意,数组指针变量向前或向后移动一个位置和地址加1减1的概念上是不同的。因为数组可以有不同的类型,各种类型的数组元素长度所占的字节长度也是不同的。如指针变量加1即向后移动1个位置标示指针指向想一个数据元素的首地址,而不是在原地址基础上家1,例如:
int a[5], *pa;
pa = a;
pa = pa + 2; //pa指向a[2],即pa的值是&a[2]
指针变量的加减运算只能对数组指针变量进行,对指向其他类型的变量的指针变量做加减运算时毫无意义的。
2.对于两个指针变量的加减运算,只有指向同一数组的两个指针变量之间才能进行运算,否则毫无意义。
两个指针相减所得的差是两个指针元素之间相差的元素个数。实际上是两个指针值相减再除以该数组元素的长度。
两个指针变量相加没有实际意义。
3.两指针变量进行关系运算:指向同一数组的两指针进行关系运算可以表示他们所指元素之间的关系。例如:
pf1==pf2表示pf1和pf2指向同一数组元素。
pf1>pf2表示pf1处于高地址位置。
pf1<pf2表示pf1处于低地址位置。
指针变量还可以与0比较,p==0表示p是空指针,它不指向任何变量。
对变量赋0值和不赋值是不同的。指针变量未赋值时,可以是任意值,是不能使用的,否则会造成意外错误。指针变量赋0值后,则可以使用,只是它不指向具体变量而已。
四.数组名作为函数参数
指针变量的值是地址,数组指针的变量的值即为数组的首地址,可以作为函数的参数使用。
注意,数组名作为函数参数传入函数后,会自动转换为指针。
例:
void function(int a[])
{
printf("sizeof(a)=%d\n",sizeof(a)); //sizeof(a)
}
void main()
{
int a[10] ={0};
printf("sizeof(a)=%d\n",sizeof(a)); //sizeof(a)=40
function(a);
}
五.指向多维数组的指针和指针变量
1.多维数组的地址
设有多维数组 inta[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
C语言允许把一个二维数组分解为多个一维数组来处理。因此a可以分解为三个一维数组a[0],a[1],a[2],每个数组又含四个元素。(a是一个包含三个数组的数组,每一个元素又分别包含4个元素)。
a是二维数组名,代表整个二维数组的首地址,也是二维数组0行的首地址,a+1代表第一行的首地址。
a[0]是第一个一维数组的数组名和首地址,*(a+0),*a,a,a[0],&a[0][0]是等同的。
a[1]是第二个一维数组的数组名和首地址,*(a+1),a+1,a[1],&a[1][0]是等同的。
由此可推 *(a+i),a+i,a[i],&a[i][0]
&a[i]和a[i]也是等同的。因为在二维数组中不能把&a[i]理解为a[i]的地址,不存在元素a[i]。c语言规定,它是一种地址计算方法,表示数组a第i行的首地址。由此得出a[i],&a[i],*(a+i),a+i也是是等同的。
a[0]也可以看成是a[0]+0,是一维数组a[0]的0号元素首地址,而a[0]+1则是a[0]的1号元素首地址,由此可得a[i]+j是一维数组a[i]的j号元素首地址,它等与&a[i][j]。
由a[i] = *(a+i)得a[i]+j=*(a+i)+j。由于*(a+i)+j是二维数组a的第i行j列的首地址,所以该元素的值等于*(*(a+i)+j)
2.指向多维数组的指针变量
把二维数组a分解为一维数组a[0],a[1],a[2]后,设p为指向二维数组的指针变量,可以定义为 int (*p)[4]; 它表示p是一个指针变量,指向包含4个元素的一维数组。
int (*p)[4]=a; *(p+i)+j是二维数组i行j列元素的首地址,*(*(p+i)+j)则是i行j列元素的值。
注意:
int (*p)[4];中的括号比不可少,如果没有括号则表示是指针数组,意义就完全不同了。