数组元素替换后末尾重复,设置NULL触发Segmentation Fault求助
问题描述
我写的程序会将数组中的某个值替换为下一个值,但最终数组的最后两个值出现重复。尝试直接将最后一个值设为array[i-1] = NULL;(i为数组大小)时触发了Segmentation Fault。
当前程序输出:
found it again Array value 0: cat: Array value 1: file1.txt: Array value 2: output.txt: Array value 3: output.txt: Array value 4: (null): Array value 5: (null): This is the first line in file1.txt This is the last line
设置array[i-1] = NULL;后的错误输出:
found it again Array value 0: cat: Array value 1: file1.txt: Array value 2: output.txt: Array value 3: (null): Array value 4: (null): Array value 5: (null):
完整代码:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> #include <fcntl.h> #include <string.h> #define BUFFERSIZE 1024 int main(int argc, char* argv[]) { int fd_out = dup(STDOUT_FILENO); int fd_in = dup(STDIN_FILENO); argc++; char buf[BUFFERSIZE]; int n; printf("Please enter commands: \n"); while ((n = read(STDIN_FILENO, buf, BUFFERSIZE)) > 0) { buf[n] = 0; buf[strlen(buf)-1] = '\0'; int i = 0; char* array[10]; char* token1 = strtok(buf, " "); while ((token1 != NULL)) { array[i++] = token1; token1 = strtok(NULL, " "); }//while array[i] = NULL; if (strcmp(buf, "exit") == 0) { break; }//if for (int j = 0; j < i; j++) { if (!strcmp(array[j], ">")) { char* filename_out = array[j+1]; printf("STDOUT redirected\n"); printf("found it\n"); int file_out = open(filename_out, O_WRONLY | O_CREAT, 0777); int file2_out = dup2(file_out, 1); for(int k = j; k < i-1; k++) { array[k] = array[k + 1]; }//if array[i] = NULL; printf("found it again\n"); if ((file_out | file2_out) == -1) { return 1; }//if //array[i-1] = NULL; // for (int j = 0; j < i+2; j++) // { // printf("Array value %d: %s:\n", j, array[j]); // }//for*/ }//if if (!strcmp(array[j], "<")) { char* filename_in = array[j+1]; printf("STDIN_FILENO redirected\n"); int file_in = open(filename_in, O_WRONLY | O_CREAT, 0777); int file2_in = dup2(file_in, 0); for(int l = j; l < i - 1; l++) { array[l] = array[l + 1]; }//for if ((file_in | file2_in) == -1) { return 1; }//if } }//for for (int i = 1; i < argc; i++) { pid_t pid; if (argc >= 1) { if ((pid = fork()) < 0) { perror("fork"); }//if else if (pid == 0) { // child process if (execvp(array[0], array) == -1) { perror("execvp"); return EXIT_FAILURE; } // if }//else if else { // parent process int status; wait(&status); //int again_out = dup2(fd_out, 1); //int again_in = dup2(fd_in, 0); if ((again_out | again_in) == -1) { return 1; } printf("Please enter commands again: \n"); }//else }//if else { fprintf(stderr, "Please specify the name of the program to exec as a command line argument\n"); return EXIT_FAILURE; }//if }//for }//while if (n == -1) perror("read"); }//main
问题分析与解决
核心问题
- 重定向参数处理错误:当前移位逻辑仅把
>替换成后续文件名,未将>和文件名从数组中移除,导致execvp误把文件名当命令参数,同时数组末尾出现重复值。 - 数组计数未更新:处理重定向后未调整有效元素个数
i,后续操作访问超出有效范围的数组元素,触发段错误。 - 文件操作参数错误:输入重定向
<使用O_WRONLY | O_CREAT(写权限),读文件应使用O_RDONLY。 - 错误判断逻辑有误:用
(file_out | file2_out) == -1检测open/dup2失败无效,按位或无法正确识别单个调用失败。 - 文件描述符恢复未生效:
again_out和again_in被注释且未定义,重定向后无法恢复标准输出/输入。
修复步骤
1. 正确移除重定向参数
处理>或<时,将符号和文件名从数组中完全移除,更新数组计数i:
// 处理>的情况 if (!strcmp(array[j], ">")) { char* filename_out = array[j+1]; printf("STDOUT redirected\n"); printf("found it\n"); // 添加O_TRUNC覆盖文件,权限用0666更合理 int file_out = open(filename_out, O_WRONLY | O_CREAT | O_TRUNC, 0666); int file2_out = dup2(file_out, 1); // 将j之后的元素往前移2位,跳过>和文件名 for(int k = j; k < i-2; k++) { array[k] = array[k + 2]; } i -= 2; // 有效元素个数减少2 array[i] = NULL; // 正确终止数组,符合execvp要求 printf("found it again\n"); // 分别判断open和dup2是否失败 if (file_out == -1 || file2_out == -1) { perror("open/dup2 failed"); return 1; } // 只打印有效元素 for (int idx = 0; idx <= i; idx++) { printf("Array value %d: %s:\n", idx, array[idx]); } }
2. 修复输入重定向参数
// 处理<的情况 if (!strcmp(array[j], "<")) { char* filename_in = array[j+1]; printf("STDIN_FILENO redirected\n"); // 读文件用O_RDONLY int file_in = open(filename_in, O_RDONLY); int file2_in = dup2(file_in, 0); for(int l = j; l < i - 2; l++) { array[l] = array[l + 2]; } i -= 2; array[i] = NULL; if (file_in == -1 || file2_in == -1) { perror("open/dup2 failed"); return 1; } }
3. 恢复标准文件描述符
取消注释并定义again_out和again_in:
else { // parent process int status; wait(&status); int again_out = dup2(fd_out, 1); int again_in = dup2(fd_in, 0); if (again_out == -1 || again_in == -1) { perror("dup2 restore failed"); return 1; } printf("Please enter commands again: \n"); }
4. 避免数组越界
移除或修改越界的打印循环,确保仅访问数组有效元素范围。
段错误原因
处理重定向后未更新i的值,原i仍包含>和文件名的元素个数,此时i-1可能指向数组无效区域甚至超出数组长度(array长度为10),导致非法内存访问,触发Segmentation Fault。
内容的提问来源于stack exchange,提问作者sgrandom
相关产品推荐
相关产品推荐

