C++常見面試題-1.C++基礎

一、C++ 基礎

1.1 語言特性與區別

  1. C++ 與 C 的主要區別是什么?C++ 為何被稱為 “帶類的 C”?

    • 主要區別:C++ 引入了面向對象編程(OOP)特性(類、繼承、多態等),而 C 是過程式編程語言;C++ 支持函數重載、模板、異常處理等高級特性,C 不支持。
    • 為何稱為"帶類的 C":早期 C++ 是在 C 語言基礎上添加類和對象機制擴展而來,保留了 C 的大部分語法和功能,因此被稱為"帶類的 C"。
  2. C++ 的基本數據類型有哪些?它們的大小(32 位 / 64 位系統)分別是多少?

    • 基本數據類型:整數類型(char、short、int、long、long long)、浮點類型(float、double、long double)、布爾類型(bool)、空類型(void)。
    • 大小(32位/64位系統)
      • char:1字節
      • short:2字節
      • int:4字節
      • long:4字節(32位)/ 8字節(64位)
      • long long:8字節
      • float:4字節
      • double:8字節
      • bool:1字節
  3. 指針和引用的區別是什么?何時使用指針,何時使用引用?

    • 區別

      • 指針可以為空(nullptr),引用必須初始化且不能為null;
      • 指針可以重新指向其他對象,引用一旦綁定不能更改;
      • 指針需要解引用(*)訪問對象,引用直接訪問;
      • 指針有自己的內存空間,引用不占用額外內存(編譯器處理為指針)。
    • 使用場景

      • 當需要表示"無對象"時使用指針(如返回可能失敗的查找結果);
      • 當需要動態修改指向的對象時使用指針;
      • 其他情況優先使用引用(更安全、簡潔)。
    • 代碼示例

      int a = 10;
      int* p = &a;  // 指針
      int& r = a;   // 引用
      *p = 20;      // 解引用修改a的值
      r = 30;       // 直接修改a的值
      p = nullptr;  // 指針可以為空
      // r = nullptr;  // 錯誤:引用不能為null
      
  4. 結構體 struct 和共同體 union(聯合)的區別是什么?

    • struct:各成員占用獨立內存空間,總大小為各成員大小之和(考慮內存對齊)。

    • union:所有成員共享同一塊內存空間,總大小為最大成員的大小。同一時間只能有一個成員有效。

    • 代碼示例

      struct S { int a; char b; };  // 大小至少為 4+1=5字節(實際可能更大,取決于對齊)
      union U { int a; char b; };   // 大小為4字節(int的大小)
      
  5. struct 和 class 的區別?

    • 默認訪問權限:struct默認public,class默認private。
    • 默認繼承方式:struct默認public繼承,class默認private繼承。
    • 模板參數:class可用于定義模板參數(如template),struct不行(C++11后無區別)。
  6. C++ 是不是類型安全的?為什么?

    • 不是完全類型安全。原因:
      • 存在強制類型轉換(如reinterpret_cast可以任意轉換指針類型);
      • 指針運算可能導致越界訪問;
      • 空指針解引用;
      • 未初始化的變量;
      • 數組與指針的隱式轉換。

1.2 關鍵字與修飾符

  1. const 關鍵字的用法(修飾變量、函數參數、函數返回值、成員函數)?

    • 修飾變量:表示變量的值不能被修改。

      const int MAX = 100;  // 常量
      
    • 修飾函數參數:防止函數修改實參的值。

      void print(const std::string& message);  // 引用傳遞,不修改原字符串
      
    • 修飾函數返回值:表示返回值不能被修改(通常用于返回指針或引用時)。

      const char* getName() const;  // 返回常量指針
      
    • 修飾成員函數:表示該函數不會修改類的成員變量。

      class Test { 
      public:int getValue() const;  // 不會修改成員變量
      };
      
  2. volatile 關鍵字的作用?它與 const 能否同時修飾一個變量?

    • 作用:告訴編譯器不要對該變量進行優化,每次都從內存中讀取值。通常用于多線程環境中共享的變量或硬件寄存器映射的變量。

    • 與const共存:可以同時修飾一個變量,表示變量的值不能被程序修改,但可能被其他因素(如硬件、其他線程)修改。

      volatile const int* p = &someRegister;  // 指向只讀寄存器的指針
      
  3. typedef 和 using(C++11)的區別?如何用它們定義函數指針?

    • 區別

      • typedef是C語言的關鍵字,using是C++11引入的別名聲明;
      • using可以定義模板別名,typedef不能;
      • using的語法更清晰,尤其是在復雜類型別名時。
    • 定義函數指針

      // 使用typedef
      typedef int (*FuncPtr)(int, int);// 使用using(C++11)
      using FuncPtr = int (*)(int, int);// 使用示例
      int add(int a, int b) { return a + b; }
      FuncPtr f = add;
      
  4. typedef 和 #define 的區別是什么?

    • 類型檢查:typedef會進行類型檢查,#define只是簡單的文本替換;
    • 作用域:typedef有作用域限制,#define全局有效;
    • 復雜性:typedef適合定義復雜類型(如函數指針),#define更適合簡單的文本替換;
    • 調試:typedef在調試時更友好,可以顯示類型信息。
  5. extern “C” 的作用是什么?

    • 作用:指定使用C語言的函數命名規則和調用約定,以便C++代碼能夠調用C語言編寫的函數。
    • 使用場景:在C++項目中調用C語言庫,或者讓C項目調用C++編寫的接口。
