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

STL string::find 陷阱深度解析:為什麼查找位置總是返回 3?

     編輯:關於C語言

現象重現

string s = "UIPower";
string s2 = "owe";
size_t x = s.find("owe", 1); // 從下標 1 開始找 "owe"
size_t y = s.find(s2, 2);    // 從下標 2 開始找 s2
// 預期 x=2, y=1,實際 x=3, y=3

源碼追蹤

查看 MSVC STL xstring 中 find(const _Elem* _Ptr, size_type _Off, size_type _Count) 實現:

  1. _Off 為起始偏移,_Count 為模式串長度。
  2. 內層循環用 _Traits::find(_Vptr, _Nm, *_Ptr) 尋找模式串首字符(此處 'o')。
  3. 找到後用 _Traits::compare(_Uptr, _Ptr, _Count) 比較前 _Count 字符。
  4. 匹配成功返回 _Uptr - _Myptr() —— 這裡的關鍵:_Myptr() 返回的是字符串緩衝區起始地址,而非 _Vptr(偏移後地址)!

根本原因

_Myptr() 內部邏輯:

_Elem* _Myptr() {
    return (_BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf); // 總是返回緩衝區首地址
}

因此 _Uptr - _Myptr() 計算的是模式串在原字符串中的絕對下標,而非相對於 _Off 的相對下標。這導致無論 _Off 為多少,返回值始終是模式串首字符在原串中的首次出現位置。

驗證

string s = "UIPower";      // 下標: 0:U 1:I 2:P 3:o 4:w 5:e 6:r
s.find("owe", 1); // 返回 3('o' 在原串下標 3)
s.find("owe", 2); // 仍返回 3
s.find("owe", 3); // 仍返回 3
s.find("owe", 4); // 返回 npos(因為 'o' 在 3,已被跳過)

結論與建議

  • 這是 STL 實現的行為特性(非標準規定):C++ 標準僅要求返回「第一個不小於 pos 的匹配位置」,MSVC 選擇返回全局首次出現位置。
  • 跨平台代碼不能依賴此行為,GCC libstdc++ 會正確返回相對位置。
  • 若需精確控制,建議自行實現 KMP/BM 或使用 std::search 配合迭代器範圍。

補充:正確用法示例

// 手動實現帶偏移的精確查找
size_t find_from(const string& haystack, const string& needle, size_t pos) {
    if (pos > haystack.size()) return string::npos;
    auto it = std::search(haystack.begin() + pos, haystack.end(),
                          needle.begin(), needle.end());
    return (it != haystack.end()) ? (it - haystack.begin()) : string::npos;
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved