天天看點

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

      

根據上面執行個體可以看到,淺複制僅複制對象本身(其中包括是指針的成員),這樣不同被複制對象的成員中的對應非空指針會指向同一對象,被成員指針引用的對象成為共享的,無法直接通過指針成員安全地删除(因為若直接删除,另外對象中的指針就會無效,形成所謂的野指針,而通路無效指針是危險的;

除非這些指針有引用計數或者其它手段確定被指對象的所有權);而深複制在淺複制的基礎上,連同指針指向的對象也一起複制,代價比較高,但是相對容易管理。

程式員必備硬核資料,點選下載下傳

繼續閱讀