二级指针内存模型建立
void main2() { int i = 0;
//指针数组 char * p1[] = { "123", "456", "789" };//二级指针的第一种内存模型
//二维数组 char p2[3][4] = { "123", "456", "789" };//二级指针的第二种内存模型
//手工二维内存: 二级指针的第三种内存模型 char **p3 = (char **)malloc(3 * sizeof(char *)); //int array[3]; for (i = 0; i<3; i++) { p3[i] = (char *)malloc(10 * sizeof(char)); //char buf[10]
sprintf(p3[i], "%d%d%d", i, i, i); } } |
数组类型和多维数组本质
数组概念
概念
- 1)元素类型角度:数组是相同类型的变量的有序集合
- 2)内存角度:联系的一大片内存空间
数组初始化
- //数组元素的个数可以显示或隐式指定
- //分析数组初始化{0}与memset比较 →https://blog.csdn.net/ace_fei/article/details/7448368 这一个博客已经分析的很透彻了.向大神膜拜!
int main() { int i = 0; int a[10] = { 1,2 }; //其他初始化为0 int b[] = { 1, 2 }; int c[20] = { 0 };
for (i = 0; i<10; i++) { printf("%d ", a[i]); } memset(a, 0, sizeof(a)); getchar(); return 0; } |
数组名的技术盲点
- 1)数组首元素的地址和数组地址是两个不同的概念
-
2)数组名代表数组首元素的地址,它是个常量。
- 解释如下:变量本质是内存空间的别名,一定义数组,就分配内存,内存就固定了。所以数组名起名以后就不能被修改了。
- 3)数组首元素的地址和数组的地址值相等
- 4、怎么样得到整个一维数组的地址?
C语言规定:
int a[10];
printf("得到整个数组的地址a: %d \n", &a);
printf("数组的首元素的地址a: %d \n", a);
//虽然值是一样的,但是代表的意思是不一样的.
怎么样表达int a[10]这种数据类型? 为int[10]类型.
数组类型、数组指针类型、数组指针类型变量
数组类型
- 1数据类型分为基础、非基础,思考角度应该发生变化
-
2 C语言中的数组有自己特定的类型
- 数组的类型由元素类型和数组大小共同决定
- 例:int array[5]的类型为int[5]
- 3定义 数组类型,并用数组类型定义变量
int main() { typedef int i = 0; MYINT5 array; for (i = 0; i<5; i++) { array[i] = i; }
for (i = 0; i<5; i++) { printf("%d ", array[i]); }
getchar(); return 0; } |
数组指针类型
- 数组指针用于指向一个数组
int a[10]
数组名是数组首元素的起始地址,但并不是数组的起始地址
通过将取地址符&作用于数组名可以得到整个数组的起始地址
//定义数组指针 有两种
1)通过数组类型定义数组指针:
typedef
int(ArrayType)[5];
int *a;
ArrayType* pointer;
2) 声明一个数组指针类型
typedef int(*MyPointer)[5];
MyPointer myPoint;
3)直接定义:
int (*pointer)[n];
pointer 为数组指针变量名
type 为指向的数组的类型
n 为指向的数组的大小
注意这个地方是type类型(比如 int (*pointer)[10])
- 数组指针:用数组类型加*定义一个数组指针
int mian() { int a[5]; //声明一个数组类型 typedef //用数组类型 加*,定义一个数组指针变量 MYINT5 *array; array = &a; for (i = 0; i<5; i++) { (*array)[i] = i; } // for (i = 0; i<5; i++) { printf("\n%d %d", a[i], (*array)[i]); } } |
数组指针:定义一个数组指针类型,然后用类型定义变量
int b[5]; //声明一个数组指针类型 typedef //用数组指针类型,去定义一个变量 MyPointer mypoint; mypoint = &b; for (i = 0; i<5; i++) { (*mypoint)[i] = i; } // for (i = 0; i<5; i++) { printf("\n%d %d", b[i], (*mypoint)[i]); } } |
//3数组指针:直接定义一个数组指针变量
{ int c[5]; //直接声明一个数组指针变量 int(*pointer)[5] = &c; for (i = 0; i<5; i++) { (*pointer)[i] = i; } for (i = 0; i<5; i++) { printf("\n%d %d", c[i], (*pointer)[i]); } } |
多维数组本质技术推演
//int a[10]; //char myarray[3][5] PK int(*p)[5] //myarray名称到底是什么? //多维数组char a[i][j] == > *(*(a + i) + j)转换技巧分析 void main() { int a[3][5];
int c[5]; //&c + 1; int b[10]; //b代表数组首元素的地址 &b代表这个数组的地址 &b+1相当于 指针后移4*10个单位
//a代表什么什么那?a是一个数组指针 指向低维数组的指针 //a +1; → 跳5*4(int)个字节的内存 printf("a:%d, a+1:%d \n", a, a + 1); //4*5
{ int i = 0, j = 0, tmp = 0; for (i = 0; i<3; i++) { for (j = 0; j<5; j++) { a[i][j] = ++tmp; } }
printf("\n"); for (i = 0; i<3; i++) { for (j = 0; j<5; j++) { printf("%d \n", a[i][j]); } } }
//a的本质是一个数组指针,每次往后跳一维的维数 { int i = 0, j = 0; //定义了一个数组指针 变量 int(*myArrayPoint)[5]; //告诉编译给我开辟五个四字节内存 myArrayPoint = a; printf("\n"); for (i = 0; i<3; i++) { for (j = 0; j<5; j++) { //myArrayPoint[i][j] = ++tmp; printf("%d \n", myArrayPoint[i][j]); } } }
/* char cbuf[30]; // cbuf(1级指针) 代表数组首元素的地址 &cbuf(二级指针) 代表整个数组的地址 char array[10][30]; //array是二级指针 (array+i) //相当于 整个第i行的数组地址 //二级指针 &cbuf
(*(array+i))//一维数组的首地址 cbuf
(*(array+i))+j //相当于第i行第j列的地址 &array[i][j]
*((*(array+i))+j) //相当于第i行第j列的元素 <====> array[i][j] */ } |
结论:a是一个指向int myarray[5]的数组指针 a+1 向后跳5*4,跳一行。
多维数组做函数参数退化原因大剖析
//证明一下多维数组的线性存储 //线性打印
void printfArray411(int *array, int { int i = 0; for (i = 0; i<num; i++) { printf("%d ", array[i]); } }
void printfArray412(int(*array)[5], int { return; }
void printfArrr333(int { return; } void main() { int a[3][5]; int c[3][4][5]; int i, j = 0; int tmp = 0; for (i = 0; i<3; i++) { for (j = 0; j<5; j++) { a[i][j] = tmp++; } }
printfArray411((int *)a, 15);
system("pause"); } |
多维数组做函数参数技术推演
|
int fun(char a[20], size_t b){ printf("%d\t%d",b,sizeof(a)); } |
原因1:高效 原因2:C语言处理a[n]的时候,它没有办法知道n是几,它只知道&n[0]是多少,它的值作为参数传递进去了;虽然c语言可以做到直接int fun(char a[20]),然后函数能得到20这个数字,但是,C没有这么做。 |
2、二维数组参数同样存在退化的问题 |
二维数组可以看做是一维数组 二维数组中的每个元素是一维数组 二维数组参数中第一维的参数可以省略 void f(int a[5]) ====》void f(int a[]); ===》 void f(int* a); void g(int a[3][3])====》 void g(int a[][3]); ====》 void g(int (*a)[3]); |
3、等价关系 |
数组参数 等效的指针参数
一维数组 char a[30] 指针 char* 指针数组 char *a[30] 指针的指针 char **a 二维数组 char a[10][30] 数组的指针 char(*a)[30] |
指针数组的应用场景
指针数组的两种用法(菜单 命令行(argv*[]))
操作系统拉起应用 在框架下干活
字符数组自我结束标志
// NULL 0 '\0'
实际上NULL==0=='\0'=0
强化训练
int sort(char *p[], int count, char **p, int *ncount);
int sort(char *p[], int count, char (*p)[30], int *ncount);
int sort(char (*p)[30], int ncount, char **p, int *ncount);
//把第一种内存模型和第二种内存模型的结果copy到第三种内存模型中,并排序,打印
char ** sort(char **p1, int num1, char (*p)[30], int num2, int *num3 );
int getArray3_Free(char **p3, int { int i; if (p3 == NULL) { return -1; } for (i = 0; i<p3num; i++) { if (p3[i] != NULL) { free(p3[i]); } } free(p3); }
int getArray3_Free2(char ***p3, int { int i; char **tmp = NULL;
if (p3 == NULL) { return -1; } tmp = *p3;
for (i = 0; i<p3num; i++) { if (tmp[i] != NULL) { free(tmp[i]); } } free(tmp);
*p3 = NULL; //通过间接赋值,去间接的修改实参的值,成0 }
int getArray3_2(char **myp1, int { int ret = 0; int i, j; int tmpNum3 = 0;
char **tmpp3 = NULL; char *temp;
/* printf("111111111"); if (*myp3 ==NULL ) { printf("222222222"); } */ printf("33333"); if (myp1 == NULL || myp2 == NULL || num3 == NULL || myp3 == NULL) { ret = -1; return ret; } //准备内存 tmpNum3 = num1 + num2; //分配第一维 tmpp3 = (char **)malloc(tmpNum3 * sizeof(char *)); if (tmpp3 == NULL) { return NULL; }
//分配第二维 把第一种内存模型数据和第二种内存模型数据,copy到第3中内存模型中 for (i = 0; i<num1; i++) { tmpp3[i] = (char *)malloc(strlen(myp1[i]) + 1); if (tmpp3[i] == NULL) { puts("out of space"); return NULL; } strcpy(tmpp3[i], myp1[i]); } for (j = 0; j<num2; j++, i++) { tmpp3[i] = (char *)malloc(strlen(myp2[j]) + 1); //note modify if (tmpp3[i] == NULL) { puts("out of space"); return NULL; } strcpy(tmpp3[i], myp2[j]); }
//排序 for (i = 0; i<tmpNum3; i++) { for (j = i + 1; j<tmpNum3; j++) { if (strcmp(tmpp3[i], tmpp3[j])>0) { temp = tmpp3[i]; tmpp3[i] = tmpp3[j]; tmpp3[j] = temp; } } }
//通过间接赋值,把结果甩给实参 *num3 = tmpNum3; *myp3 = tmpp3; //*0 = 100; return ret; }
char **getArray3(char **myp1, int { int i, j; int tmpNum3 = 0;
char **tmpp3 = NULL; char *temp;
if (myp1 == NULL || myp2 == NULL || num3 == NULL) { return NULL; } //准备内存 tmpNum3 = num1 + num2; //分配第一维 tmpp3 = (char **)malloc(tmpNum3 * sizeof(char *)); if (tmpp3 == NULL) { return NULL; }
//分配第二维 把第一种内存模型数据和第二种内存模型数据,copy到第3中内存模型中 for (i = 0; i<num1; i++) { tmpp3[i] = (char *)malloc(strlen(myp1[i]) + 1); if (tmpp3[i] == NULL) { puts("out of space"); return NULL; } strcpy(tmpp3[i], myp1[i]); } for (j = 0; j<num2; j++, i++) { tmpp3[i] = (char *)malloc(strlen(myp2[j]) + 1); //note if (tmpp3[i] == NULL) { puts("out of space"); return NULL; } strcpy(tmpp3[i], myp2[j]); }
//排序 for (i = 0; i<tmpNum3; i++) { for (j = i + 1; j<tmpNum3; j++) { if (strcmp(tmpp3[i], tmpp3[j])>0) { temp = tmpp3[i]; tmpp3[i] = tmpp3[j]; tmpp3[j] = temp; } } }
*num3 = tmpNum3; return tmpp3; }
void main() { int num3 = 0, i = 0; int ret = 0; char *p1[] = { "222222", "1111111", "33333333" }; char p2[4][30] = { "bbbbb", "aaaaa", "zzzzzz", "ccccccc" }; char **p3 = NULL; char ***myerrp3 = NULL;
//p3 = getArray3(p1, 3, p2, 4, &num3); //ret = getArray3_2(p1,3, p2, 4, &p3, &num3); ret = getArray3_2(p1, 3, p2, 4, 0, &num3); //错误做法 if (ret != 0) { return; } for (i = 0; i<num3; i++) { printf("%s \n", p3[i]); }
//getArray3_Free(p3, num3); // p3=NULL; getArray3_Free2(&p3, num3);
printf("p3:%d \n", p3);
system("pause"); } |