C语言自制迷你shell execvp执行报错问题如何修复
迷你Shell代码问题排查与修复方案
核心问题列表
- 野指针访问:
username仅声明为字符指针未分配内存,scanf直接向非法地址写入数据,会触发段错误。 - 输入缓冲区残留换行:
scanf读取用户名后,用户输入的换行符残留在标准输入缓冲区,第一次执行fgets会直接读到空字符串,导致首次命令执行异常。 - 命令携带换行符:
fgets会将用户输入的换行符一并存入命令数组,分词后命令/参数末尾会携带\n字符,execvp无法匹配到对应可执行文件。 - 数组越界风险:
argv数组仅定义了3个元素的空间,当命令参数超过2个时会触发数组越界,内存被篡改导致execvp执行失败。 - 分词规则不全:仅以空格作为分词分隔符,无法处理制表符、换行等其他空白字符的分割场景。
修复步骤
- 将
username改为定长字符数组,分配足够的存储空间避免野指针:char username[256]; scanf读取用户名后调用getchar(),吃掉缓冲区残留的换行符。fgets读取命令后,手动移除末尾的换行符:comand[strcspn(comand, "\n")] = '\0';- 放大
argv数组长度,改为char *argv[64];,支持最多63个命令参数。 - 调整
strtok的分隔符为" \t\n",兼容多种空白字符分割场景。
修复后完整代码
#include <unistd.h> #include <string.h> #include <sys/wait.h> #include <sys/stat.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #define MAX_LINE 1024 void run_shell(char * cmd){ char * str = cmd; char delims[] = " \t\n"; char * token = strtok(str, delims); char * argv[64]; int i = 0; while(token != NULL){ argv[i] = token; i++; token = strtok(NULL, delims); } argv[i] = NULL; pid_t pid; if((pid = fork()) == 0){ if(execvp(argv[0], argv) < 0){ perror("Invalid Command"); exit(EXIT_FAILURE); } } else{ if(waitpid(pid, NULL, 0) < 0){ perror("Wait Process Error"); exit(EXIT_FAILURE); } } printf("\n"); } int main(){ char comand[MAX_LINE]; char username[256]; printf("Enter your name : "); scanf("%s", username); getchar(); while(1){ char cwd[MAX_LINE]; getcwd(cwd, sizeof(cwd)); printf("%s %s$ > ", username, cwd); fgets(comand, MAX_LINE, stdin); comand[strcspn(comand, "\n")] = '\0'; printf("\n"); run_shell(comand); } }
内容的提问来源于stack exchange,提问作者김정훈
相关产品推荐
相关产品推荐