// 在C++代碼中聲明C函數
extern "C" {void cFunction();
}// 在C++頭文件中同時支持C和C++編譯
#ifdef __cplusplus
extern "C" {
#endifvoid commonFunction();
#ifdef __cplusplus
}
#endif
  1. static 關鍵字的作用有哪些(函數體內、模塊內、類中)?

    • 函數體內:變量在函數調用之間保持值,只初始化一次。

      void increment() {static int count = 0;  // 只初始化一次count++;  // 每次調用都增加
      }
      
    • 模塊內:限制變量或函數的作用域為本模塊(.cpp文件),不能被其他模塊訪問。

      static void helper() { /* 只在當前文件可見 */ }
      
    • 類中:靜態成員變量屬于類而不是對象,靜態成員函數不依賴于對象實例。

      class MyClass {
      public:static int count;  // 靜態成員變量聲明static void printCount() {  // 靜態成員函數std::cout << count << std::endl;}
      };
      int MyClass::count = 0;  // 靜態成員變量定義
      
  2. auto(C++11 前僅用于自動變量)和 decltype 的區別?

    • auto:根據初始化表達式自動推導變量類型,需要初始化。

      auto x = 10;  // x被推導為int類型
      auto s = "hello";  // s被推導為const char*
      
    • decltype:根據表達式推導類型,不需要初始化。

      int a = 5;
      decltype(a) b;  // b被推導為int類型
      decltype(a + 1.0) c;  // c被推導為double類型
      
  3. nullptr 與 NULL 的區別?為何推薦使用 nullptr?

    • NULL:通常是一個宏定義,在C++中被定義為0或 (void*)0,可能導致類型歧義。

    • nullptr:C++11引入的關鍵字,表示空指針常量,類型為nullptr_t。

    • 推薦使用nullptr的原因:

      • 避免整數和指針類型混淆;
      • 在函數重載時提供明確的類型信息;
      • 提高代碼的可讀性和安全性。
      void f(int);
      void f(int*);
      f(NULL);  // 可能調用f(int)而不是f(int*)
      f(nullptr);  // 明確調用f(int*)
      

