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

C/C++ 語言學習總結:函數參數傳遞、記憶體管理、類別機制與常見陷阱

     編輯:關於C++

前言

本文系統整理 C/C++ 核心語言特性:三種參數傳遞方式、三大記憶體分配區、常見記憶體錯誤、malloc vs new、重載/覆蓋/隱藏辨析、extern "C"、預設參數規則、巨集 vs 內聯函數、建構/解構順序、字串類別實現要點。

一、函數參數傳遞三種方式

方式語法機制影響外部變數典型用途
值傳遞void f(int x)建立副本否小型型別、不需修改原值
指標傳遞void f(int* x)傳遞位址是 (透過解參考)C 風格、可選參數 (nullptr)、陣列
參考傳遞void f(int& x)別名綁定是C++ 慣用、修改原值、避免拷貝大型物件

程式碼驗證


void Func1(int x) { x += 10; }          // 值傳遞
void Func2(int* x) { *x += 10; }        // 指標傳遞
void Func3(int& x) { x += 10; }         // 參考傳遞

int n = 0;
Func1(n); cout << n;  // 0
Func2(&n); cout << n; // 10
Func3(n); cout << n;  // 20

二、記憶體分配三大區域

區域對象特點
靜態儲存區全域變數、static 變數編譯期分配、程式全生命週期存在
堆疊函數區域變數、參數CPU 指令集支援、極快、容量有限 (~1-8MB)
堆積new/malloc 動態分配程式員手動管理、靈活大容量、易碎片化

三、常見記憶體錯誤與對策

  1. 分配失敗卻使用 → 檢查 nullptr/NULL
  2. 未初始化就引用 → 定義即初始化、std::vector 等容器
  3. 越界存取 → 邊界檢查、at()、範圍 for、std::span (C++20)
  4. 忘記釋放 → 記憶體洩漏 → RAII、智慧指標 (unique_ptr/shared_ptr)
  5. 釋放後繼續使用 (懸空指標) → 釋放後設 nullptr
  6. 返回區域物件指標/參考 → 返回值、智慧指標、std::optional
  7. 物件關係複雜難追蹤 → 重新設計資料結構、所有權模型明確化
  8. 釋放未置 NULL → 野指標 → 封裝 SafeDelete、智慧指標

四、malloc/free vs new/delete

維度malloc/freenew/delete
性質標準庫函數C++ 運算符
型別安全無 (返回 void*)有 (返回具型別指標)
建構/解構不呼叫自動呼叫
失敗處理返回 NULL拋出 std::bad_alloc
重新分配realloc無直接對應 (用 vector)
適用對象POD 型別、C 介面所有 C++ 類別 (非 POD 必須用 new)

核心原因:malloc 是函數,編譯器無法注入建構/解構呼叫;new 是運算符,語言層面保證物件語意。

五、重載 vs 覆蓋 vs 隱藏

特徵重載覆蓋隱藏
範圍同一類別基類/衍生類別基類/衍生類別
函數名相同相同相同
參數不同相同相同/不同
virtual可有可無基類必須有基類無 virtual
回傳型別可不同相同 (或共變)可不同

程式碼示範


class Base {
    void f(int); void f(float);           // 重載
    virtual void g(); void h(float); void k(float);
};
class Derived : public Base {
    virtual void g();                     // 覆蓋
    void h(int);                          // 隱藏 Base::h(float)
    void k(float);                        // 隱藏 Base::k(float) (非 virtual)
};

六、extern "C" 解決 C/C++ 混合連結

C++ 編譯器對函數名進行 Name Mangling (如 _foo_int_int) 支援重載;C 編譯器不會 (_foo)。


// 告訴 C++ 編譯器用 C 連結規則
extern "C" {
    void foo(int x, int y);
    #include "c_header.h"
}

七、函數預設參數規則

  • 只能出現在宣告,不可在定義體:void f(int x=0); ✓ / void f(int x=0) {} ✗
  • 右邊參數有預設值,左邊必須也有:void f(int x, int y=0, int z=0); ✓ / void f(int x=0, int y, int z=0); ✗

八、巨集 vs 內聯函數

維度巨集內聯函數
處理階段預處理器 (文字替換)編譯器 (語意分析)
型別檢查無完整
自動轉換無有
this 指標無法處理正確傳遞
側邊效應易發生 (多次求值)無 (參數單次求值)
除錯不可見可見
正確用法常數、簡單運算inline 與定義體放在一起

九、建構/解構順序鐵律

  1. 建構:基類 → 成員物件 (宣告順序) → 本類別
  2. 解構:嚴格相反順序 (本類別 → 成員 → 基類)
  3. 順序唯一,否則編譯器無法自動管理

十、字串類別完整實現要點


class String {
    char* m_data;
public:
    String(const char* str = nullptr);        // 普通建構
    String(const String& other);              // 拷貝建構
    ~String();                                // 解構
    String& operator=(const String& other);   // 指派
};

String::~String() { delete[] m_data; }

String::String(const char* str) {
    if (!str) { m_data = new char[1]; *m_data = '\0'; }
    else { int len = strlen(str); m_data = new char[len+1]; strcpy(m_data, str); }
}

String::String(const String& other) {
    int len = strlen(other.m_data);
    m_data = new char[len+1];
    strcpy(m_data, other.m_data);
}

String& String::operator=(const String& other) {
    if (this == &other) return *this;  // 1. 自指派檢查
    delete[] m_data;                   // 2. 釋放舊資源
    int len = strlen(other.m_data);
    m_data = new char[len+1];          // 3. 分配新資源
    strcpy(m_data, other.m_data);
    return *this;                      // 4. 返回 *this
}

關鍵點:自指派檢查、釋放舊記憶體、深度拷貝、返回參考支援鏈式指派。

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