在C++中,指針是至關重要的組成部分。它是C++語言最強大的功能之一,也是最棘手的功能之一。 指針具有強大的能力,其本質是協助程序員完成內存的直接操縱。
指針:特定類型數據在內存中的存儲地址,即內存地址。
指針變量的定義語法: 先聲明,后賦值:
變量類型 * 指針變量名; // 聲明
指針變量名 = 內存地址值; // 賦值int num = 10;
int * p; // 聲明
p = # // 賦值
- 變量類型(如上int)表示,指針(內存地址)指向的內存區域,存放的是整型數據 ? ? ? ? ? ? ?
- *符號有兩種含義: ?? ??? ??? ?
- 聲明時:*p,表示變量p,是指針變量(存的是內存地址) ?? ??? ??? ?
- 使用時:*p,表示取指針p執行內存區域的數據 ? ? ? ? ? ? ?
- &符號表示取變量內存地址,是一個取內存地址的單目操作符
野指針和空指針
野指針:被聲明但未初始化(賦值)的指針。這個指針會指向隨機的內存空間,可能導致未知問題。
int * p; // 聲明指針(分配了8字節空間), p是野指針因為未被賦值
*p = 10; // 將10賦予指針p所指向的空間
*p = 10;是向未知的、隨機的4字節內存區域,修改存儲值為10
為避免野指針,應養成良好的變成習慣,及時初始化,或將指針置為空指針更為安全
int * p = NULL;
int * p = nullptr;
指針運算
int num = 10;
int *p = #
cout << p << endl; // 結果:0x20d1ff6e4;
cout << p++ << endl; // 結果:0x20d1ff6e8
指針進行加減運算的結果,和指針指向內存區域的數據類型有關,以加法為例:
char 類型指針 +1, 地址+1 (字節)
int 類型指針+1, 地址+4(字節)
double 類型指針+1, 地址+8 (字節)
指針運算
數組對象本身記錄的是內存地址(第一個元素地址) 可以通過指針運算,完成使用指針存取數組元素。
int v[] = {1, 2, 3, 4, 5};
int *p = v;
*p = 11; // 賦值數組第一個元素
*(p+1) = 22; // 賦值數組第二個元素
*(p+2) = 33; // 賦值數組第三個元素
cout << *p << endl; // 取數組第一個元素
cout << *(p+1) << endl; // 取數組第二個元素
cout << *(p+2) << endl; // 取數組第三個元素
動態內存分配
動態內存分配:即由程序員手動的進行內存空間的分配、內存空間的釋放等內存管理操作。
C++代碼中,變量、數組等對象的創建,是由C++自動分配內存的,稱之為(自動)靜態內存分配。
(自動)靜態內存管理,是不會進行內存空間的自動清理的。(無垃圾回收機制) 我們需要手動的管理內存,即手動分配,用完清理。
手動管理方式:
new運算符申請空間,提供該空間的指針(地址)
delete運算符申請的空間,僅用于new申請的空間
建議:寫完new后,立刻寫delete,然后再寫業務邏輯代碼
int * p = new int; // 申請int類型(4字節)空間
int * p = new double; // 申請double類型(8字節)空間
delete p; // 刪除申請的空間
int * p = new int[5]; // 申請5元素int數組空間
delete[] p; // 刪除申請的5元素數組空間
優勢: 手動控制內存,避免內存空間浪費
劣勢: 考驗程序員水平,用的好效率高,用不好有反效果
new
new運算符用于申請并分配內存空間 并提供指向該空間的指針(內存地址) 基本語法:
new type 申請普通變量空間
new type[n] 申請數組空間
delete
delete運算符用于釋放內存 僅可用于new運算符申請的內存區域
基本語法:
delete 指針 刪除普通變量空間
delete[] 指針 刪除數組空間
數組元素的插入舉例:
#include "iostream"
using namespace std;/* 在下標1和3插入數字:11和66 */int main()
{// 示例數組int * pArr = new int[5] {1, 3, 5, 7, 9};// 創建新數組int * pNewArr = new int[7];// 循環新數組,挨個進行元素填充(非插入的位置,填充老數組元素,插入位置填充新元素)int offset = 0; // 偏移量用來控制新老數組元素的下標對照for (int i = 0; i < 7; i++){if (i == 1){// 走到了下標1,應當執行新元素插入pNewArr[i] = 11;offset++; // 每插入一個新元素,offset+1continue;} else if (i == 3){// 走到了下標3,應當執行新元素插入pNewArr[i] = 66;offset++; // 每插入一個新元素,offset+1continue;}// 不是插入位置,從老數組中提取元素放入新數組中// 公式:老數組的元素下標 + offset = 新數組元素下標// 當前循環的i是新數組的元素下標pNewArr[i] = pArr[i-offset];}// 收尾工作delete[] pArr;pArr = pNewArr;// 將新數組的內容輸出for (int i = 0; i< 7; i++){cout << pNewArr[i] << ",";}return 0;
}
數組元素的刪除舉例:
#include "iostream"
using namespace std;int main()
{// 示例數組int * pArr = new int[5] {1, 3, 5, 7, 9};// 創建一個新的數組,將需要保留的復制到新數組中int * pNewArr = new int[4];// 循環去遍歷老的數組,將需要的元素放入新數組中(不要的要跳過)for (int i = 0; i < 5; i++){if (i == 2){continue;}if (i > 2){pNewArr[i-1] = pArr[i];}else{pNewArr[i] = pArr[i];}}// 可選delete[] pArr; // 回收老數組的空間(可選,根據需要來說)// 可選pArr = pNewArr; // 將老數組的指針指向新數組的內存空間(可選,根據需要)for (int i = 0; i < 4; i++){cout << "新數組的元素是:" << pNewArr[i] << endl;cout << "新數組的元素是:" << pArr[i] << endl;}return 0;
}
指針懸掛:
指針指向區域已經被回收(delete),這種問題稱之為:指針懸掛。
不要輕易進行指針之間相互賦值
delete回收空間前,確保此空間100%不再被使用
錯誤示范:
int main()
{ int * p1 = new int;int * p2 = p1; // 將p1賦值給p2*p1 = 10; delete p1;cout << "p2指針記錄的是:" << *p2 << endl;return 0;
}
const指針
const是C++關鍵字,被譯為常量,const指針即表示:常量指針。
const用來修飾常量(不可更改),可以配合指針使用 以int為例。
const int * p; 指向常量的指針,即存儲值不可變,但指針可修改指向
int * const p = 地址; 常量指針
存儲的值可以變 指著不可修改指向 必須初始化指針的地址
const int * const p = 地址; 指向常量的常量指針
存儲的值和指針的指向,均不可修改