10W+字C语言硬核总结(七),值得阅读收藏!

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;
}

根据上面实例可以看到,浅复制仅复制对象本身(其中包括是指针的成员),这样不同被复制对象的成员中的对应非空指针会指向同一对象,被成员指针引用的对象成为共享的,无法直接通过指针成员安全地删除(因为若直接删除,另外对象中的指针就会无效,形成所谓的野指针,而访问无效指针是危险的;


除非这些指针有引用计数或者其它手段确保被指对象的所有权);而深复制在浅复制的基础上,连同指针指向的对象也一起复制,代价比较高,但是相对容易管理。

程序员必备硬核资料,点击下载

上一篇:10W+字C语言硬核总结(八),值得阅读收藏!


下一篇:java对数据库的操作