2.2.3 指针数组(元素为指针)
2.2.3.1 栈区指针数组
//数组做函数函数,退化为指针 void array_sort(char** arr,int len){ for (int i = 0; i < len; i++){ for (int j = len - 1; j > i; j --){ //比较两个字符串 if (strcmp(arr[j-1],arr[j]) > 0){ char* temp = arr[j - 1]; arr[j - 1] = arr[j]; arr[j] = temp; } } } } //打印数组 void array_print(char** arr,int len){ for (int i = 0; i < len;i++){ printf("%s\n",arr[i]); } printf("----------------------\n"); } void test(){ //主调函数分配内存 //指针数组 char* p[] = { "bbb", "aaa", "ccc", "eee", "ddd"}; //char** p = { "aaa", "bbb", "ccc", "ddd", "eee" }; //错误 int len = sizeof(p) / sizeof(char*); //打印数组 array_print(p, len); //对字符串进行排序 array_sort(p, len); //打印数组 array_print(p, len); }
2.2.3.2 堆区指针数组
//分配内存 char** allocate_memory(int n){ if (n < 0 ){ return NULL; } char** temp = (char**)malloc(sizeof(char*) * n); if (temp == NULL){ return NULL; } //分别给每一个指针malloc分配内存 for (int i = 0; i < n; i ++){ temp[i] = malloc(sizeof(char)* 30); sprintf(temp[i], "%2d_hello world!", i + 1); } return temp; } //打印数组 void array_print(char** arr,int len){ for (int i = 0; i < len;i++){ printf("%s\n",arr[i]); } printf("----------------------\n"); } //释放内存 void free_memory(char** buf,int len){ if (buf == NULL){ return; } for (int i = 0; i < len; i ++){ free(buf[i]); buf[i] = NULL; } free(buf); } void test(){ int n = 10; char** p = allocate_memory(n); //打印数组 array_print(p, n); //释放内存 free_memory(p, n); }
2.2.4二维数组三种参数形式
2.2.4.1 二维数组的线性存储特性
void PrintArray(int* arr, int len){ for (int i = 0; i < len; i++){ printf("%d ", arr[i]); } printf("\n"); } //二维数组的线性存储 void test(){ int arr[][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; int arr2[][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int len = sizeof(arr2) / sizeof(int); //如何证明二维数组是线性的? //通过将数组首地址指针转成Int*类型,那么步长就变成了4,就可以遍历整个数组 int* p = (int*)arr; for (int i = 0; i < len; i++){ printf("%d ", p[i]); } printf("\n"); PrintArray((int*)arr, len); PrintArray((int*)arr2, len); }
2.2.4.2 二维数组的3种形式参数
//二维数组的第一种形式 void PrintArray01(int arr[3][3]){ for (int i = 0; i < 3; i++){ for (int j = 0; j < 3; j++){ printf("arr[%d][%d]:%d\n", i, j, arr[i][j]); } } } //二维数组的第二种形式 void PrintArray02(int arr[][3]){ for (int i = 0; i < 3; i++){ for (int j = 0; j < 3; j++){ printf("arr[%d][%d]:%d\n", i, j, arr[i][j]); } } } //二维数组的第二种形式 void PrintArray03(int(*arr)[3]){ for (int i = 0; i < 3; i++){ for (int j = 0; j < 3; j++){ printf("arr[%d][%d]:%d\n", i, j, arr[i][j]); } } } void test(){ int arr[][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; PrintArray01(arr); PrintArray02(arr); PrintArray03(arr); }
2.3总结
2.3.1 编程提示
源代码的可读性几乎总是比程序的运行时效率更为重要
只要有可能,函数的指针形参都应该声明为 const。
在多维数组的初始值列表中使用完整的多层花括号提高可读性
2.3.2 内容总结
在绝大多数表达式中,数组名的值是指向数组第 1 个元素的指针。这个规则只有两个例外,sizeof 和对数组名&。
指针和数组并不相等。当我们声明一个数组的时候,同时也分配了内存。但是声明指针的时候,只分配容纳指针本身的空间。
当数组名作为函数参数时,实际传递给函数的是一个指向数组第 1 个元素的指针。
我们不单可以创建指向普通变量的指针,也可创建指向数组的指针。