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;
}
根据上面实例可以看到,浅复制仅复制对象本身(其中包括是指针的成员),这样不同被复制对象的成员中的对应非空指针会指向同一对象,被成员指针引用的对象成为共享的,无法直接通过指针成员安全地删除(因为若直接删除,另外对象中的指针就会无效,形成所谓的野指针,而访问无效指针是危险的;
除非这些指针有引用计数或者其它手段确保被指对象的所有权);而深复制在浅复制的基础上,连同指针指向的对象也一起复制,代价比较高,但是相对容易管理。