开发简易Shell时的回车空白行段错误及分隔符适配问题求助
修复简易Shell空白行触发段错误的问题
嘿,我来帮你搞定这个Shell的段错误问题!咱们先拆解一下核心原因,再一步步修复:
问题根源分析
- 空指针访问触发段错误:当输入空白行时,
strtok找不到任何符合分隔符(" \n")的有效token,所以split_str返回的args数组第一个元素args[0]是NULL。但你在main里直接用strcmp(args[0], "exit"),这相当于对空指针做字符串操作,直接触发段错误。 - 内存分配类型错误:
split_str里的eachstr = malloc(sizeof(char) * 100);是错的!eachstr是char**类型(指向字符串指针的数组),每个元素是char*,所以应该分配sizeof(char*) * 100,否则内存空间不够存指针,会导致后续越界写入,埋下隐患。 - 额外小问题:
getline会自动重新分配userinput的内存(你传了&r作为第二个参数),所以一开始手动malloc的1000字节其实没必要,甚至可能和getline的内存管理冲突,不过这个不是当前段错误的直接原因。
修复后的代码
修复split_str函数
char **split_str(char *buf) { char *token, **eachstr; char *delim = " \n"; int count = 0; // 分配能存100个char*的内存,而非char的内存 eachstr = malloc(sizeof(char*) * 100); if (!eachstr) return NULL; token = strtok(buf, delim); while (token) { eachstr[count] = token; token = strtok(NULL, delim); count++; } // 无论是否有有效token,都确保数组末尾为NULL(符合exec系列函数参数要求) eachstr[count] = NULL; return eachstr; }
修复main函数的空指针检查
int main(void) { unsigned int status = 1; char *userinput = NULL; // 让getline自动分配内存,避免手动分配的冲突 size_t r = 0; char **args; while (status) { _print("($) "); get_cmd(&userinput, &r); // 修改get_cmd接收r的指针,适配getline的内存管理 args = split_str(userinput); // 先检查args[0]是否为NULL,再执行后续逻辑 if (args[0] != NULL && _strcmp(args[0], "exit") == 0) { status = 0; } // 空白行(args[0]为NULL)时跳过execute,直接循环打印提示符 if (args[0] != NULL) { execute(args); } free(args); } free(userinput); return (0); }
同步修改get_cmd函数
void get_cmd(char **userinput, size_t *r) { getline(userinput, r, stdin); }
修复逻辑说明
- 空指针防护:在
main里先判断args[0]是否为NULL,如果是(空白行),就跳过strcmp和execute,直接重新打印提示符,彻底避免空指针访问。 - 内存分配修正:给
char**类型的数组分配正确的指针大小内存,解决潜在的越界写入问题。 getline优化:把userinput初始化为NULL,让getline自动管理内存,避免手动分配的内存和getline的重分配机制冲突。
这样修改后,输入空白行按回车就会正常重新显示($)提示符,命令执行功能也完全不受影响啦!
内容的提问来源于stack exchange,提问作者tony baidoo
相关产品推荐
相关产品推荐