1.3 內存管理

  1. C++ 的內存分區(棧、堆、全局 / 靜態存儲區、常量存儲區、代碼區)各自的特點?

    • 棧(Stack)
      • 由編譯器自動分配釋放;
      • 存儲函數參數、局部變量等;
      • 空間小,訪問速度快;
      • 內存分配是連續的。
    • 堆(Heap)
      • 由程序員動態分配和釋放;
      • 空間較大,訪問速度相對較慢;
      • 內存分配不一定連續,可能產生碎片。
    • 全局/靜態存儲區
      • 存儲全局變量和靜態變量;
      • 程序運行期間一直存在;
      • 程序結束時由系統釋放。
    • 常量存儲區
      • 存儲常量(如字符串常量、const常量);
      • 內容不允許修改。
    • 代碼區
      • 存儲程序的二進制指令;
      • 通常是只讀的。
  2. 堆和棧的區別(申請方式、大小限制、生命周期、碎片問題等)?

    • 申請方式:棧由編譯器自動分配;堆由程序員調用malloc/free或new/delete分配。
    • 大小限制:棧的大小通常較小(幾MB);堆的大小受限于系統虛擬內存(幾GB)。
    • 生命周期:棧中的數據在函數調用結束后自動銷毀;堆中的數據需要手動釋放,否則會造成內存泄漏。
    • 碎片問題:頻繁分配/釋放堆內存會產生碎片;棧不會產生碎片。
    • 分配效率:棧的分配效率高;堆的分配效率相對較低。
  3. 什么是內存泄漏?如何檢測和避免內存泄漏?

    • 內存泄漏:程序中動態分配的內存沒有被正確釋放,導致這部分內存無法被重用。
    • 檢測方法
      • 使用內存檢測工具(如Valgrind、Visual Leak Detector);
      • 在代碼中添加內存跟蹤日志;
      • 使用智能指針自動管理內存。
    • 避免方法
      • 及時釋放動態分配的內存;
      • 使用RAII原則(Resource Acquisition Is Initialization);
      • 優先使用智能指針(如std::unique_ptr、std::shared_ptr);
      • 避免復雜的內存管理邏輯。
  4. C 和 C++ 動態管理內存的方法有何不同(malloc/free vs new/delete)?

    • malloc/free:C語言的函數,只負責分配/釋放內存空間,不調用構造函數/析構函數。

      int* p = (int*)malloc(sizeof(int));
      free(p);
      
    • new/delete:C++的運算符,不僅分配/釋放內存,還會調用構造函數/析構函數。

      int* p = new int(10);  // 分配內存并初始化
      delete p;  // 調用析構函數并釋放內存// 數組版本
      int* arr = new int[5];
      delete[] arr;  // 必須使用delete[]釋放數組
      
    • 其他區別

      • new/delete是運算符,malloc/free是函數;
      • new自動計算所需內存大小,malloc需要手動計算;
      • new分配失敗時拋出異常,malloc返回nullptr;
      • new/delete可以重載,malloc/free不能。
  5. new 和 delete 是如何實現的?與 malloc 和 free 有何異同?

    • new的實現
      1. 調用operator new分配內存;
      2. 調用構造函數初始化對象。
    • delete的實現
      1. 調用析構函數清理對象;
      2. 調用operator delete釋放內存。
    • 與malloc/free的異同
      • 相同點:都是用于動態內存管理。
      • 不同點
        • new/delete是運算符,malloc/free是函數;
        • new/delete會調用構造函數/析構函數,malloc/free不會;
        • new自動計算內存大小,malloc需要手動指定;
        • new失敗時拋出異常,malloc返回nullptr;
        • new/delete可以重載,malloc/free不能。
  6. delete 和 delete [] 的區別是什么?

    • delete:用于釋放單個對象的內存,先調用該對象的析構函數,然后釋放內存。
    • delete []:用于釋放數組對象的內存,先調用數組中每個對象的析構函數,然后釋放內存。
    • 混用的后果:用delete釋放數組會導致只調用第一個對象的析構函數,造成內存泄漏;用delete []釋放單個對象會導致多次調用析構函數,可能導致程序崩潰。
  7. 什么是野指針?其成因有哪些?

    • 野指針:指向已釋放內存或未分配內存的指針,無法確定其指向的內容。
    • 成因
      • 指針未初始化;
      • 指針指向的內存已被釋放,但指針未置空;
      • 指針越界訪問。
    • 避免方法
      • 指針初始化時置為nullptr;
      • 釋放內存后將指針置為nullptr;
      • 使用智能指針代替裸指針。
  8. 棧溢出的原因是什么?有哪些解決方法?

    • 原因
      • 函數調用層次過深(如遞歸調用沒有終止條件);
      • 局部變量占用過多棧空間(如大型數組);
      • 棧空間設置過小。
    • 解決方法
      • 優化遞歸算法,避免過深的調用層次;
      • 使用堆內存代替棧內存存儲大型數據;
      • 調整棧空間大小(特定編譯器/環境下)。
  9. C++ 的內存管理中,自由存儲區與堆的區別是什么?

    • 自由存儲區:由C++的new/delete運算符分配和釋放的內存區域,是C++概念。
    • :由C語言的malloc/free函數分配和釋放的內存區域,是操作系統概念。
    • 關系:通常情況下,自由存儲區和堆是同一塊內存區域,但嚴格來說,自由存儲區是基于堆實現的。
    • 區別
      • 分配/釋放方式不同:自由存儲區使用new/delete,堆使用malloc/free;
      • 內存管理機制不同:new/delete會調用構造函數/析構函數,malloc/free不會;
      • new/delete可以重載,改變自由存儲區的分配策略。

