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;
}
根據上面執行個體可以看到,淺複制僅複制對象本身(其中包括是指針的成員),這樣不同被複制對象的成員中的對應非空指針會指向同一對象,被成員指針引用的對象成為共享的,無法直接通過指針成員安全地删除(因為若直接删除,另外對象中的指針就會無效,形成所謂的野指針,而通路無效指針是危險的;
除非這些指針有引用計數或者其它手段確定被指對象的所有權);而深複制在淺複制的基礎上,連同指針指向的對象也一起複制,代價比較高,但是相對容易管理。