Arduino字符串分割程序输出异常:strtok分割结果不符合预期
异常根因定位
原代码存在两个核心逻辑错误,直接导致输出异常:
- 类型不匹配导致逐字符读取:
stringsplit函数当前返回值为*words,等价于返回words[0]——也就是第一个分割字符串的起始字符指针(char*类型)。后续代码把这个指向单个字符串的指针,直接当成字符数组逐位取值:p1[0]是第一个字符串的首字符、p1[1]是第一个字符串的第二个字符,最终只能输出单字符,完全匹配你看到的f、i、r、s的输出结果。 - 局部栈内存的野指针风险:函数内部定义的
char *words[4]是运行在栈上的局部数组,函数一旦执行完毕,栈帧被回收,就算修正返回值逻辑,后续读取数组内容也会出现数据错乱、乱码的问题。
修复方案
修改核心逻辑:将存储分割结果的指针数组改为静态存储、修正返回值类型匹配关系,最终可用代码如下:
// 返回值为二级指针,指向存储分割结果的指针数组首地址 char** stringsplit(char msg[]) { // 用static修饰数组,存储在静态内存区,不会随函数退出被回收 static char *words[4]; char *p; int i = 0; char dauphay[] = ","; p = strtok(msg, dauphay); while(p && i < 4) { words[i] = p; p = strtok(NULL, dauphay); i++; } // 未填满的数组位置设置为空指针,避免后续读取到无效值 while(i < 4) { words[i] = NULL; i++; } // 直接返回数组首地址,不做解引用操作 return words; } void setup() { Serial.begin(115200); char msg[] = "first,Second,third,four"; // 用二级指针接收返回的指针数组地址 char **p1 = stringsplit(msg); for(int i = 0; i < 4; i++) { // 遇到空指针就终止循环,避免读取乱码 if(p1[i] == NULL) break; Serial.println(p1[i]); } } void loop() { }
代码优化说明
- 给内部存储分割结果的数组加
static修饰后,数组内存和程序生命周期一致,彻底解决局部栈内存回收导致的野指针问题 - 修正返回值类型为
char**,和调用方的接收变量类型匹配,此时p1[i]对应每个分割字符串的起始地址,传给Serial.println即可输出完整的分割结果 - 增加空值判断逻辑,当输入字符串分割后的段数不足4个时,会直接终止输出,不会读到内存中的随机乱码
- 注意:
strtok会直接修改传入的原字符串,将分隔符替换为字符串结束符,因此传入的参数必须是可修改的字符数组,不能直接传入字符串常量(存在于Flash只读区,修改会触发硬件异常)
内容的提问来源于stack exchange,提问作者nghihoang2207
相关产品推荐
相关产品推荐