1.4 函數與預處理

  1. 函數重載的原理是什么?為何返回值不同不能構成重載?

    • 原理:編譯器根據函數的參數類型、數量、順序生成不同的函數名(名稱修飾),使得同名但參數列表不同的函數在編譯后實際上有不同的標識符。

    • 返回值不同不能構成重載:因為在函數調用時,編譯器無法僅根據返回值類型來確定要調用哪個函數。函數調用的語法中,返回值是可選的,不影響函數的選擇。

      void print(int);
      void print(double);  // 重載,參數類型不同
      // int print(int);  // 錯誤:僅返回值不同,不能構成重載
      
  2. 函數默認參數的規則(從右向左設置,調用時不能跳過前面的參數)?

    • 從右向左設置:默認參數必須從最右邊的參數開始設置,不能跳過中間的參數。

      void func(int a, int b = 10, int c = 20);  // 正確
      // void func(int a = 10, int b, int c = 20);  // 錯誤:不能跳過b
      
    • 調用時不能跳過前面的參數:在調用有默認參數的函數時,必須從左到右提供參數,不能跳過前面的參數而直接使用后面的默認參數。

      func(5);  // 等同于func(5, 10, 20)
      func(5, 15);  // 等同于func(5, 15, 20)
      // func(, 15);  // 錯誤:不能跳過前面的參數
      
  3. 內聯函數(inline)的作用?與宏定義的區別?為何內聯函數不宜過長?

    • 作用:減少函數調用的開銷,提高程序運行效率。編譯器會嘗試將內聯函數的代碼插入到調用點,而不是進行函數調用。

    • 與宏定義的區別

      • 內聯函數由編譯器處理,進行類型檢查;宏由預處理器處理,僅進行文本替換。
      • 內聯函數支持調試;宏不支持調試。
      • 內聯函數更安全,不會有宏替換可能帶來的副作用;宏可能因優先級問題導致錯誤。
      // 內聯函數
      inline int max(int a, int b) { return a > b ? a : b; }// 宏定義
      #define MAX(a, b) ((a) > (b) ? (a) : (b))
      
    • 內聯函數不宜過長的原因:

      • 如果內聯函數過長,編譯器可能會忽略inline關鍵字,將其當作普通函數處理;
      • 過長的內聯函數會導致代碼膨脹,增加可執行文件的大小。
  4. 預處理指令(#include、#define、#ifdef 等)的作用?#include <> 和 #include “” 的區別?

    • 常用預處理指令
      • #include:包含頭文件;
      • #define:定義宏;
      • #undef:取消宏定義;
      • #ifdef/#ifndef:條件編譯(如果宏已定義/未定義);
      • #else/#elif:條件編譯的分支;
      • #endif:結束條件編譯塊;
      • #pragma:特定編譯器的指令。
    • #include <> 和 #include “” 的區別
      • #include <>:用于包含標準庫頭文件,編譯器會先在標準庫目錄中查找;
      • #include "":用于包含用戶自定義頭文件,編譯器會先在當前目錄中查找,然后再到標準庫目錄中查找。
  5. 定義和聲明的區別是什么?

    • 聲明(Declaration):告訴編譯器某個名字的存在及其類型,但不分配內存或初始化。

      extern int g_var;  // 變量聲明
      int func(int a);   // 函數聲明
      
    • 定義(Definition):聲明的同時分配內存或提供函數體。一個變量或函數可以有多個聲明,但只能有一個定義。

      int g_var = 10;  // 變量定義
      int func(int a) { return a * 2; }  // 函數定義
      
  6. 引用作為函數參數以及返回值的好處是什么?有哪些限制?

    • 作為函數參數的好處

      • 避免拷貝大對象,提高效率;
      • 可以修改實參的值(如果不是const引用);
      • 比指針更安全,不需要檢查空指針。
    • 作為函數返回值的好處

      • 避免返回值的拷貝,提高效率;
      • 可以直接修改返回的對象(鏈式調用)。
    • 限制

      • 引用必須綁定到有效的對象,不能返回局部變量的引用;
      • 返回引用時需要確保引用的對象在函數調用結束后仍然存在。
      // 正確:返回類成員的引用
      class MyClass {
      private:int value;
      public:int& getValue() { return value; }
      };// 錯誤:返回局部變量的引用
      int& badFunction() {int x = 10;return x;  // x在函數結束后被銷毀
      }
      
  7. C++ 文件編譯與執行的四個階段是什么?

    • 預處理(Preprocessing)
      • 處理預處理指令(如#include、#define);
      • 刪除注釋;
      • 宏展開;
      • 生成.i文件。
    • 編譯(Compilation)
      • 將預處理后的代碼轉換為匯編語言;
      • 進行語法檢查、語義分析、優化等;
      • 生成.s文件。
    • 匯編(Assembly)
      • 將匯編代碼轉換為機器碼(二進制);
      • 生成.obj文件(Windows)或.o文件(Unix/Linux)。
    • 鏈接(Linking)
      • 將多個目標文件和庫文件鏈接在一起;
      • 解決符號引用;
      • 生成可執行文件(.exe文件或ELF文件)。
  8. 頭文件中 #ifndef/define/endif 與 #pragma once 的區別是什么?

    • #ifndef/define/endif(條件包含):

      • 標準C++語法,所有編譯器都支持;
      • 可以嵌套使用,實現更復雜的條件包含;
      • 可能存在宏名沖突的問題。
      #ifndef HEADER_FILE_NAME_H
      #define HEADER_FILE_NAME_H// 頭文件內容#endif  // HEADER_FILE_NAME_H
      
    • #pragma once

      • 非標準但被大多數編譯器支持的語法;
      • 更簡潔,不容易出錯;
      • 依賴于編譯器對文件的識別,可能在某些情況下(如硬鏈接)導致重復包含。
      #pragma once// 頭文件內容
      
    • 選擇建議:兩種方式都可以使用,通常推薦使用#pragma once,因為它更簡潔且不容易出錯,但如果需要兼容不支持#pragma once的編譯器,或者需要更復雜的條件包含,可以使用#ifndef/define/endif

1.5 類型轉換與其他

  1. C++ 的四種強制轉換(static_cast、dynamic_cast、const_cast、reinterpret_cast)分別是什么?各自的適用場景?

    • static_cast

      • 適用場景:用于基本類型轉換、上行轉換(派生類指針/引用轉為基類指針/引用)、轉換編譯器能明確識別的類型。
      • 特點:編譯時進行檢查,不進行運行時類型檢查。
      int i = 10;
      double d = static_cast<double>(i);  // 基本類型轉換Base* base = static_cast<Base*>(derived);  // 上行轉換(安全)
      
    • dynamic_cast

      • 適用場景:主要用于下行轉換(基類指針/引用轉為派生類指針/引用),必須用于包含虛函數的類。
      • 特點:運行時進行類型檢查,如果轉換失敗返回nullptr(指針)或拋出異常(引用)。
      Base* base = new Derived();
      Derived* derived = dynamic_cast<Derived*>(base);  // 下行轉換,需要運行時檢查
      
    • const_cast

      • 適用場景:用于移除變量的const或volatile限定符。
      • 注意:如果原對象本身不是const的,使用const_cast修改是合法的;如果原對象是const的,修改其內容是未定義行為。
      const int* p = &value;
      int* q = const_cast<int*>(p);  // 移除const限定符
      
    • reinterpret_cast

      • 適用場景:用于不同類型指針之間的轉換、指針與整數之間的轉換,是最不安全的轉換方式。
      • 特點:僅重新解釋指針的二進制表示,不進行任何類型檢查或轉換。
      int* p = reinterpret_cast<int*>(0x12345678);  // 指針與整數轉換
      
  2. 左值和右值的區別?左值引用與右值引用的區別是什么?

    • 左值(lvalue):表達式結束后依然存在的持久對象,可以出現在賦值語句的左側。
    • 右值(rvalue):表達式結束后就不再存在的臨時對象,只能出現在賦值語句的右側。
    int a = 10;  // a是左值,10是右值
    int& lr = a;  // 左值引用綁定到左值
    // int& lr2 = 10;  // 錯誤:左值引用不能綁定到右值
    const int& lr3 = 10;  // 常量左值引用可以綁定到右值// C++11引入的右值引用
    int&& rr = 10;  // 右值引用綁定到右值
    // int&& rr2 = a;  // 錯誤:右值引用不能直接綁定到左值
    int&& rr3 = std::move(a);  // 使用std::move將左值轉換為右值
    
    • 左值引用(&)
      • 可以綁定到左值或const右值;
      • 通常用于函數參數傳遞,避免拷貝。
    • 右值引用(&&)
      • C++11引入,用于實現移動語義和完美轉發;
      • 只能綁定到右值或通過std::move轉換的左值;
      • 主要用于移動構造函數、移動賦值運算符和完美轉發。
  3. 指針數組和數組指針的區別是什么?

    • 指針數組:一個數組,其元素是指針。

      int* arr[5];  // 包含5個int*指針的數組
      
    • 數組指針:一個指針,指向一個數組。

      int (*ptr)[5];  // 指向包含5個int元素的數組的指針
      int arr[5];
      ptr = &arr;  // 正確:ptr指向整個數組
      
    • 記憶方法:看括號的位置,*和變量名在括號內的是數組指針,否則是指針數組。

  4. sizeof 和 strlen 的區別是什么?

    • sizeof

      • 運算符,不是函數;
      • 編譯時計算;
      • 計算變量、類型或表達式所占的字節數;
      • 對于數組名,計算整個數組的大小;
      • 對于指針,計算指針本身的大小(通常為4或8字節)。
    • strlen

      • 函數,定義在頭文件中;
      • 運行時計算;
      • 計算字符串的長度,不包括結束符’\0’;
      • 只適用于以’\0’結尾的字符數組(C風格字符串)。
      char str[] = "hello";
      sizeof(str);  // 6字節(包含'\0')
      strlen(str);  // 5字節(不包含'\0')char* p = str;
      sizeof(p);  // 4或8字節(指針的大小)
      strlen(p);  // 5字節
      
  5. 關于 sizeof 的詳細小結(包括不同類型、數組、結構體等)?

    • 基本類型:sizeof(char) = 1字節,sizeof(short) = 2字節,sizeof(int) = 4字節,sizeof(long) = 4或8字節,sizeof(long long) = 8字節,sizeof(float) = 4字節,sizeof(double) = 8字節,sizeof(bool) = 1字節。

    • 指針類型:在32位系統上,sizeof(任意指針) = 4字節;在64位系統上,sizeof(任意指針) = 8字節。

    • 數組:sizeof(數組名) = 數組元素個數 * sizeof(元素類型),但當數組名作為函數參數傳遞時,會退化為指針,sizeof(指針) = 指針本身的大小。

      int arr[10];
      sizeof(arr);  // 10 * sizeof(int) = 40字節(假設int為4字節)void func(int a[]) {sizeof(a);  // 4或8字節(指針的大小)
      }
      
    • 結構體:sizeof(結構體)考慮內存對齊,通常大于或等于各成員大小之和。

      struct S {char c;    // 1字節int i;     // 4字節double d;  // 8字節
      };
      // 在大多數64位系統上,sizeof(S) = 16字節(內存對齊)
      
    • 空類:C++中空類的大小為1字節(為了區分不同的對象實例)。

      class Empty { };
      sizeof(Empty);  // 1字節
      
  6. 結構體為什么需要內存對齊?內存對齊的原因是什么?

    • 內存對齊:編譯器為了提高訪問效率,會對結構體成員進行對齊,使每個成員的起始地址是其大小的整數倍。
    • 內存對齊的原因
      • 性能考慮:處理器訪問對齊的內存比未對齊的內存更快;
      • 硬件限制:某些處理器架構不支持非對齊的內存訪問,或者訪問非對齊內存會導致性能下降;
      • 兼容性:不同編譯器、不同平臺可能有不同的對齊要求,適當的對齊可以保證數據結構的兼容性。
    • 對齊規則
      • 每個成員的起始地址必須是其自身大小的整數倍;
      • 整個結構體的大小必須是其最大成員大小的整數倍(或編譯器指定的最大對齊值的整數倍)。
  7. 引用是否占用內存空間?為什么?

    • 從實現角度:引用通常在編譯器內部實現為指針,因此會占用內存空間(在32位系統上為4字節,在64位系統上為8字節)。
    • 從語言標準角度:C++標準沒有明確規定引用是否占用內存空間,只是規定引用必須綁定到一個對象,并且不能重新綁定。
    • 為何會有這樣的設計:引用的設計目的是提供一個便捷、安全的別名機制,而不是作為一種新的指針類型。因此,標準并不關心其具體實現細節,只關心其行為。
  8. 全局變量和局部變量的區別是什么?是怎么實現的?操作系統和編譯器是怎么知道的?

    • 全局變量
      • 定義在函數外部,作用域為整個程序;
      • 存儲在全局/靜態存儲區,程序啟動時分配內存,程序結束時釋放;
      • 默認初始化為0或空指針。
    • 局部變量
      • 定義在函數內部,作用域為函數內部或代碼塊內部;
      • 存儲在棧區,函數調用時分配內存,函數返回時釋放;
      • 不默認初始化,其值是未定義的。
    • 實現方式
      • 編譯器在編譯時為全局變量和局部變量分配不同的內存區域;
      • 全局變量的地址在編譯時或鏈接時確定;
      • 局部變量的地址在運行時動態確定(基于棧指針)。
    • 操作系統和編譯器如何知道
      • 編譯器在編譯過程中會記錄變量的作用域和存儲類型;
      • 鏈接器會處理全局變量的引用;
      • 操作系統在加載程序時,根據可執行文件中的段信息(如.data段、.bss段)來分配和初始化全局變量的內存空間。
  9. main 函數執行之前,還會執行什么代碼?

    • 全局變量的構造函數:程序啟動時,會先初始化全局變量和靜態變量,并調用它們的構造函數;

    • C++ 運行時庫初始化:初始化C++標準庫,如內存分配器、異常處理機制等;

    • main函數的參數設置:解析命令行參數,設置argc和argv;

    • 其他初始化:如靜態對象的初始化、線程局部存儲的初始化等。

    • 示例

      class MyClass {
      public:MyClass() { std::cout << "MyClass constructor called" << std::endl; }
      };MyClass globalObj;  // 全局對象,其構造函數在main之前調用int main() {std::cout << "main function called" << std::endl;return 0;
      }
      // 輸出順序:
      // MyClass constructor called
      // main function called
      

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/93776.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/93776.shtml
英文地址,請注明出處:http://en.pswp.cn/web/93776.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Tomcat里catalina.sh詳解

