[day04]数组类型基础、数组指针、多维数组的本质、指针数组
1.数组类型基础
1.int a[10] = {1,2}; |
a代表数组首元素的地址,不是整个数组的地址,数组首元素的类型。 &a 代表整个数组的地址,数组类型 int[10]。 &a与a代表的数据类型不一样。 这条结论可以通过第3点的两个printf得以验证,一个+20,一个加+4。 |
2. 1 int c[20] = {0}; 与 1 memset(c, 0, sizeof(c)); 区别 |
前者编译期间搞定,后者相当于手工使用一个循环搞定。 |
3.数组类型 |
1 typedef int(MyArr5)[5]; //声明一个数组类型 2 MyArr5 arr5; //相当于int arr5[5]; 3 4 /* 指针步长问题*/ 5 printf(“%d %d\n”, &arr5, &arr5 + 1); // +20 6 printf(“%d %d\n”, arr5, arr5 + 1); // +4 |
2.数组指针
1.数组首元素地址 |
1 int a[5] = {1, 3, 4, 55, 6}; 2 // a为数组首元素地址,是个常量指针,不能被修改; 3 a = 0x11; // 错误 |
2.间接数组指针定义 |
1 typedef int(MyArr5)[5]; //声明一个数组类型 2 MyArr5 *pArray = &a; //注意要&a,虽然不加&貌似也能得出正确结果 3 /* 相当于是数组中存了5个指针,循环打印时,使用*取值,再加下标访问即可。 如: */ 4 printf(“%d ”, (*pArray)[i]); |
3.直接数组指针定义 |
1 typedef int(*PMyArr5)[5]; //声明一个数组指针类型 2 PMyArr5 myp = NULL; 3 myp = &a; 4 5 printf(“%d ”, (*myp)[i]); 6 7 /* 直接一步了当 */ 8 int (*myparra)[5] = &a; |
3.多维数组的本质
1.对int myarray[3][5]; 中myarray的理解 |
myarray是数组首元素的地址 myarray是一个常量指针 myarray是一个数组指针 |
2.测试步长 |
1 #include <stdio.h> 2 3 int main(void) 4 { 5 //1 myarray数组首元素的地址吧 6 //2 myarray是一个常量指针 7 //3 myarray是一个数组指针 8 int myarray[3][5]; 9 10 printf("myarray:%d myarray+1:%d\n", myarray, myarray+1); //+20 11 printf("&myarray:%d &myarray+1:%d\n", &myarray, &myarray+1); //+60 12 13 return 0; 14 } |
3.数组指针操作 |
1 int (*p)[5] = myarray; // 直接赋值操作就行了 2 printf(“%d ”, p[i][j]); // 直接打印即可 |
4.一点总结 |
1 不管是几维数组,都是线性存储的。所以会存在多维数组做函数参数,退化问题。 2 多维数组做函数参数 二维数组,能勉强表达出来。但是三维数组,四维数组,就表达不出来了。 结论:指针做函数参数,有效内存维数,只到2级。如果你看到3级指针 4级指针,它表示的不是内存的维数。 |
1 *(*(myarray+i)+j )
直接就相当于 1 myarray[i][j]
|
5.二维数组强转成一维指针,打印。(线性存储) |
1 #include <stdio.h> 2 3 void printArr(int *a, int iNum) 4 { 5 int i; 6 for (i=0; i<iNum; i++) { 7 printf("%d ", a[i]); 8 } 9 } 10 11 int main(void) 12 { 13 int myarray[3][5]; 14 15 int i, j; 16 int tmp = 0; 17 18 for (i=0; i<3; i++) { 19 for (j=0; j<5; j++) { 20 *(*(myarray+i)+j) = tmp ++; 21 } 22 } 23 24 printArr((int *)myarray, 3*5); 25 26 return 0; 27 } |
6.二级指针第二种内存模型做函数参数(使用数组指针) |
原本第二种模型为 char arr[3][5] = {“abc”, “aaa”, “acd”}; Func: Func(char arr[3][5], int iNum); 根据一级指针传参推演过程: Func(char arr[5], int iNum)->Func(char arr[], int iNum)->Func(char *arr, int iNum); 得到二级指针传参推演过程: Func(char arr[3][5], int iNum)->Func(char arr[][5], int iNum)->Func(char (*arr)[5], int iNum);
|
4.指针数组
指针数组例子 |
1 #include <stdio.h> 2 3 int main(void) 4 { 5 //指针数组 6 char *p1[] = {"123", "456", "789"}; 7 int i; 8 9 printf("p1:%d p1+1:%d\n", p1, p1+1); // 4 10 printf("&p:%d &p1+1:%d\n", &p1, &p1+1); //12 11 12 for (i=0; i<3; i++) 13 printf("%s ", p1[i]); 14 15 return 0; 16 } |
可以当做二维数组理解?(不是说可以当作二维数组理解,无论是一维数组还是二维数组,&p1都是整个数组的地址,因为它是指针数组,它原生就是数组,只是存放指针而已)。 一样的p1代表首元素的地址,&p1代表整个数组的首地址? |
注意:在主函数中使用sizeof(p1)/sizeof(*p1)计算size是没有问题了,但是如果在被调用函数中使用这样的方法求是有问题的,因为数组做函数参数会退化,求出来就是1了。 |
指针数组应用场景 |
#include <stdio.h> #include <stdlib.h> // 场景1,main函数的参数 int main(int argc, char **argv, char **env) { // 可以直接打印argv以及env,不需要用到argc int i = 0; for (; argv[i] != NULL; i++){ printf("%s\n", argv[i]); } for (i=0; env[i] != NULL; i++){ printf("%s\n", env[i]); } //场景2,做菜单 char *pmenu[] = { "aa", "bb", "cc", 0 }; for (i = 0; pmenu[i] != NULL; i++) { printf("%s\n", pmenu[i]); } system("pause"); return 0; } |