一. 一维数组的指针
数组的一个特点为连续存储,它被存储在内存中一大片连续的存储空间里。C语言对数组元素的访问是访问数组的首地址加上相对于初始位置的偏移量。使用指针也可以对数组进行操作,但同样要注意数组越界的问题。任何用数组下标完成的工作都可以用指针完成,实际上一个不带下标的数组名就是一个指向该数组的指针。
数组在编译过程中会转化为指针进行操作,直接用指针对数组进行操作会使系统的编译时间减少,但用指针编写的程序语法晦涩难懂,因此在对数组的操作中尽量的使用下标,虽然编译费时,但会让程序清晰明了。
例如:
int a[10];
int *p;
p = a;
数组名是指向数组首元素地址的地址常量名,所以p = a;和p = &a[0];是等价的。
p[i]和a[i]都是对数组第i+1个元素进行访问,也可以使用*(p+1)或*(a+1)对数组元素进行访问,第一种为下标法,第二种为指针法。
例子:从键盘上输入是个整形变量值,在输出到屏幕上。有四种方法:
法一:用指针引用数组元素
#include<stdio.h>
int main()
{
int *p,i,a[10];
p = a;
for(i = 0;i<10;i++)
scanf("%d",p++); //先放到地址p上,然后p++
p = a; //指针p回到数组a的首元素
for(i = 0;i<10;i++,p++)
printf("%d",*p) //取p上的元素
return 0;
}
法二:用下标来引用数组元素
#include<stdio.h>
int main()
{
int i,a[10];
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(i=0;i<10;i++)
scanf("%d",a[i]);
return 0;
}
法三:用指针下标来引用数组元素
#include<stdio.h>
int main()
{
int *p,i,a[10];
p = a;
for(i=0;i<10;i++)
scanf("%d",&p[i]);
p = a;
for(i=0;i<10;i++,p++)
printf("%d",p[i]);
return 0;
}
法四:用数组名引用数组元素
#include<stdio.h>
int main()
{
int i,a[10];
for(i = 0;i<10;i++)
scanf("%d",(a+i));
for(i =0;i<10;i++)
printf("%d",*(a+i));
}
注意:
1.指针变量可以实现自身的值的改变,例如p++是合法的,但a++是错误的,因为a代表的是首元素的地址,是常量,不会向后移动。
2.指针变量可以移动到数组的边界外,而系统不会报错,这十分危险
3.*p++的计算顺序:*和++同等级,运算从右向左,即等价于*(p++)
4.*(p++)和*(++p)和(*p)++含义不同
二. 二维数组的指针
int a[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,12}};
说明:
二维数组名a是二维数组的首地址,包含三个元素a[0],a[1],a[2],a[0]代表的是第一行的首地址,即a[0][0],a[0]+2即为a[0][2],a[i]、*(a+i)均表示第i行第0列元素的地址,a[i]+j、*(a+i)+j表示都是第i行第j列的元素地址,*(a[i]+j)和*(*(a+i)+j)均表示的是第i行第j列的元素的值
引用形式 | 含义 | 地址 |
---|---|---|
a,&a[0] | 二维数组名,a[0]行元素的初地址 | 1000 |
a[0],*(a+0),*a,&a[0][0] | a[0]数组名,0行0列元素的地址 | 1000 |
a[0]+1,*a+1,&a[0][1] | a[0]行1列元素的地址 | 1002 |
a+1,&a[1] | a[1]数组元素的地址 | 1010 |
a[1],*(a+1),&a[1][0] | a[1]数组名,1行0列元素的地址 | 1010 |
a[1]+4,*(a+1)+4,&a[1][4] | a[1]行4列元素的地址 | 1018 |
*(a[2]+4),*(*(a+2)+4),a[2][4] | a[2]第4列的元素 | 1028 |
对二维数组中元素输出 例子:
法一:引用下标
#include<stdio.h>
int main()
{
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
int i,j;
for(i=0;i<3;i++){
for(j=0;i<4;j++){
printf("%d",a[i][j]);
printf("\n")
}
}
return 0;
}
法二:使用指针和下标引用二维数组
#include<stdio.h>
int main()
{
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("%d",*(a[i]+j));
printf("\n")
}
}
return 0;
}
法三:使用指针引用二维数组
#include<stdio.h>
int main()
{
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
int *p[4];
int i,j;
p = a;
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("%d",*(*(p+i)+j));
printf("\n");
}
}
return 0;
}
第四种:使用指针引用二维数组
#include<stdio.h>
int main()
{
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
int i,j;
int *p[4];
for(p=a;p<a+3;p++)
{
for(j=0;j<4;j++)
{
printf("%d",*(*p+j));
printf("\n");
}
}
}
三. 指针数组
指针数组是一个数组,里面的元素都是指针变量。
声明格式: <储存格式> <数据类型> *<数组名>[<数组长度>] = {初值列表};
注意:[]比*优先度要高,所以数组名先和数组长度结合,形成数组定义,*表示此数组中所有元素都是指针类型。
例如: int *p1[10]; //不能写成int (*p1) [10];
char *p2[4][8] = {"Fortran","COBOL","BASIC","Pascal"};
说明:二维字符数组和二维指针数组的区别:二维字符数组表示的字符串在存储上是一片连续的空间,但中间可能有很多空的存储单元,因为作为数组定义,需要指定列数为最长字符串的长度加1,而实际上个字符串长度一般并不相等。字符指针数组表示的字符串在空间上是分散的。