在 Tomcat 中&#xff0c;catalina.sh&#xff08;Linux/macOS&#xff09;或 catalina.bat&#xff08;Windows&#xff09;是 核心的啟動和關閉腳本&#xff0c;用于控制 Tomcat 服務器的運行。它是 Tomcat 的“主控腳本”&#xff0c;負責設置環境變量、啟動/關閉 JVM 進程&…

STM32之MCU和GPIO

一、單片機MCU 1.1 單片機和嵌入式 嵌入式系統 以計算機為核心&#xff0c;tips&#xff1a;計算機【處理單元&#xff0c;內存 硬盤】 可以控制的外部設備&#xff0c;傳感器&#xff0c;電機&#xff0c;繼電器 嵌入式開發 數據源--> 處理器(CPU MCU MPU) --> 執行器 …

22_基于深度學習的桃子成熟度檢測系統(yolo11、yolov8、yolov5+UI界面+Python項目源碼+模型+標注好的數據集)

目錄 項目介紹&#x1f3af; 功能展示&#x1f31f; 一、環境安裝&#x1f386; 環境配置說明&#x1f4d8; 安裝指南說明&#x1f3a5; 環境安裝教學視頻 &#x1f31f; 二、數據集介紹&#x1f31f; 三、系統環境&#xff08;框架/依賴庫&#xff09;說明&#x1f9f1; 系統環…

