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

新加坡程式設計師測試題深度解析:STL string 衍生與 Token 分割實作

     編輯:關於C++

題目需求核心解讀

題目明確要求:

  1. 衍生自 STL 標準 std::string**,非 MFC CString。
  2. 衍生類別命名為 String**,非 CMyString。
  3. 實作 operator/ 計算子字串出現次數、get_token() 分割語彙。

原始碼完全不符合上述要求,以下提供符合規範的正確實作與錯誤分析。

正確實作範例

1. 例外類別與 operator/ 實作

class divide_empty_substring : public std::logic_error {
public:
    const char* what() const throw() { 
        return "Divided by an empty substring"; 
    }
};

std::string::size_type String::operator/(const String& sub) const {
    if (sub.empty())
        throw divide_empty_substring();  // 拋出例外優於回傳 0
    
    std::string::size_type n = 0;
    std::string::size_type i = 0;
    while ((i = find(sub, i)) != std::string::npos) {
        ++n;
        i += sub.length();  // 避免無限迴圈
    }
    return n;
}

關鍵點:

  • 第二個 const 表示不修改物件狀態。
  • 使用 std::string::npos 而非 -1。
  • 找到後需前移索引 i += sub.length(),否則空字串會無限迴圈。
  • 拋出例外比回傳 0 更符合 C++ 慣例,呼叫端可明確處理錯誤。

2. get_token() 實作避坑指南

嚴禁使用 static 區域變數! 題目敘述易誤導使用 static 計數器,但成員函式應使用成員變數追蹤狀態。否則多物件共用 static 變數會導致錯誤:

String str1, str2;
str1.get_token();  // 取得 str1 第一個 token
str2.get_token();  // 錯誤:取得 str2 的第二個 token(static 計數器共用)

原始碼錯誤深度剖析

operator/ 錯誤

int CMyString::operator/(const String& sub) {
    if (sub.IsEmpty()) return 0;
    int count = 0;
    int ret = Find(sub);
    if (ret == -1) return 0;
    else if (ret <= GetLength())  // 條件永真,多餘
    {
        do {
            count++;
            ret = Find(sub, GetAt(ret));  // GetAt() 回傳字元,非索引!邏輯錯誤
        } while (ret != -1);
    }
    return count;
}
  • GetAt(ret) 回傳位置 ret 的字元,非下一搜尋起始索引,導致邏輯完全錯誤。
  • 迴圈缺少索引遞增,若子字串重疊會無限迴圈或漏計。

get_token() 災難現場

CString CMyString::get_token() {
    static int callednum = 0;  // 致命錯誤:static 共用於所有實例
    int totalnum = operator/(' ');  // 空格總數
    if (totalnum == 0) return NULL;
    int tokennum, ret1 = 0, ret2 = 0;
    while ((ret1 = Find(' ', ret2)) != -1 && (ret2 = Find(' ', ret1)) != -1) {
        // ret1, ret2 初始皆 0,永遠找到第一個空格 → 無限迴圈或錯誤
        if (ret1 == ret2 - 1) totalnum--;  // 相鄰空格合併
        return Mid(ret1, ret2 - ret1);  // 提早返回,callednum 不遞增
    }
    // 以下程式碼永遠不會執行...
    if (ret2 == -1) return Right(GetLength() - ret1);
    tokennum = totalnum;
    (callednum++) %= tokennum;  // tokennum 等於 totalnum,多此一舉
    // 最後分支無返回值 → 未定義行為
}
  • static callednum 導致多物件狀態汙染。
  • 迴圈條件 ret1=Find(' ', ret2) 與 ret2=Find(' ', ret1) 互相依賴初始值 0,邏輯崩壞。
  • 提早 return 導致狀態更新失效,後半段死碼。
  • 函式宣告回傳 CString 卻回傳 NULL,型別不匹配。
  • 控制流程混亂,缺乏邊界檢查。

正確設計原則總結

  1. 嚴格遵循題目規範:基底類別、類別命名、函式簽章。
  2. 例外處理優於錯誤碼:語意清晰、不可忽略。
  3. 成員變數維護物件狀態:拒絕 static 區域變數造成跨實例干擾。
  4. 演算法邏輯嚴謹:索引正確遞增、邊界處理、避免無限迴圈。
  5. 程式碼完整性:所有路徑皆有返回值、型別一致。

此題考驗不僅是語法熟悉度,更是物件導向設計、標準庫運用與防禦性程式設計能力的綜合體現。

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