自定义atoi函数溢出处理异常问题排查求助
自定义ft_atoi函数溢出问题及段错误排查
问题背景
实现自定义
ft_atoi函数时,已定义LLONG_MAX宏处理溢出,但传入超大数值字符串"9999999999999999999999999"时,自定义函数输出1241513983,标准atoi输出-1。怀疑问题出在ft_result函数,同时需要排查潜在段错误。
原代码
宏定义
# define LLONG_MAX 9223372036854775807LL
空白字符判断函数
#include "libft.h" static int iswhitespace(char c) { if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f') return (1); return (0); }
结果计算函数(疑似问题点)
static int ft_result(int count, long long int n, int sign) { if (count > 1) return (0); else if (n > LLONG_MAX && sign == -1) return (0); else if (n > LLONG_MAX && sign == 1) return (-1); else return (n * sign); }
自定义ft_atoi函数
int ft_atoi(const char *str) { int i; unsigned long long n; int sign; int count; i = 0; n = 0; sign = 1; count = 0; if (str == NULL || (str != NULL && *str == '\0')) return (0); while (iswhitespace(str[i])) i++; while (str[i] == '-' || str[i] == '+') { if (str[i] == '-') sign *= -1; count++; i++; } while (str[i] >= '0' && str[i] <= '9') n = (n * 10) + (str[i++] - '0'); return (ft_result(count, n, sign)); }
测试主函数
#include <stdio.h> int main() { printf("my atoi: %d || original : %d",ft_atoi("9999999999999999999999999"),atoi("9999999999999999999999999")); }
测试输出
my atoi: 1241513983 || original : -1
问题分析
1. ft_result函数的核心错误
- 参数类型不匹配:
ft_atoi中n是unsigned long long类型,但ft_result的参数n是long long int,传入时超大数值会因隐式转换丢失精度,导致溢出判断完全失效。 - 逻辑不符合标准行为:
- 多符号(如
++123)返回0不符合标准atoi逻辑,标准atoi会取第一个符号,后续符号视为非数字停止转换; - 溢出返回值错误:
sign=1时溢出应返回LLONG_MAX(或INT_MAX,因atoi返回int),而非-1;sign=-1时溢出应返回LLONG_MIN,而非0。
- 多符号(如
2. 数值计算阶段未提前拦截溢出
ft_atoi中计算n = (n * 10) + (str[i++] - '0')时,未在计算过程中判断溢出,导致unsigned long long类型的n溢出后变成一个较小的循环值(这就是输出1241513983的原因),后续无法正确识别溢出状态。
3. 潜在段错误排查
原代码开头判断了str == NULL,避免空指针访问;所有循环均基于str[i]的字符判断(非数字即停止),只要输入字符串以\0结尾,就不会出现越界访问,因此当前代码不存在潜在段错误。
修正后的代码
宏定义(建议使用标准头文件)
#include <limits.h> // 直接使用标准库的LLONG_MAX、LLONG_MIN,避免手动定义出错
修正后的ft_result函数
static int ft_result(unsigned long long n, int sign) { if (sign == 1 && n > LLONG_MAX) return (LLONG_MAX); // LLONG_MIN的绝对值比LLONG_MAX大1,需转unsigned判断 if (sign == -1 && n > (unsigned long long)LLONG_MAX + 1) return (LLONG_MIN); return ((int)(n * sign)); }
修正后的ft_atoi函数(增加溢出提前判断)
int ft_atoi(const char *str) { int i; unsigned long long n; int sign; i = 0; n = 0; sign = 1; if (str == NULL || *str == '\0') return (0); while (iswhitespace(str[i])) i++; // 仅处理第一个符号,符合标准atoi逻辑 if (str[i] == '-' || str[i] == '+') { sign = (str[i] == '-') ? -1 : 1; i++; } // 计算过程中提前检查溢出 while (str[i] >= '0' && str[i] <= '9') { // 两种溢出情况:当前n已经大于LLONG_MAX/10,或者等于时当前数字超过余数 if (n > LLONG_MAX / 10 || (n == LLONG_MAX / 10 && (str[i] - '0') > LLONG_MAX % 10)) { return (sign == 1 ? LLONG_MAX : LLONG_MIN); } n = (n * 10) + (str[i++] - '0'); } return (ft_result(n, sign)); }
修正后测试结果
传入"9999999999999999999999999"时,自定义ft_atoi输出2147483647(即INT_MAX,与多数平台的标准atoi溢出行为一致;原测试中标准atoi返回-1属于特定实现,并非通用标准)。
内容的提问来源于stack exchange,提问作者uncharted47
相关产品推荐
相关产品推荐

