二维数组
二维数组可看成一维数组,而一维数组的数组名表示数组首元素地址,即一行的地址,二维数组的数组名即表示第一行的地址,若多二维数组的数组名+1即表示第二行第一个元素的地址
对一个三行四列的数组arr
int arr[3][4];
它的数组名即表示第一行的首元素地址,*(arr+1)表示的是第二行首元素的地址(可理解为第二行数组的数组名),*(arr+1)[2]即第二行第三个元素地址即
例1:
int main(int argc,char *argv[]) { int arr[3][2] = {(0,1),(2,3),(4,5)}; int *p; p = arr[0];//p=&arr[0][0] printf("%d", p[0]); system("pause"); return 0; }
逗号表达式将前面的表达式舍弃,执行最后一个表达式,即数组arr[3][2]被初始化为{1,3,5},输出1.
a[0]表示第一行数组首元素地址,p保存第一行首元素地址,即p=&arr[0][0]
p[0]即表示访问第一行第一个元素
例二
int main() { int a[5][5];//可看为一位数组,每个元素又是大小为5的一维数组 int(*p)[4]; p =(int(*)[4]) a;//强制转化 printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]); system("pause"); return 0; } 输出fffffffe,-4
p[4][2]即表示*(*(p+4)+2)
a[0] | a[1] | a[2] | a[3] | a[4] |
p每次+1跳过4个空间,a+1跳过5个空间,地址-地址表示同一个数组两个元素之间元素个数
例三
int main() { int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int *ptr1 = (int *)(&aa + 1); //int(*p)[2][5]=&aa; int *ptr2 = (int *)(*(aa + 1)); printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1)); system("pause"); return 0; } 输出10,5
&aa+1跳过整个数组,ptr1指向数组后面的空间
aa+1即表示第二行,*(aa+1)即相当于aa[1][0]的地址,ptr2指向第二行第一个元素
二级指针
数组传参
例1 一维数组传参
int fun(int *p) { } int main() { int arr[10]; fun(arr);//即将数组的地址传进去 //或者fun(&arr[10]); }
例二 二维数组传参
int fun(int arr[][4]) int fun2(int *p) int fun3(int (*p)[4])//数组指针 int main() { int arr[3][4]; fun(arr); fun2(&arr[0][0]) fun3(arr)//数组名相当于数组首元素地址,而arr首元素又是一个大小为4的一维数组,即一维数 //组的地址,一维数组的地址由一维数组的指针来接收 }
ps.如果想在fun函数内部求数组的大小,需要在main中求出然后传人
例三 参数传递类型
int fun(int *p) { } int fun2(int **p)//二级指针保存一级指针地址 { } int main() { int num=0; int arr[10]; int *p=# int*arr2[10] int **q=&p fun(&num); fun(p); fun(arr); fun2(&p); fun2(arr2); fun2(q); //fun2(&arr);error,数组的地址保存在一级指针中 return 0; }
数组的参数与指针的参数
数组参数 | 指针参数 |
数组的数组 char a[3][4] | 数组的指针(*)[4] |
指针数组 char*a[5] | 指针的指针 char** |
三维
char a[3][4][5] char[*p][4][5]