C语言中给isdigit传指针为何有时触发core dump有时不
问题原因分析
1. 为什么没有编译报错
C标准中isdigit的函数原型是int isdigit(int c);,它的入参要求是要么是EOF值,要么是可被隐式转换为unsigned char的字符值。
你传入的s是char*类型的指针,本质是内存地址的整数值,C语言允许指针类型隐式转换为整型,所以只要你没有开启高等级的编译警告(比如-Wall -Wextra),编译器不会报错,最多只会给出隐式转换的警告。
2. 两种写法表现不同的核心原因
两种写法触发的都是未定义行为(Undefined Behavior),未定义行为的表现是不可预测的,可能运行正常、可能输出错误结果、也可能直接段错误,你遇到的差异只是未定义行为的不同表现形式而已,具体到你的场景可以这么解释:
- 第一种写法
isdigit(s), s++;后直接return -1:
首先逗号表达式会忽略isdigit(s)的返回值,其次你传的指针s的地址值截断为int后,要么刚好落在标准库isdigit内部查表数组的合法下标范围内,访问该内存可读没有触发越界;要么你使用的标准库isdigit实现对大于255的入参直接返回0,没有查表操作,再加上执行完这行就直接返回了,没有后续非法操作,所以看起来没有崩溃。 - 第二种写法触发段错误:
你测试时大概率注释掉了if块后的return -1,代码会继续执行到下方的for循环:- 首先
if (!isdigit(s))的判断结果不可预测,如果结果为真就会执行s++,指针偏移后可能指向非法内存 - 其次
for循环的条件里写的是isdigit(s),同样是传入指针而非字符值,如果某次s的地址值作为查表下标刚好落在不可读的内存区域,就会直接触发段错误;或者s指针偏移后指向非法地址,执行*s取值的时候也会触发段错误。
- 首先
3. 正确写法
所有需要传入字符值的地方都要给指针解引用,也就是写isdigit(*s),传入s指向的字符值而不是指针本身。
内容的提问来源于stack exchange,提问作者Lyon Ma
相关产品推荐
相关产品推荐

