HOWTO · C++

如何在 C++ 中把 Char 陣列轉換為 Int

本文演示了在 C++ 中把 char 陣列轉換為 int 型別的方法。

本頁內容

以 null 結尾的 char 陣列可以存放代表整數的文字。C++ 提供多種解析方式,但各函式回報錯誤的方式不同,也不一定會接受數字前綴後面還有其他字元的輸入。請依輸入是否可信,以及是否要求整個陣列都必須是有效數字來選擇方法。

範例使用十進位輸入。成功解析數字前綴,不代表每個字元都已經處理;例如,解析 "23323tail" 可能會得到 23323,而 tail 則未被解析。如果要求整個輸入都必須是數字,除了檢查轉換結果,也要檢查解析器停止的位置。

使用 std::strtol 函式將 char 陣列轉換為 int

std::strtol 會解析以 null 結尾的字元序列,並回傳 long。第三個引數用來指定數基:十進位使用 10、十六進位使用 16,或使用 0 根據前綴推斷數基。數基不為零時,有效範圍是 2 到 36。

第二個引數會接收一個指標,指向第一個未處理的字元。如果它仍指向輸入開頭,表示沒有解析到任何數字;如果它指向結尾的 null 字元,表示整個字串都已處理。呼叫函式前先將 errno 設為零,並在呼叫後檢查 ERANGE,以偵測結果是否超出 long 的範圍。由於結果型別是 long,存入 int 前也要先與 std::numeric_limits<int>::min() 和 max() 比較。

執行此範例。它使用存放在以 null 結尾之字元陣列中的十進位文字,並印出解析後的整數。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

#include <cerrno>
#include <cstdlib>
#include <iostream>
#include <limits>

int main() {
  const char input[] = "23323";
  char* end = nullptr;
  errno = 0;
  const long parsed = std::strtol(input, &end, 10);

  if (end == input || *end != '\0' || errno == ERANGE ||
      parsed < std::numeric_limits<int>::min() ||
      parsed > std::numeric_limits<int>::max()) {
    std::cout << "Could not convert the complete input.\n";
    return 0;
  }

  const int value = static_cast<int>(parsed);
  std::cout << value << '\n';
}

提供的成功案例執行結果為退出碼 0,輸出如下:

23323

這次執行只涵蓋有效輸入,無法據此判斷轉換失敗或數值超出範圍時的行為。用於正式環境的輸入仍應保留這些檢查,藉此區分沒有轉換、仍有未處理字元、long 範圍錯誤,以及數值無法放入 int 的情況。

使用 std::atoi 函式將 char 陣列轉換為 int

當輸入可信且格式正確時,std::atoi 是較簡短的選擇:

int value = std::atoi(input);

它會接受開頭的空白字元與可選的正負號,接著解析十進位數字。和其他只解析前綴的函式一樣,遇到非數字字元時可能停止解析,並忽略後續字元。它無法可靠地區分有效的零與轉換失敗,也沒有實用的錯誤回報方式可用來檢查範圍錯誤。如果解析出的數值無法由 int 表示,行為未定義;不要對未檢查或不可信的數字輸入使用 std::atoi。如果輸入可能格式錯誤或超出範圍,或呼叫端需要轉換診斷資訊及明確的 int 範圍檢查,請改用 std::strtol。

使用 std::sscanf 函式將 char 陣列轉換為 int

std::sscanf 會依照格式解析文字,並回報成功轉換的項目數量。若要解析一個整數,請確認回傳值為 1 後再使用目的變數:

int value = 0; int converted = std::sscanf(input, "%d", &value);

%d 會接受開頭的空白字元與可選的正負號,接著讀取十進位數字。它可能成功解析一段前綴,卻留下後續文字未讀;若要求完整解析,請搭配額外的格式檢查,或改用其他解析方法。目的變數必須是實際存在且可寫入的 int 物件;只有在轉換次數確認成功轉換後,才能讀取它。即使轉換次數符合要求,也不代表無法表示的數值是安全的:如果匹配到的數值無法由 int 表示,行為仍未定義。不要對可能超出範圍、未經檢查或不可信的數字輸入使用 %d。對這項簡單工作而言,std::strtol 能更明確地提供停止位置與範圍檢查方式。

使用迴圈將 char 陣列轉換為 int

當程式刻意採用自訂語法時,使用迴圈才合適。請先定義接受的語法。例如,十進位解析器可以接受開頭的 + 或 -,要求至少有一個數字,並拒絕其他所有字元。每次乘法與加法之前,也必須檢查下一個數字是否仍在指定的整數範圍內;否則,有號整數溢位可能導致結果錯誤或引發未定義行為。

不要略過任意非數字字元,再把後面的數字接起來:將 "23tail4" 轉成 234 是篩選字元,不是解析整數。完整的自訂解析器必須處理正負號位置、數字驗證、完整輸入消耗及溢位。除非確實需要這些自訂規則,否則請改用 std::strtol 及其結尾指標。

結論

一般情況下,優先使用 std::strtol:它會提供停止位置,也能偵測 long 範圍錯誤,並可在轉換前將結果與 int 的範圍比較。只有在輸入可信、格式正確且不需要詳細診斷資訊時,才使用 std::atoi。需要格式化解析時,可選用 std::sscanf,並檢查其轉換次數。若程式需要刻意採用不同的輸入語法,才自行撰寫迴圈,並明確處理正負號、數字、完整輸入消耗及溢位檢查。