做網(wǎng)站 單頁數(shù)量網(wǎng)絡營銷的步驟
前言
指針變量作為參數(shù)傳遞時,很容易混淆指針本身和指針指向的內(nèi)容,實際應用中可能會導致無法預料的問題,所以做一下詳細分析。
注意,在測試過程中為了看測試效果,有些指針變量分配了空間,但是未做回收,實際應用中要注意,分配空間后在合適的位置釋放。
1. 指針變量直接作為參數(shù)傳遞
指針變量pVariant 作為實參傳遞給函數(shù)funcPointer,在funcPointer中由形參pParam接收
1.1 代碼
void funcPointer(int *pParam)
{qDebug()<<"pParam 自身的地址:"<<&pParam<<"pParam 指向的地址:"<<pParam<<"pParam 值"<<*pParam;// 修改指針所指向地址中的內(nèi)容*pParam = 2;qDebug()<<"pParam 自身的地址:"<<&pParam<<"pParam 指向的地址:"<<pParam<<"pParam 值"<<*pParam;// 修改pParam的指向pParam = new int;*pParam = 3;qDebug()<<"pParam 自身的地址:"<<&pParam<<"pParam 指向的地址:"<<pParam<<"pParam 值"<<*pParam;
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);int *pVariant = new int;*pVariant = 1;qDebug()<<"pVariant自身的地址:"<<&pVariant<<"pVariant指向的地址:"<<pVariant<<"pVariant值"<<*pVariant;funcPointer(pVariant);qDebug()<<"pVariant自身的地址:"<<&pVariant<<"pVariant指向的地址:"<<pVariant<<"pVariant值"<<*pVariant;return a.exec();
}
1.2 輸出結(jié)果:
1. pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x1986708 pVariant值 1
2. pParam 自身的地址: 0x77fdd0 pParam 指向的地址: 0x1986708 pParam 值 1
3. pParam 自身的地址: 0x77fdd0 pParam 指向的地址: 0x1986708 pParam 值 2
4. pParam 自身的地址: 0x77fdd0 pParam 指向的地址: 0x1986848 pParam 值 3
5. pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x1986708 pVariant值 2
1.2.1 結(jié)果分析:
- 從1,2可以看出,pVariant和pParam 本身的存儲地址不相同,指向的地址和pVariant相同,說明pParam是pVariant的一個拷貝。
- 從2,3,5可以看出,通過函數(shù)funcPointer可以成功修改指針所指向的地址中的內(nèi)容。
- 從1,3,4,5可以看出,修改形參pParam指向的地址后,不會影響實參pVariant。
綜上,一級指針變量直接做為參數(shù)傳遞時,函數(shù)中會產(chǎn)生一個臨時拷貝,通過這個拷貝可以修改原指針變量所指向地址的內(nèi)容,但是不能改變原指針的指向。
1.3 在函數(shù)funcPointer最后增加回收空間操作:
delete pParam;pParam = nullptr;qDebug()<<"pParam 自身的地址:"<<&pParam<<"pParam 指向的地址:"<<pParam;
1.3.1 輸出結(jié)果:
1. pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x31265e8 pVariant值 1
2. pParam 自身的地址: 0x77fdd0 pParam 指向的地址: 0x31265e8 pParam 值 1
3. pParam 自身的地址: 0x77fdd0 pParam 指向的地址: 0x31265e8 pParam 值 2
4. pParam 自身的地址: 0x77fdd0 pParam 指向的地址: 0x3126768 pParam 值 3
5. pParam 自身的地址: 0x77fdd0 pParam 指向的地址: 0x0
6. pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x31265e8 pVariant值 2
從結(jié)果可以看出,如果形參pParam 執(zhí)行new重新分配了空間,即此時pParam 和pVariant指向的地址不同,那么在函數(shù)中回收指針空間時只能操作pParam,不會回收指針變量pVariant的空間,所以此時想回收指針變量pVariant空間的話,需要在外部回收。
1.3.2 funcPointer函數(shù)中去掉pParam的new操作,增加delete
void funcPointer(int *pParam)
{qDebug()<<"pParam 自身的地址:"<<&pParam<<"pParam 指向的地址:"<<pParam<<"pParam 值"<<*pParam;// 修改指針所指向地址中的內(nèi)容*pParam = 2;qDebug()<<"pParam 自身的地址:"<<&pParam<<"pParam 指向的地址:"<<pParam<<"pParam 值"<<*pParam;delete pParam;pParam = nullptr;qDebug()<<"pParam 自身的地址:"<<&pParam<<"pParam 指向的地址:"<<pParam;
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);int *pVariant = new int;*pVariant = 1;qDebug()<<"pVariant自身的地址:"<<&pVariant<<"pVariant指向的地址:"<<pVariant<<"pVariant值"<<*pVariant;funcPointer(pVariant);qDebug()<<"pVariant自身的地址:"<<&pVariant<<"pVariant指向的地址:"<<pVariant<<"pVariant值"<<*pVariant;return a.exec();
}
1.3.3 輸出結(jié)果
pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x19267e8 pVariant值 1
pParam 自身的地址: 0x77fdd0 pParam 指向的地址: 0x19267e8 pParam 值 1
pParam 自身的地址: 0x77fdd0 pParam 指向的地址: 0x19267e8 pParam 值 2
pParam 自身的地址: 0x77fdd0 pParam 指向的地址: 0x0
pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x19267e8 pVariant值 1761789996
從結(jié)果可以看出,執(zhí)行 delete pParam; pParam = nullptr;后,pVariant指向的空間也已經(jīng)被回收,但是pVariant不為空,依然指向原來的地址,獲取到了一個未定義的值,這樣可能導致程序出現(xiàn)不可控的問題。
2.指針變量作為引用參數(shù)傳遞
2.1 代碼
void funcRefPointer(int *&pParam)
{qDebug()<<"pParam 自身的地址:"<<&pParam<<"pParam 指向的地址:"<<pParam<<"pParam 值"<<*pParam;*pParam = 2;qDebug()<<"pParam 自身的地址:"<<&pParam<<"pParam 指向的地址:"<<pParam<<"pParam 值"<<*pParam;pParam = new int;*pParam = 3;qDebug()<<"pParam 自身的地址:"<<&pParam<<"pParam 指向的地址:"<<pParam<<"pParam 值"<<*pParam;
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);int *pVariant = new int;*pVariant = 1;qDebug()<<"pVariant自身的地址:"<<&pVariant<<"pVariant指向的地址:"<<pVariant<<"pVariant值"<<*pVariant;funcRefPointer(pVariant);qDebug()<<"pVariant自身的地址:"<<&pVariant<<"pVariant指向的地址:"<<pVariant<<"pVariant值"<<*pVariant;return a.exec();
}
2.2 輸出結(jié)果:
1. pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x34665f8 pVariant值 1
2. pParam 自身的地址: 0x77fe04 pParam 指向的地址: 0x34665f8 pParam 值 1
3. pParam 自身的地址: 0x77fe04 pParam 指向的地址: 0x34665f8 pParam 值 2
4. pParam 自身的地址: 0x77fe04 pParam 指向的地址: 0x3466738 pParam 值 3
5. pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x3466738 pVariant值 3
2.2.1結(jié)果分析:
pParam 和 pVariant的存儲地址、指向地址和內(nèi)容完全一致。
指針變量作為引用傳遞時,形參pParam是指針變量pVariant的一個別名,對pParam的操作相當于對pVariant直接進行操作。引用傳遞時可以修改原指針的指向,可以修改指向地址的內(nèi)容。
2.3在函數(shù)funcRefPointer最后增加回收空間操作:
delete pParam;pParam = nullptr;qDebug()<<"pParam 自身的地址:"<<&pParam<<"pParam 指向的地址:"<<pParam;
2.3.1輸出結(jié)果:
pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x3496638 pVariant值 1
pParam 自身的地址: 0x77fe04 pParam 指向的地址: 0x3496638 pParam 值 1
pParam 自身的地址: 0x77fe04 pParam 指向的地址: 0x3496638 pParam 值 2
pParam 自身的地址: 0x77fe04 pParam 指向的地址: 0x3496878 pParam 值 3
pParam 自身的地址: 0x77fe04 pParam 指向的地址: 0x0
pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x0
從結(jié)果可以看出,引用傳遞指針變量時,在函數(shù)中所有對引用變量的操作,都會影響原來的指針,包括delete操作,所以引用傳遞時,如果確定此指針之后不再使用,那么可以在函數(shù)中釋放空間并將指針置空。detele指針并置為nullptr后,無法再獲取指針指向的內(nèi)容。
3.使用二級指針傳遞
傳遞指針變量的地址
3.1 代碼
void funcPPointer(int **pParam)
{qDebug()<<"pParam 自身的地址:"<<&(*pParam)<<"pParam 指向的地址:"<<*pParam<<"pParam 值"<<**pParam;**pParam = 2;qDebug()<<"pParam 自身的地址:"<<&(*pParam)<<"pParam 指向的地址:"<<*pParam<<"pParam 值"<<**pParam;*pParam = new int;**pParam = 3;qDebug()<<"pParam 自身的地址:"<<&(*pParam)<<"pParam 指向的地址:"<<*pParam<<"pParam 值"<<**pParam;
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);int *pVariant = new int;*pVariant = 1;qDebug()<<"pVariant自身的地址:"<<&pVariant<<"pVariant指向的地址:"<<pVariant<<"pVariant值"<<*pVariant;funcPPointer(&pVariant);qDebug()<<"pVariant自身的地址:"<<&pVariant<<"pVariant指向的地址:"<<pVariant<<"pVariant值"<<*pVariant;return a.exec();
}
3.2 輸出結(jié)果
pVariant自身的地址: 0x77fdec pVariant指向的地址: 0x35166c8 pVariant值 1
pParam 自身的地址: 0x77fdec pParam 指向的地址: 0x35166c8 pParam 值 1
pParam 自身的地址: 0x77fdec pParam 指向的地址: 0x35166c8 pParam 值 2
pParam 自身的地址: 0x77fdec pParam 指向的地址: 0x3516748 pParam 值 3
pVariant自身的地址: 0x77fdec pVariant指向的地址: 0x3516748 pVariant值 3
二級指針傳遞時,輸出結(jié)果和引用傳遞一樣,因為都相當于傳遞了原指針的地址。
3.3 在函數(shù)funcPPointer最后增加:
delete (*pParam);(*pParam) = nullptr;qDebug()<<"pParam 自身的地址:"<<&(*pParam)<<"pParam 指向的地址:"<<*pParam;
3.4 輸出結(jié)果:
pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x34967a0 pVariant值 1
pParam 自身的地址: 0x77fe04 pParam 指向的地址: 0x34967a0 pParam 值 1
pParam 自身的地址: 0x77fe04 pParam 指向的地址: 0x34967a0 pParam 值 2
pParam 自身的地址: 0x77fe04 pParam 指向的地址: 0x3496730 pParam 值 3
pParam 自身的地址: 0x77fe04 pParam 指向的地址: 0x0
pVariant自身的地址: 0x77fe04 pVariant指向的地址: 0x0
增加delete后的輸出結(jié)果也和引用傳遞時相同。所以,指針變量作為引用和二級指針的方式傳遞時,效果相同。
注意事項
1. delete指針后,如果不將指針置為nullptr,會產(chǎn)生野指針,指針仍會指向原來的地址,再次使用可能會導致程序崩潰,或者會得到一個不確定的值,導致程序產(chǎn)生不可控的結(jié)果。
2. 使用引用傳遞或者二級指針傳遞時,在函數(shù)中重新分配空間之前,需要將上一次new分配的空間回收,否則會造成內(nèi)存泄漏。也就是多次new的時候需要對應的delete。
3. 如果需要使用調(diào)用接口的方式釋放指針空間時,需要使用二級指針或者引用傳遞指針變量的方式,也就是直接傳遞指針變量的地址。如果直接使用指針傳遞,能夠正常回收空間,但是無法將實參指針置為空值,導致其成為野指針,從而引起內(nèi)存問題。