Valgrind报Conditional jump错误排查:已初始化变量仍触发问题
解决Valgrind提示的“Conditional jump or move depends on uninitialised value(s)”问题
你的代码功能正常,但触发Valgrind未初始化内存错误的核心原因是:normalize_wspace2的for循环处理末尾空白时,i会被递增到字符串终止符'\0'的下一个位置,此时循环条件检查_str[i] != '\0'会访问栈上未初始化的内存。
错误触发流程
- 原字符串末尾是连续空白时,进入空白判断分支,执行
while循环跳过所有空白,最终i指向'\0'。 - 执行
_str[j] = _str[i],把'\0'写入目标位置。 - 执行for循环的
j++, i++,此时i指向'\0'的下一个字节——这部分属于栈上未初始化的内存。 - 循环条件检查
_str[i] != '\0',访问了未初始化的值,触发Valgrind报错。
另外del_twspace函数存在隐患:如果输入字符串全是空白字符,last_char会保持初始值-1,执行s[last_char + 1] = '\0'虽然不会崩溃,但逻辑不严谨。
修复后的代码
#include "main.h" #include <stdio.h> #include <ctype.h> void normalize_wspace2(char *_str); void del_twspace(char *s); int main(void) { char s[] = " ls -la f1\t folder2 this one\t\t "; printf("s initial = %s,\n", s); normalize_wspace2(s); printf("s normalized = %s,\n", s); } void normalize_wspace2(char *_str) { size_t i = 0, j = 0; // 跳过开头所有空白 while (isspace((unsigned char)_str[i])) { i++; } for (; _str[i] != '\0'; i++) { if (isspace((unsigned char)_str[i])) { // 写入单个空格 _str[j++] = ' '; // 跳过后续所有空白 while (isspace((unsigned char)_str[++i])) { if (_str[i] == '\0') break; } // 提前遇到终止符就退出循环 if (_str[i] == '\0') break; } // 复制非空白字符 _str[j++] = _str[i]; } _str[j] = '\0'; del_twspace(_str); } void del_twspace(char *s) { if (s == NULL) { fprintf(stderr, "error: del_twspace passed null\n"); return; } size_t last_non_ws = 0; int has_non_ws = 0; size_t i = 0; while (s[i] != '\0') { if (!isspace((unsigned char)s[i])) { last_non_ws = i; has_non_ws = 1; } i++; } // 处理全空白字符串的情况 if (has_non_ws) { s[last_non_ws + 1] = '\0'; } else { s[0] = '\0'; } }
关键修复说明
normalize_wspace2:- 先跳过开头空白,避免生成以空格开头的字符串。
- 重构循环逻辑,确保
i不会越过'\0',彻底避免访问未初始化内存。 - 用
isspace简化空白判断,覆盖所有标准空白字符(空格、制表符、垂直制表符等),代码更简洁。
del_twspace:- 新增
has_non_ws标记,处理全空白字符串的边界情况,避免last_char为-1的问题。 - 把
perror换成fprintf,因为perror用于系统调用错误,这里是参数错误,更合适。
- 新增
内容的提问来源于stack exchange,提问作者mnalish27
相关产品推荐
相关产品推荐

