编写字符串去连续空格程序时出现Segmentation Fault,求原因解析
解析你的段错误问题及修复方案
嗨,我来帮你分析下这个Segmentation Fault(段错误)的原因,再给你一个能正常工作的实现方案~
可能触发段错误的核心原因
首先,咱们先排查最常见的几个坑:
- 修改只读字符串常量:如果调用函数时传入的是类似
"hello world"这种直接写的字符串常量(而不是存在栈上的可修改字符数组),那你试图给t[w]赋值的时候肯定会触发段错误——因为字符串常量存在程序的只读内存区,根本不允许写入操作。 - 数组越界访问:你代码里的嵌套循环逻辑有问题,
i被外层的i++和内层的j++,i++同时递增,很容易跳过字符串的终止符'\0',进而访问到数组之外的内存,直接触发段错误。 - 未处理字符串终止:就算逻辑没问题,处理完字符后没手动加
'\0',后续读取字符串时也可能读到垃圾数据,甚至间接引发越界。
你的代码片段的逻辑漏洞
看你贴的代码片段:
int limpaEspacos (char t[]){ int i, j, w=0; char c; for(i=0;t[i];i++){ t[w]=t[i]; w++; for(j=i;t[j];j++,i++){ if (...) // 这里应该是判断连续空格的逻辑,但没写完 } } // 缺少添加字符串终止符的代码 }
这里的嵌套循环是典型的逻辑误区:内层循环里i被两次递增,会导致外层循环的索引跳步,要么漏处理字符,要么直接跳过'\0'去访问非法内存,段错误也就来了。
修复后的正确实现
下面是一个能正确完成需求、避免段错误的版本,每一步都加了注释:
int limpaEspacos(char t[]) { int write_idx = 0; // 处理后字符串的写入索引 int read_idx = 0; // 原字符串的读取索引 int in_consec_space = 0; // 标记是否处于连续空格中 // 先防御空指针,避免传入NULL时崩溃 if (t == NULL) { return 0; } while (t[read_idx] != '\0') { if (t[read_idx] == ' ') { if (!in_consec_space) { // 只保留第一个空格,之后的连续空格跳过 t[write_idx++] = t[read_idx]; in_consec_space = 1; } } else { // 非空格字符直接写入,同时重置连续空格标记 t[write_idx++] = t[read_idx]; in_consec_space = 0; } read_idx++; } // 处理末尾的空格(可选,如果你不希望字符串以空格结尾的话) if (write_idx > 0 && t[write_idx - 1] == ' ') { write_idx--; } // 必须添加字符串终止符,否则处理后的字符串是非法的 t[write_idx] = '\0'; return write_idx; }
调用时的关键注意点
一定要确保传入的是可修改的字符数组,而不是字符串常量:
// 正确用法:栈上的字符数组,支持修改 char input[] = "hello world"; int result_len = limpaEspacos(input); // 此时input是"hello world",result_len为11
// 错误用法:字符串常量,不可修改,会触发段错误 char *input = "hello world"; int result_len = limpaEspacos(input);
测试验证
用你给的例子测试,输入"hello world",处理后得到"hello world",返回长度11,完全符合你的需求。
内容的提问来源于stack exchange,提问作者Carlos Afonso
相关产品推荐
相关产品推荐

