知名企业门户网站建设,仿牌外贸网站制作,广东省住建部官网,采购系统erp软件文章目录1 二维指针#xff08;指向指针的指针#xff09;2 二维数组3 二维数组的类型3.2 如何动态申请二维数组4 总结1 二维指针#xff08;指向指针的指针#xff09;
指针的本质是变量指针的指针是保存指针变量的地址。如下面的代码#xff1a; 为什么需要指向指针的存… 文章目录1 二维指针指向指针的指针2 二维数组3 二维数组的类型3.2 如何动态申请二维数组4 总结 1 二维指针指向指针的指针
指针的本质是变量指针的指针是保存指针变量的地址。如下面的代码 为什么需要指向指针的存在还记得之前学习的过程中说的函数传值调用和传址调用么当要在函数内部修改传进来参数变量的时候需要传址调用。
同理如果传进来的本来就是一个指针想要修改该指针那么就需要传指向该指针的指针了。道理是一样的。看下面的代码就明白了
代码34-1.c函数reset为重新为某一段内存分配一段内存空间可大可小
#include stdio.h
#include malloc.h/* 想要修改p指向的内容且p的地址也是会变的就必须使用传址调用。传p的地址。就是双指针 */
int reset(char** p, int old_size, int new_size){int ret 1;int i 0;int len 0;char* pp *p;char* pt NULL;char* tmp NULL;if((NULL!p) (new_size0)){pt (char*)malloc(new_size);tmp pt;len (old_size new_size) ? old_size : new_size;for(i0; ilen; i){*tmp *pp;tmp;pp; }free(*p);*ppt;}else{ret 0;}return ret;
}int main(){char* p (char*)malloc(5);printf(p %p\n,p);if(reset(p, 5, 8)){printf(reset p %p\n,p);}else{printf(no reset!\n);}free(p);return 0;
}编译运行结果为
p 0x8833008 reset p 0x8833018 分析 上述代码中reset函数是重新为一块内存分配另一个内存空间。我们知道要分配另一块空间的话地址肯定是会变的那么想要最终将原来的地址p改变就需要进行传址调用。因为p本来就是指针所以需要传指针的指针进入reset函数。在reset函数中进行重新分配内存空间并将原有的内存空间中的值拷贝到新的内存地址处。具体自己好好看一下reset函数就可以理解。 由运行可以看出
地址p确实改变了说明传址调用起了作用注意理解指向指针的指针的意义与用法。需要多琢磨。
2 二维数组
在C语言中没有二维数组的概念。它只是另一种形式的一维数组。
二维数组在内存中是以一维数组的形式排布二维数组的第一维是一维数组注意一维数组相当于一个常量指针也就说二维数组的第一维是存的指针二维数组的第二维是具体存的数值既然一维数组的数组名可以看成是常量指针那么二维数组的数组名也同样可以看成是常量指针结合上述四条看看下图中的二维数组在内存中的样式 结合下面的代码来认识认识二维数组
代码34-2.c
#include stdio.hvoid print_array(int a[], int size){printf(print_array:sizeof(array) %d\n,sizeof(a));int i 0;for(i0; isize; i){printf(%d ,a[i]);}printf(\n);
}
int main(){int a[3][3] {{0,1,2},{3,4,5},{6,7,8}}; int* p a[0][0];int i0,j0;for(i0; i3; i){for(j0; j3; j){printf(%d, , a[i][j]);}printf(\n);}printf(\n);for(i0; i3; i){for(j0; j3; j){printf(%d, , *(*(ai)j));}printf(\n);}printf(a %p, a1 %p\n,a,a1);printf(a %p, a1 %p\n,a,a1);printf(p %p, p1 %p\n,p,p1);printf(\n);print_array(p,9);return 0;
}编译运行结果为
分析
上述代码并不是很难所以不做详细分析。只做以下几点说明 可以像这样访问二维数组*(*(ai)j) 。可以想这样理解 其中ai 代表是一维数组的第i个元素即指针*(ai)代表找到第i个一维数组的起始地址*(ai)j 表示第i个一维数组中的第j个元素的地址。最终*(*(ai)j) 表示取出元素。可以参考上面的二维数组的内存图。 由a 0xbfb71b00, a1 0xbfb71b0c 知道二维数组的名字a可以看成是一个常量指针它的值为二维数组首元素这个首元素相当于是一个一维数组的地址值。a1就直接跨过一个一维数组的长度这里是12三个int。 由a 0xbfb71b00, a1 0xbfb71b24 知道 a 代表整个数组的地址这与一维数组很相似。a1 就直接跨过整个数组的大小到数组末尾 由print_array 函数的参数是一维数组知道二维数组在内存中排布是一维数组的形式。参考上图。
3 二维数组的类型
之前学过以为数组的类型如下
int a[5] a的类型为 int*
二维数组的类型为
int a[2][5] a的类型为int(*)[5]
二维数组名可以看做是指向数组的常量指针二维数组可以看成是一维数组中存的元素类型是一个同类型的一维数组
3.2 如何动态申请二维数组
从下面的代码来学习如何动态申请二维数组参考下面的二维数组的内存模型就可以理解下面的代码
代码34-3.c
#include stdio.h
#include malloc.hint** malloc2d(int row, int col){int** ret NULL;if(row0 col0){ret (int**)malloc(row*sizeof(int*)); //相当于申请一个一维数组存的元素是指针int* p (int*)malloc(row*col*sizeof(int));//相当于二维数组在内存中的一维排布指针p指向这个一维排布if(NULL!p NULL!ret){int i 0;for(i0; irow; i){ret[i] p i*col; // ret[i]存的是一个个指针指向的数组每个数组长度是col可以参考下图的二维数组内存模型}}else{free(ret);free(p);ret NULL;}}return ret;
}void free2d(int** p){if(NULL ! *p){free(*p);}free(p);
}
int main(){int** a malloc2d(3,3);int i0,j0;for(i0; i3; i){for(j0; j3; j){printf(a[%d][%d] %d,, i,j,a[i][j]);}printf(\n);} free2d(a);return 0;
}编译运行代码如下 虽然上述的数组中的各个值都是0但是我们要知道malloc申请后的内存中的值是不确定的并不一定是0 分析
上述代码中的核心代码已经标注多画图分析即可可以参考下面的二维数组的内存模型图进行分析 至此就学会了如何动态的申请二维数组了。一位数组的动态申请比较简单之前的文章也有学习过。
4 总结
C语言中只支持一维数组所谓的二维数组在内存中依然是以一维数组的形式排布C语言中的数组大小必须在编译期就作为常数确定。毕竟数组的大小是数组类型的一部分类型都不确定好如何编译二维数组就是一个一维数组存的元素是同类型的数组而已