數據結構:二叉樹oj練習

在講今天的題目之前&#xff0c;我們還需要講一下二叉樹的以下特點&#xff1a; 對任意一顆二叉樹&#xff0c;如果度為0的節點個數是n0&#xff0c;度為2的節點個數是n2&#xff0c;則有n0n21. 證明&#xff1a;二叉樹總的節點個數是n&#xff0c;那么有nn0n1n2 二叉樹的度為…

RabbitMQ高級特性——TTL、死信隊列、延遲隊列、事務、消息分發

目錄 一、TTL 1.1設置消息的TTL 1.2設置隊列的TTL 1.3兩者之間的區別 二、死信隊列 2.1死信的概念 2.2死信產生的條件&#xff1a; 2.3死信隊列的實現 死信隊列的工作原理 2.4常??試題 三、延遲隊列 3.1概念 3.2應用場景 3.3RabbitMQ 實現延遲隊列的核心原理 1…

神經網絡設計中關于BN歸一化(Normalization)的討論

在神經網絡的結構中&#xff0c;我們常常可以看見歸一化&#xff08;Normalization&#xff09;如BN的出現&#xff0c;無論是模型的backbone或者是neck的設計都與它有著重大的關系。 因此引發了我對它的思考&#xff0c;接下來我將從 是什么&#xff08;知識領域&#xff0c;誕…

MacOS 安全機制與“文件已損壞”排查完整指南

1. 背景說明macOS 為了保護系統安全&#xff0c;內置了多個安全機制&#xff1a;機制作用是否影響第三方 AppSIP (System Integrity Protection)保護系統關鍵文件/目錄不被篡改高風險 App/驅動可能受限Gatekeeper限制未簽名/未認證 App 運行阻止“未知開發者” App文件隔離屬性…

package.json文件中的devDependencies和dependencies對象有什么區別?

前端項目的package.json文件中&#xff0c;dependencies和devDependencies對象都用于指定項目所依賴的軟件包&#xff0c;但它們在項目的開發和生產環境中的使用有所不同。1.dependencies&#xff1a;dependencies是指定項目在生產環境中運行所需要的依賴項。這些依賴項通常包括…

【最新版】CRMEB Pro版v3.4系統源碼全開源+PC端+uniapp前端+搭建教程

一.系統介紹 crmebPro版 v3.4正式發布&#xff0c;智能任務推送、動態標簽管理、商城AI生產力&#xff0c;煥然一新&#xff0c;不負期待&#xff01;頁面DIY設計功能全面升級&#xff0c;組件更豐富&#xff0c;樣式設計更全面&#xff1b;移動端商家管理&#xff0c;讓商城管…

AI 浪潮下 IT 從業者的職業展望:替代之惑與轉型之道

