STM32 Nucleo平台strtok无法返回NULL致死循环问题求助
问题根源:数组越界破坏了strtok的内部状态
让我们直奔主题——你的代码出现死循环的核心原因是数组越界访问破坏了strtok函数的内部静态变量,线上编译器没出问题只是运气好(属于未定义行为,随时可能翻车)。
具体分析:
你输入的字符串是 "2x^2+x/5+2=0",用分隔符 "+-=" 分割后,会得到4个独立的token:
"2x^2""x/5""2""0"
但你定义的数组 char *array[2]; 只能容纳2个指针。当循环执行到第3次时,i 变成2,此时 array[i++] = ptr 会写入 array[2]——这属于数组越界,会直接覆盖栈上的其他内存数据。
而strtok函数是依赖内部静态变量来记录上次分割位置的(这也是它线程不安全的原因),在STM32这类嵌入式平台使用的Newlib库中,这个静态变量的存储位置刚好被你越界写入的内容破坏了。结果就是strtok无法正确判断字符串是否处理完毕,每次调用都返回非NULL值,直接导致死循环。
线上编译器的栈布局或者内存保护机制可能让越界的影响没有立刻显现,但这绝对不是正确的行为——未定义行为在任何时候都可能引发奇怪的bug。
修复方案
1. 先解决数组越界问题
首先扩大数组容量,确保能容纳所有可能的token。比如根据你的输入,至少需要4个元素:
char *array[4];
同时在循环中加上数组长度的限制,防止未来输入变化再次导致越界:
while (ptr != NULL && i < sizeof(array)/sizeof(array[0])) { array[i++] = ptr; ptr = strtok(NULL, delim); }
2. 修正其他隐藏问题
除了死循环,你的代码还有几个逻辑错误,也需要一起修复:
- 返回类型错误:函数计算的是浮点数,但返回类型是
int,会直接丢失精度,应该改成float。 - 一元一次方程解算错误:
ax + b = 0的正确解是x = -b/a,原代码写成了b/a。 - 系数解析错误:
array[1]是"x/5",直接用atof解析会得到0(因为遇到'x'就停止了),需要额外处理提取系数的逻辑,比如跳过'x'后解析分数或数字。
修改后的完整代码
#include <string.h> #include <stdio.h> #include <stdlib.h> #include <math.h> #include <ctype.h> float funk(char *skai) { char delim[] = "+-="; int i = 0; float x, d = 0; char *array[4]; // 扩大数组容量以容纳所有token char *ptr = strtok(skai, delim); // 循环时同时限制数组索引,避免越界 while (ptr != NULL && i < sizeof(array)/sizeof(array[0])) { array[i++] = ptr; ptr = strtok(NULL, delim); } // 先检查token数量是否符合预期,避免后续访问越界 if (i < 3) { printf("Error: Invalid input format\n"); return 0.0f; } // 解析二次项系数a int a = atoi(array[0]); if (a == 0) { printf("Error: Quadratic coefficient can't be zero\n"); return 0.0f; } // 解析一次项系数b(处理x、2x、x/5等形式) float b = 0.0f; char *b_str = array[1]; // 跳过开头的'x' if (*b_str == 'x') { b_str++; // 如果是x/5这种分数形式 if (*b_str == '/') { int denominator = atoi(b_str + 1); if (denominator != 0) { b = 1.0f / denominator; } else { printf("Error: Division by zero\n"); return 0.0f; } } else if (strlen(b_str) == 0) { // 单纯的x,系数为1 b = 1.0f; } else { // 带数字的系数,比如2x或-3x b = atof(b_str); } } else { // 理论上不会走到这里,除非输入格式异常 printf("Error: Invalid linear term format\n"); return 0.0f; } // 解析常数项c int c = atoi(array[2]); if (c != 0) { d = b * b - 4 * a * c; if (d > 0) { float root1 = (-b + sqrt(d)) / (2 * a); float root2 = (-b - sqrt(d)) / (2 * a); x = (root1 > root2) ? root1 : root2; } else { x = -b / (2 * a); } } else { // 一元一次方程的解 x = -b / a; } printf("Result: %0.3f\n", x); return x; } int main(void) { char rxd[20] = "2x^2+x/5+2=0"; funk(rxd); return 0; }
额外建议
- 嵌入式平台上尽量避免使用strtok这类依赖静态变量的函数,因为它不仅线程不安全,还容易因为内存越界破坏内部状态。如果可以,改用
strtok_r(可重入版本)会更可靠。 - 对于输入解析,最好添加更多的格式校验,避免因为异常输入导致程序崩溃。
内容的提问来源于stack exchange,提问作者Karol Rawdo
相关产品推荐
相关产品推荐

