首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C/C++ 經典編程練習:數組與指針常見錯誤深度剖析

     編輯:關於C語言

C/C++ 經典編程練習:數組與指針常見錯誤深度剖析

指針與數組交互是 C/C++ 初學者最易踩坑的領域。本文通過一個經典錯誤代碼,層層剖析內存洩漏、野指針、釋放錯誤等核心問題,並給出正確寫法與最佳實踐。

錯誤代碼示例

int main() {
    char a[] = { "I am a bad boy" };
    char *pA = new char[sizeof(a)];
    pA = a;                    // 錯誤關鍵點
    for (size_t i = 0; i < sizeof(a); ++i) {
        std::cout << *pA << std::endl;
        ++pA;                  // 修改堆內存指針
    }
    delete[] pA;               // 崩潰點
    pA = NULL;
    return 0;
}

三大核心錯誤剖析

1. 指針賦值導致內存洩漏 + 丟失堆內存控制權

char *pA = new char[sizeof(a)];  // ① 在堆上分配內存,pA 指向堆起始地址
pA = a;                          // ② pA 被改指向棧上數組 a,堆內存地址丟失 → 內存洩漏

本意是拷貝字符串內容,實際卻只是改變指針指向。堆內存無法被釋放,造成洩漏。

2. 遍歷過程中修改堆內存基址指針

++pA;  // 循環中不斷移動指針

指針最終指向棧數組 a 的結尾(空字符處),而非堆內存起始地址。

3. 釋放非堆起始地址導致未定義行為(崩潰)

delete[] pA;  // pA 已非 new 返回的地址 → 堆損壞、程序崩潰

delete[] 必須傳入 new[] 返回的原始地址,否則行為未定義。

正確代碼實現

int main() {
    char a[] = "I am a bad boy";
    char *pA = new char[sizeof(a)];      // 分配堆內存
    strcpy(pA, a);                       // 正確拷貝內容(含結束符)
    
    for (size_t i = 0; i < sizeof(a); ++i) {
        std::cout << *(pA + i);          // 使用指針偏移,不修改 pA 本身
    }
    
    delete[] pA;                         // 釋放原始堆地址
    pA = nullptr;
    return 0;
}

關鍵最佳實踐總結

錯誤模式正確做法說明
pA = a; 指針賦值 strcpy(pA, a) 或逐字符拷貝 拷貝內容而非地址
循環中 ++pA 移動基址指針 用 pA[i] 或 *(pA+i) 訪問 保持基址指針不變,便於正確釋放
new char[strlen(a)] 忽略結束符 new char[strlen(a)+1] 或 sizeof(a) 預留空字符位置,防止字符串函數越界讀取
delete pA; 釋放數組 delete[] pA; 數組必須配對使用 new[]/delete[],否則 UB

補充:為什麼 std::string 支持賦值?

std::string 重載了 operator=,內部實現深拷貝(分配新內存、拷貝內容、更新長度),屬於類封裝行為,原始指針不具備此能力。初學者切勿混淆。

避坑口訣

  1. new[] 必配 delete[],縱使編譯器不報錯,UB 終將爆雷。
  2. 指針基址如命根,遍歷用偏移,釋放才安穩。
  3. 分配大小記得加一,空字符缺了字符串函數全瞎眼。
  4. 拷貝內容用 strcpy,指針賦值只會洩漏又崩潰。

掌握內存所有權轉移與指針算術的本質,是從 C/C++ 初學者進階為可靠系統程序員的關鍵一課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved