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

C/C++ 字串常量比較陷阱與正確拷貝姿勢

     編輯:關於C++

現象:看似相同的字串常量卻不相等

if ("test" == "test")  // 編譯器可能優化合併,但標準不保證
    cout << "相等";
else
    cout << "不相等";  // 多數情況輸出此行

根因:字串常量存儲於唯讀資料段,各自擁有獨立地址

  • "test" 是 const char[5],編譯期分配於 .rodata 區。
  • 兩處字面量雖內容相同,但 C++ 標準**不要求**合併(合併屬編譯器優化行為)。
  • == 比較的是**地址**,而非內容,故多數情況判定為不相等。

正確做法:使用 strcmp 比較內容

#include <cstring>
if (strcmp("test", "test") == 0)  // 返回 0 表示相等
    cout << "相等";

strcmp(const char*, const char*) 逐字元比較,直到遇到差異或 \0,相等返回 0,否則返回非零值(正/負表示字典序大小)。

字串拷貝:strcpy vs memcpy

場景 1:以 \0 結尾的 C 風格字串 → strcpy

char src[] = "test str!";
char dst[15];
strcpy(dst, src);  // 包含結束符 \0 自動複製
cout << dst;       // 輸出: test str!
  • src 是陣列,可修改;若寫 char *p = "literal" 則指向唯讀區,**不可**作為 strcpy 目的端。
  • 目的端必須預留足夠空間,否則緩衝區溢出。

場景 2:任意二進位資料 / 非 \0 結尾陣列 → memcpy

int a[] = {1,2,3,4,5};
int b[5];
memcpy(b, a, sizeof(a));  // 第三參數為位元組數
for (int i=0; i<5; ++i) cout << b[i] << ",";  // 1,2,3,4,5,
  • memcpy(void* dest, const void* src, size_t n) 逐位元組複製 n bytes,不關心內容語意。
  • 適用於結構體、整數陣列、二進位緩衝區等無 \0 終止符的場景。
  • 注意:重疊記憶體區域請用 memmove。

常見錯誤對比表

錯誤代碼問題修正
if (str1 == str2)比較指標地址strcmp(str1, str2) == 0
char *p = "abc"; strcpy(p, "def");寫入唯讀區導致崩潰char p[] = "abc"; 或 char *p = new char[4];
strcpy(dst, src); // dst 未分配空間緩衝區溢出確保 sizeof(dst) > strlen(src)+1
memcpy(dst, src, sizeof(src)); // src 是指標sizeof 取得指標大小而非資料長度顯式傳遞長度或用 strlen+1

現代 C++ 建議

  • 優先使用 std::string:支援 == 直接比較內容,自動管理記憶體,避免上述所有坑。
  • 需 C 風格介面互操作時,用 str.c_str() 取得 const char*,strcpy(buf, str.c_str()) 時確保緩衝區足夠。
  • 二進位資料用 std::vector<uint8_t> 或 std::span (C++20),配合 std::copy 替代 memcpy,型別安全且可檢查邊界。

總結

  1. 字串常量比較**必須**用 strcmp(或 std::string),切勿用 ==。
  2. strcpy 專為以 \0 結尾字串設計;memcpy 適用於任意記憶體塊,需手動指定長度。
  3. 目的緩衝區必須可寫且足夠大,來源若為字面量常量則不可作為目的端。
  4. 現代 C++ 專案中,能用 std::string/std::vector 就別手寫 C 風格字串操作。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved