2.2 二级指针做形参输出特性
二级指针做参数的输出特性是指由被调函数分配内存。
//被调函数,由参数n确定分配多少个元素内存 void allocate_space(int **arr,int n){ //堆上分配n个int类型元素内存 int *temp = (int *)malloc(sizeof(int)* n); if (NULL == temp){ return; } //给内存初始化值 int *pTemp = temp; for (int i = 0; i < n;i ++){ //temp[i] = i + 100; *pTemp = i + 100; pTemp++; } //指针间接赋值 *arr = temp; } //打印数组 void print_array(int *arr,int n){ for (int i = 0; i < n;i ++){ printf("%d ",arr[i]); } printf("\n"); } //二级指针输出特性(由被调函数分配内存) void test(){ int *arr = NULL; int n = 10; //给arr指针间接赋值 allocate_space(&arr,n); //输出arr指向数组的内存 print_array(arr, n); //释放arr所指向内存空间的值 if (arr != NULL){ free(arr); arr = NULL; } }
2.3 二级指针做形参输入特性
二级指针做形参输入特性是指由主调函数分配内存。
//打印数组 void print_array(int **arr,int n){ for (int i = 0; i < n;i ++){ printf("%d ",*(arr[i])); } printf("\n"); } //二级指针输入特性(由主调函数分配内存) void test(){ int a1 = 10; int a2 = 20; int a3 = 30; int a4 = 40; int a5 = 50; int n = 5; int** arr = (int **)malloc(sizeof(int *) * n); arr[0] = &a1; arr[1] = &a2; arr[2] = &a3; arr[3] = &a4; arr[4] = &a5; print_array(arr,n); free(arr); arr = NULL; }
2.4 强化训练_画出内存模型图
void mian() { //栈区指针数组 char *p1[] = { "aaaaa", "bbbbb", "ccccc" }; //堆区指针数组 char **p3 = (char **)malloc(3 * sizeof(char *)); //char *array[3]; int i = 0; 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); } }
2.4 多级指针
将堆区数组指针案例改为三级指针案例:
//分配内存 void allocate_memory(char*** p, int n){ if (n < 0){ return; } char** temp = (char**)malloc(sizeof(char*)* n); if (temp == NULL){ return; } //分别给每一个指针malloc分配内存 for (int i = 0; i < n; i++){ temp[i] = malloc(sizeof(char)* 30); sprintf(temp[i], "%2d_hello world!", i + 1); } *p = 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; } char** temp = *buf; for (int i = 0; i < len; i++){ free(temp[i]); temp[i] = NULL; } free(temp); } void test(){ int n = 10; char** p = NULL; allocate_memory(&p, n); //打印数组 array_print(p, n); //释放内存 free_memory(&p, n); }
2.5 深拷贝和浅拷贝
如果2个程序单元(例如2个函数)是通过拷贝 他们所共享的数据的 指针来工作的,这就是浅拷贝,因为真正要访问的数据并没有被拷贝。如果被访问的数据被拷贝了,在每个单元中都有自己的一份,对目标数据的操作相互 不受影响,则叫做深拷贝。
#include <iostream> using namespace std; class CopyDemo { public: CopyDemo(int pa,char *cstr) //构造函数,两个参数 { this->a = pa; this->str = new char[1024]; //指针数组,动态的用new在堆上分配存储空间 strcpy(this->str,cstr); //拷贝过来 } //没写,C++会自动帮忙写一个复制构造函数,浅拷贝只复制指针,如下注释部分 //CopyDemo(CopyDemo& obj) //{ // this->a = obj.a; // this->str = obj.str; //这里是浅复制会出问题,要深复制 //} CopyDemo(CopyDemo& obj) //一般数据成员有指针要自己写复制构造函数,如下 { this->a = obj.a; // this->str = obj.str; //这里是浅复制会出问题,要深复制 this->str = new char[1024];//应该这样写 if(str != 0) strcpy(this->str,obj.str); //如果成功,把内容复制过来 } ~CopyDemo() //析构函数 { delete str; } public: int a; //定义一个整型的数据成员 char *str; //字符串指针 }; int main() { CopyDemo A(100,"hello!!!"); CopyDemo B = A; //复制构造函数,把A的10和hello!!!复制给B cout <<"A:"<< A.a << "," <<A.str << endl; //输出A:100,hello!!! cout <<"B:"<< B.a << "," <<B.str << endl; //输出B:100,hello!!! //修改后,发现A,B都被改变,原因就是浅复制,A,B指针指向同一地方,修改后都改变 B.a = 80; B.str[0] = 'k'; cout <<"A:"<< A.a << "," <<A.str << endl; //输出A:100,kello!!! cout <<"B:"<< B.a << "," <<B.str << endl; //输出B:80,kello!!! return 0; }
根据上面实例可以看到,浅复制仅复制对象本身(其中包括是指针的成员),这样不同被复制对象的成员中的对应非空指针会指向同一对象,被成员指针引用的对象成为共享的,无法直接通过指针成员安全地删除(因为若直接删除,另外对象中的指针就会无效,形成所谓的野指针,而访问无效指针是危险的;
除非这些指针有引用计数或者其它手段确保被指对象的所有权);而深复制在浅复制的基础上,连同指针指向的对象也一起复制,代价比较高,但是相对容易管理。