本文将介绍二级指针做函数输出以及做函数输入的三种内存模型从内存四区的角度对程序执行的过程进行剖析,通过这中方式来加深对指针的理解。
二级指针做输出(在被调函数中分配内存)模型:
主函数:
1 2 3 4 5 6 7 8 9
| int main() { char *p = NULL; int len = 0; getMem(&p, &len); printf("p=%s\n", p); FreeMem(&p); return 0; }
|
getMem函数:
1 2 3 4 5 6 7 8 9 10 11 12 13
| int getMem(char **myp,int *mylen) { char *temp = NULL; temp = (char*)malloc(100); if (temp == NULL) { return -1; } strcpy(temp, "abcdefg"); *mylen = strlen(temp); *myp = temp; return 0; }
|
犯的错误:
*myp = temp;
最初写成了*myp = *temp;
而该表达式赋值两端根本不是一种数据类型。
*myp = temp1;
这句话与*mylen = 某一数值
本质上是一样的,都是*
加上指针变量来改变主调用函数中的内容只不过,myp
为二级指针因此赋值的右端应为一级指针。
补充:
"abcdefg"
在常量区中,strcpy(temp, "abcdefg");
这一句使得temp
指向"abcdefg"
,其值为字符'a'
的地址。
总结:
想要在被调用函数中修改主调用函数中的值,必须使用指针,例如在getMem函数中,修改变量的值使用一级指针,修改一级指针需要用到二级指针。
FreeMem函数:
1 2 3 4 5 6 7 8 9 10 11
| void FreeMem(char **myp) { if (myp == NULL) { return; } char *tmp = NULL; tmp = *myp; free(tmp); tmp = NULL; }
|
1 2 3 4 5 6 7 8
| void FreeMem(char *myp) { if(myp = NULL) { return ; } free(myp); }
|
这两种FreeMem
函数都可以释放p
指向的内存,但第一个函数的好处在于使用了二级指针,可在FreeMem
函数中将主调用函数中的p
的值改为NULL
避免
野指针的出现,而第二个函数则要在FreeMem
后加上一句p=NULL
。
调试结果:
二级指针做输入(在主调用函数中分配内存)模型一:
指针数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include<stdio.h> #include<stdlib.h> #include<string.h> int main() { char *myArray[] = { "xcccc","ybbbb","zaaaa" }; int len = sizeof(myArray) / sizeof(myArray[0]); int i = 0; for (i = 0; i < len; i++) { printf("%s\n", myArray[i]); } int j, k; j = k = 0; char *temp = NULL; for (j = 0; j < len - 1; j++) { for (k = 0; k < len - j - 1; k++) { if (strcmp(myArray[k], myArray[k + 1]) > 0) { temp = myArray[k]; myArray[k] = myArray[k + 1]; myArray[k + 1] = temp; } } } for (i = 0; i < len; i++) { printf("%s\n", myArray[i]); } return 0; }
|
总结:
1.在32位操作系统下指针变量的长度为4,在64位下为8。
2.指针数组为元素为指针的数组,myArray
数组中有三个元素,sizeof(myArray) / sizeof(myArray[0])
可以求出数组长度。
3.排序使用的为最简单的冒泡排序。排序过程中交换的是指针而不是内存块。
二级指针做输入模型一封装函数:
主函数:
1 2 3 4 5 6 7 8 9 10 11 12
| int main() { char *myArray[] = { "zzz","yyyyyyy","xxxxxxxxx" }; int len = sizeof(myArray) / sizeof(myArray[0]);
printArray(myArray, len);
SortArray(myArray, len); printArray(myArray, len);
return 0; }
|
打印函数:
1 2 3 4 5 6 7
| void printArray(char **myArray, int len) { for (int i = 0; i < len; i++) { printf("%s\n", myArray[i]); } }
|
排序函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void SortArray(char **myArray, int len) { char *temp = NULL; for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - 1 - i; j++) { if (strcmp(myArray[j], myArray[j + 1]) > 0) { temp = myArray[j]; myArray[j] = myArray[j + 1]; myArray[j + 1] = temp; } } } }
|
总结:
数组在做函数参数是退化为指针,数组名指向数组的第一个元素,即数组名中存放的是数组中第一个元素的地址。指针数组也是如此,char *myArray[];
中定义了一个名为myArray
的指针数组,根据上面的说明,myArray
为第一个元素的地址,而数组元素为指向char
类型的指针,即为char *
类型,因此myArray
为char **
类型,所以在函数中第一个参数,均为char **myArray
。
二级指针做输入(在主调用函数中分配内存)模型二:
二维数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include<stdio.h> #include<stdlib.h> #include<string.h> int main() { char myArray[10][30] = { "ddddd","ccccc","bbbbb","aaaaa" }; int num = 4; for (int i = 0; i < num; i++) { printf("%s\n", myArray[i]); } char temp[30]; for (int i = 0; i < num - 1; i++) { for (int j = 0; j < num - 1 - i; j++) { if (strcmp(myArray[j], myArray[j + 1]) > 0) { strcpy(temp, myArray[j]); strcpy(myArray[j], myArray[j + 1]); strcpy(myArray[j + 1], temp); } } } for (int i = 0; i < num; i++) { printf("%s\n", myArray[i]); } return 0; }
|
二级指针做输入模型二封装函数:
主函数:
1 2 3 4 5 6 7 8 9
| int main() { char myArray[10][30] = { "ddddd","ccccc","bbbbb","aaaaa" }; int num = 4; printArray(myArray, num); SortArray(myArray, num); printArray(myArray, num); return 0; }
|
打印函数:
1 2 3 4 5 6 7
| void printArray(char (*myArray)[30], int len) { for (int i = 0; i < len; i++) { printf("%s\n", myArray[i]); } }
|
排序函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void SortArray(char (*myArray)[30], int len) { char temp[30]; for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - 1 - i; j++) { if (strcmp(myArray[j], myArray[j + 1]) > 0) { strcpy(temp, myArray[j]); strcpy(myArray[j], myArray[j + 1]); strcpy(myArray[j + 1], temp); } } } }
|
总结:
二维数组在做函数参数的时候会退化成为一个指针数组。
二维数组中重要的两个点:
1.二维数组名为第一维首元素的地址。
2.一维数组名为首元素的地址。
有了这两点下面将演示如何用数组名打印某一个元素:
1 2 3 4 5 6 7
| ==> 表示等价 myArray ==> &myArray[0] myArray + 2 ==> &myArray[2] *(myArray + 2) ==> myArray[2] ==> &myArray[2][0] *(myArray + 2) + 1 ==> &myArray[2][1] *(myArray + 2) + 4 ==> &myArray[2][4] *(*(myArray + 2) + 4) ==> myArray[2][4]
|
二级指针做输入(在主调用函数中分配内存)模型三:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include<stdio.h> #include<stdlib.h> #include<string.h> int main() { char **p = NULL; int num = 4; p = (char**)malloc(sizeof(char*)*num); for (int i = 0; i < num; i++) { p[i] = (char*)malloc(sizeof(char) * 100); sprintf(p[i], "%d%d%d", 4 - i, 4 - i, 4 - i); } for (int i = 0; i < num; i++) { printf("%s\n", p[i]); } char *temp = NULL; for (int i = 0; i < num - 1; i++) { for (int j = 0; j < num - i - 1; j++) { if (strcmp(p[j], p[j + 1]) > 0) { temp = p[j]; p[j] = p[j + 1]; p[j + 1] = temp; } } } for (int i = 0; i < num; i++) { printf("%s\n", p[i]); } for (int i = 0; i < num; i++) { if (p[i] != NULL) { free(p[i]); p[i] = NULL; } } if (p != NULL) { free(p); p = NULL; } return 0; }
|
二级指针做输入模型三封装函数:
主函数:
1 2 3 4 5 6 7 8 9 10 11 12
| int main() { int num = 4; char **p = NULL; getMem_1(&p, num); printArray(p, num); SortArray(p, num); printArray(p, num); myArrayFree(p, num); return 0; }
|
getMem函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| char **getMem(int num) { char **p = NULL; p = (char**)malloc(sizeof(char*)*num); for (int i = 0; i < num; i++) { p[i] = (char*)malloc(sizeof(char) * 100); sprintf(p[i], "%d%d%d", 4 - i, 4 - i, 4 - i); } return p; } int getMem_1(char ***p, int num) { if (p == NULL) { return -1; } char **temp = NULL; temp = (char**)malloc(sizeof(char*)*num); for (int i = 0; i < num; i++) { temp[i] = (char*)malloc(sizeof(char) * 100); sprintf(temp[i], "%d%d%d", 4 - i, 4 - i, 4 - i); } *p = temp; return 0; }
|
打印函数:
1 2 3 4 5 6 7
| void printArray(char **myArray, int len) { for (int i = 0; i < len; i++) { printf("%s\n", myArray[i]); } }
|
排序函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void SortArray(char **myArray, int len) { char *temp = NULL; for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - 1 - i; j++) { if (strcmp(myArray[j], myArray[j + 1]) > 0) { temp = myArray[j]; myArray[j] = myArray[j + 1]; myArray[j + 1] = temp; } } } }
|
Free函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void myArrayFree(char **p,int len) { for (int i = 0; i < len; i++) { if (p[i] != NULL) { free(p[i]); p[i] = NULL; } } if (p != NULL) { free(p); p = NULL; } }
|