atoi (ASCII to Integer) 是將字串轉換為整數的標準庫函數。手寫實作能深入理解字串解析、正負號處理、溢位檢測、非數字字符停止規則。本文提供標準版、健壯版(含錯誤回報)、strtol 風格完整版,並分析 INT_MIN 邊界陷阱。
#include <stdio.h>
int my_atoi(char s[]) {
int sign = 1; // 正負號旗標
int result = 0;
char *p = s;
// 1. 跳過前導空白 (標準 atoi 行為)
while (*p == ' ' || *p == '\t' || *p == '\n') p++;
// 2. 處理正負號
if (*p == '-') {
sign = -1;
p++;
} else if (*p == '+') {
p++;
}
// 3. 累積數字
while (*p >= '0' && *p <= '9') {
result = result * 10 + (*p - '0');
p++;
}
return sign * result;
}
int main() {
char s[20];
gets(s); // 注意:gets 不安全,教學用
int ret = my_atoi(s);
printf("%d\n", ret);
return 0;
}
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>
// 回傳碼:0=成功, -1=溢位, -2=無有效數字, -3=空指標
int my_atoi_robust(const char *str, long long *out) {
if (!str) return -3;
const char *p = str;
// 跳過空白
while (isspace(*p)) p++;
// 正負號
int sign = 1;
if (*p == '-') { sign = -1; p++; }
else if (*p == '+') { p++; }
// 至少一個數字
if (!isdigit(*p)) return -2;
long long result = 0;
while (isdigit(*p)) {
int digit = *p - '0';
// 溢位檢測:result * 10 + digit > LLONG_MAX
if (result > (LLONG_MAX - digit) / 10) {
return -1; // 溢位
}
result = result * 10 + digit;
p++;
}
*out = sign * result;
return 0;
}
輸入 標準 atoi 健壯版 說明 "123"123 123 正常 "-456"-456 -456 負號 " 789"789 789 前導空白 "12abc"12 12 (endptr 指向 a) 非數字停止 "abc"0 錯誤 -2 無數字 "2147483648"UB (溢位) 錯誤 -1 / LONG_MAX INT_MAX+1 "-2147483649"UB 錯誤 -1 / LONG_MIN INT_MIN-1 ""0 錯誤 -2 空字串 NULLCrash 錯誤 -3 空指標 INT_MIN 絕對值溢位陷阱
// INT_MIN = -2147483648 // 絕對值 2147483648 > INT_MAX (2147483647) // 直接 -INT_MIN 導致有號整數溢位 (UB) // 解決:使用長整型或無號型別計算 long long val = str; if (val < 0) val = -val; // long long 足夠容納 // 或:累積時用無號長整型 unsigned long long uval = 0; while (isdigit(*p)) { uval = uval * 10 + (*p - '0'); // 檢查 uval > (unsigned)LLONG_MAX ... } result = sign * (long long)uval;標準庫 atoi vs strtol
atoi:簡單、無錯誤回報、溢位未定義行為、已棄用。strtol:完整錯誤處理、支援任意基數 (2-36)、endptr 回傳解析結束位置、推薦使用。strtoll / strtoull:64 位版本。手寫 atoi 不只是面試題,更是理解「字串解析狀態機」、「有號整數溢位語義」、「API 設計權衡」的最佳切入點。建議實作健壯版並編寫完整單元測試覆蓋上述所有邊界案例。