指针和数组
1.一维数组和指针
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int *p = a; //等价于 int *p = &a[0];
- 数组名为数组首元素的地址。 所以第二条语句等价于int *p = &a[0];
- 数组名a代表首地址,所以a+1和p+1效果相同。注意数组名是常量,不能变化, 所以不能执行类似
a=a+1、a++
的操作;p是变量,p可以执行类似操作。 - a[i] <=> *(a+i) <=> *(p+i) <=> p[i]。 实际上,在编译时,对数组元素a[i]就是按 *(a+i)处理的,[]是变址运算符。
- 在指针已指向一个数组时,可对指针进行加减运算。 p+1指向数组中的下一个元素,p-1指向数组中的上一个元素(p+1并不是将p的值(地址)简单地加1,而是加上一个数组元素所占用的字节数)。
p2-p1
的结果是两者之间间隔的元素个数。具体算法是p2-p1的值(两个地址之差)除以数组元素的长度。- 如果在程序中引用了a[10],虽然并不存在这个元素(最后一个元素是a[9]),但C编译器并不认为它非法,因为系统把它按*(a+10)处理。这样做虽然在编译时不出错,但运行结果是不预期的,应避免。
2.二维数组和指针
int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}};
- a是数组名,代表二维数组首元素的地址,但现在的首元素是第0行,即由4个整形元素所组成的一维数组。
- 可以认为
a[0]、a[1]、a[2]
是一维数组名,指向每行的起始元素。 - a+1代表序号为1的行的起始地址。
而*(a+1)就是a[1],而a[1]是一维数组名,所以也是地址,它指向a[1][0]。
- 第0行1列元素的地址怎么表示?应该用
a[0]+1、*(a+0)+1
来表示。 - 有必要对a[i]的性质作进一步说明。a[i]从形式上看是a数组中序号为i的元素。如果a是一维数组名,则a[i]的确表示序号为i的地址单元里的值。但如果a是二维数组,则a[i]是一维数组名,它只是一个地址,并不代表该地址单元中的值。
- 现在a[0]是一维数组名(一维数组中首元素的地址),a是二维数组名(二维数组中首行的地址),二者的纯地址相同,为2000,但它们的基类型不同,前者指向整型数据,后者指向一维数组。
a[0]、a[1]、a[2]的类型为
int* 型
,指向整型变量。
而a的类型为int(*)[4]
,指向包含4个元素的一维数组。这就是数组指针。
- 在指向行的指针前面加一个*,就转换为指向列的指针, 如a和a+1是指向行的指针,*a和*(a+1)就成为指向列的指针。反之,在指向列的指针前面加&,就成为指向行的指针,如a[0]是指向0行0列元素的指针,而&a[0]指向二维数组的第0行。&a[0] <=> &*a <=> a
2.1一级指针遍历二维数组
#include <stdio.h>
int main()
{
int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}};
int *p; //p是int *型指针变量,使其指向列元素
for(p=a[0]; p<a[0]+12; p++) //p依次指向下一个元素
{
if( (p-a[0])%4==0 )
printf("\n");
printf("%4d", *p);
}
printf("\n");
return 0;
}
运行结果:
2.2数组指针遍历二维数组
//输出二维数组任一行一列的元素值
#include <stdio.h>
int main()
{
int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}};
int (*p)[4]; //表示p指向包含4个整型元素的一维数组(数组指针)
p = a; //p指向二维数组的第0行
for(int i=0; i<3; i++)
{
for(int j=0; j<4; j++)
{
printf("%4d", *(*(p+i)+j) );
}
printf("\n");
}
return 0;
}
2.3数组指针遍历一维数组
重点: 对一维数组名取&,转为指向行的地址
#include <stdio.h>
int main()
{
int a[4] = {1, 3, 5, 7};
int (*p)[4]; //数组指针,指向包含4个整型元素的一维数组
p = &a; //重点,对一维数组名取&,转为指向行的地址
printf("%d\n", (*p)[3] ); //输出a[3],相当于*(*(p+0)+3)
return 0;
}
3.数组传参
3.1一维数组的形参
一维数组的形参可以写成如下几种:
void test(int arr[10])
{}
void test(int arr[])
{}
void test(int *arr)
{}
可以接受的参数:
(1)可以是一个整形指针
(2)可以是整型变量地址
(3)可以是一维整型数组数组名
3.2指针数组的形参
void test(int *arr[20])
{}
void test(int **arr)//传过去是指针数组的数组名,代表首元素地址,首元素是个指针向数组的指针,再取地址,就表示二级指针,用二级指针接收
{}
3.3二维数组的形参
void test(int arr[3][4])
{}
void test(int arr[][4])//二维数组的两个方括号,不能全部为空,也不能第二个为空,只能第一个为空
{}
void test(int (*arr)[4])//传过去的是二维数组的数组名,即数组首元素的地址,也就是第一行的地址,第一行也是个数组,用一个数组指针接收
{}
指针的大小
在32位平台下,无论指针的类型是什么,sizeof(指针名)都是4,在64位平台下,无论指针的类型是什么,sizeof(指针名)都是8。