一、引言1.1 科技變革的浪潮&#xff1a;AI 崛起與 IT 行業震蕩在當今科技飛速發展的時代&#xff0c;人工智能&#xff08;AI&#xff09;無疑是最具影響力的變革力量之一。從實驗室的前沿研究到廣泛的商業應用&#xff0c;AI 以驚人的速度滲透到各個領域&#xff0c;徹底改變…

DSP音頻算法移植優化工程師實戰

以下以音頻FIR濾波器算法為例&#xff0c;完整演示從MATLAB原型 → Python驗證 → TI DSP C語言移植優化的全流程&#xff0c;包含關鍵代碼和優化技巧&#xff1a;關鍵優化技術解析&#xff1a; 內存訪問優化使用#pragma DATA_ALIGN確保64位對齊&#xff08;滿足LDDW指令要求&a…

Spark 運行流程核心組件(三)任務執行

一、啟動模式 1、standalone資源申請&#xff1a;Driver向Master申請Executor資源Executor啟動&#xff1a;Master調度Worker啟動Executor注冊通信&#xff1a;Executor直接向Driver注冊 2、YARNDriver向YARN ResourceManager(RM)申請AM容器RM分配NodeManager(NM)啟動AM&#x…

rabbitmq發送的延遲消息時間過長就立即消費了

RabbitMQ延遲消息在設置過長時間后被立即消費的問題&#xff0c;通常與以下原因有關&#xff1a; TTL限制問題 RabbitMQ對消息TTL(Time To Live)有32位整數限制(0-4294967295毫秒)&#xff0c;約49.7天。超過該值的延遲時間會導致消息立即被消費解決方案&#xff1a;確保設置的…

kafka的pull的依據

1. 每次 pull() 是否必須在提交上一批消息的 offset 之后&#xff1f;絕對不需要&#xff01; 提交 offset 和調用 poll() (拉取消息) 是兩個完全獨立的行為。消費者可以連續調用 poll() 多次&#xff0c;期間完全不提交任何 offset。 這是 Kafka 消費者的正常工作模式。提交 o…

學習嵌入式的第二十一天——數據結構——鏈表

單向鏈表特點&#xff1a;存儲的內存空間不連續 。為了彌補順序存儲存劣勢。優勢 插入&#xff0c;刪除 O(1) 動態存儲 &#xff0c;在程序運行期間決定大小。劣勢&#xff1a; 不能隨機訪問 O(N) 節點-> 數據域指針域 順序表(數組) 只有數據域鏈表的操作代碼&#xff1…

Rust Web 全棧開發(十三):發布

Rust Web 全棧開發&#xff08;十三&#xff09;&#xff1a;發布Rust Web 全棧開發&#xff08;十三&#xff09;&#xff1a;發布發布 teacher_service發布 svr測試 teacher_service 和 svr發布 wasm-client測試 wasm-clientRust Web 全棧開發&#xff08;十三&#xff09;&a…

Zephyr 中的 bt_le_per_adv_set_data 函數的介紹和應用方法

目錄 概述 1 函數接口介紹 1.1 函數原型 1.2 功能詳解 2 使用方法 2.1 創建流程 2.1.1 創建擴展廣播實例 2.1.2 設置周期性廣播數據 2.1.3 配置周期性廣播參數 2.1.4 啟動廣播 2.2 主流程函數 2.3 關鍵配置 (prj.conf) 3 高級用法 3.1 大數據分片傳輸 3.2 動態數…

Ansible 角色管理指南

Ansible 角色管理指南 實驗環境設置 以下命令用于準備實驗環境&#xff0c;創建一個工作目錄并配置基本的Ansible設置&#xff1a; # 創建web工作目錄并進入 [azurewhiskycontroller ~]$ mkdir web && cd web# 創建Ansible配置文件 [azurewhiskycontroller web]$ cat &…

【補充】數據庫中有關系統編碼和校驗規則的簡述

一、字符集和校驗規則&#xfeff;1.創建數據庫案例數據庫創建方法&#xff1a;使用CREATE DATABASE語句創建數據庫字符集指定方式&#xff1a;通過CHARACTER SETutf8指定數據庫編碼格式默認配置說明&#xff1a;未指定字符集時默認使用utf8和utf8_general_ci配置文件位置&…

計算機網絡 HTTP1.1、HTTP2、HTTP3 的核心對比及性能分析

以下是 HTTP/1.1、HTTP/2、HTTP/3 的核心對比及性能分析&#xff0c;重點關注 HTTP/3 的性能優勢&#xff1a;&#x1f4ca; HTTP 協議演進對比表特性HTTP/1.1 (1997)HTTP/2 (2015)HTTP/3 (2022)傳輸層協議TCPTCPQUIC (基于 UDP)連接建立TCP 三次握手 TLS 握手 (高延遲)同 HTT…