【问题标题】:Segmentation Fault - strcpy() - C分段错误 - strcpy() - C
【发布时间】:2013-02-23 12:37:59
【问题描述】:

我正在为命令行 shell 实现历史功能。我已经实现了一个循环数组来保存十个最近的命令。每个命令也由一个整数标记,指定哪个总命令是。例如,如果总共输入了 30 个命令,则循环数组中的 10 个命令将编号为(30、29、28、27、...、21)。

如果用户要插入命令“r”,后跟一个标记十条指令之一的数字,则该指令应该运行。在尝试确保正确接受两个字命令时,我一直遇到段错误。谁能帮忙指出问题所在。

int main(void)
{
    char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
    int background;             /* equals 1 if a command is followed by '&' */
    char *args[MAX_LINE/2+1];/* command line (of 80) has max of 40 arguments */

    int position, count, rnum = 0;
    char historyArray[10][MAX_LINE];
    char *holder[MAX_LINE]={0};

    while (1){            /* Program terminates normally inside setup */
        background = 0;
        printf("COMMAND->");
        fflush(0);

        setup(inputBuffer, args, &background);       /* get next command */

        position = (count % MOD_VAL);
        strcpy(historyArray[position],args[0]);

        if(!strcmp("rr",args[0]))
        {
            strcpy(historyArray[position],historyArray[((position-1)+MOD_VAL)%MOD_VAL]);
            printf("%i",count);
            printf("%c",'.');
            printf("%c",' ');
            printf("%s",historyArray[position]);
            printf("%c",'\n');
            strcpy(args[0],historyArray[position]);
        }

        else if(!strcmp("r",args[0])) //SEG FAULT OCCURING IN THIS ELSE-IF BLOCK!
        {
            //args[1] will hold given number
            printf("%c",'\n');
            printf("%s",args[0]);
            printf("%s",args[1]);
            printf("%s",args[2]);
            printf("%c",'\n'); //PRINT STATEMENTS FOR DEBUGGING

            strncpy(holder[0], args[2], MAX_LINE - 1); //SEG FAULT

            rnum = atoi(args[1]);
            strcpy(historyArray[position],historyArray[((position-(count-rnum))+MOD_VAL)%MOD_VAL]);
            strcpy(args[0],historyArray[position]); //CHANGES VALUES OF args[1], args[2]

            if(holder[0] != NULL)
            {
                strncpy(args[1],holder[0],MAX_LINE-1);
                args[2] = NULL;
            }
            else
            {
                args[1] = NULL;
            }

            printf("%c",'\n');
            printf("%s",args[0]);
            printf("%s",args[1]);
            printf("%s",args[2]);
            printf("%c",'\n');
        }

        else if(!(strcmp("h",args[0]))||!(strcmp("history",args[0])))
        {
            int counter = 0;
            while(counter < 10)
            {
                printf("%i",(count - counter));
                printf("%c",'.');
                printf("%c",' ');
                printf("%s", historyArray[((position - counter + MOD_VAL)%MOD_VAL)]);
                printf("%c",' ');
                printf("%c",'\n');
                counter ++;

                if(counter > count)
                    break;
            }
        }
        count++;

        pid_t pid1; //Initialize pid_t variable to hold process identifier
        pid1 = fork(); //Fork process and assign process identifier to "pid1"

        if (pid1 == 0) //Child process
        {
            //Child process executes the command specified by the user and
            //then quits.
            execvp(args[0], args);
            exit(0);
        }
        else //Parent process
        {
            if (background != 1)//Check for inclusion of '&' in command 
            {
                wait(NULL); //Wait for child process to finish executing
            }
        } 

        /* the steps are:
         (1) fork a child process using fork()
         (2) the child process will invoke execvp()
         (3) if background == 0, the parent will wait, 
         otherwise returns to the setup() function. */
    }
}

感谢任何帮助!

-亚光

【问题讨论】:

  • 马特,你能修复缩进吗?此外,代码以 else if 开头,这没有多大意义。
  • 实现对所有单字命令 (ls) 都有效。试图确保它对输入命令(例如 mkdir dirname)有效。用户输入:r 1 目录名;其中 r = args[0],1=args[1],dirname=args[2]。需要 dirname 在 else-if 案例末尾的 args[1] 中!
  • 抱歉,代码有点长,我不确定是否可以接受全文发布。
  • 使用调试器找出崩溃的地方。然后重新运行监视该变量。
  • @MattKoz - 缩小问题范围并发布一个小型自包含示例来演示该问题。

标签: c segmentation-fault strcpy


【解决方案1】:

你注意到崩溃发生就行了

else if(!strcmp("r",args[0]))

如果我是你,我会在调试器中加载核心文件,并查看传递给 strcmp()args[0] 的值是什么。

我希望您收到关于 charchar* 之间类型不匹配的编译器警告。您将 args 声明为 char*。这意味着args[0]char,而不是char*。要比较单个字符,只需使用字符而不是strcmp()

else if ('r' != args[0])

关于 C 字符串处理的一些注意事项:

  • strcmp() 当其参数未正确以 NUL 终止时,对于数组边界是不安全的
    • 使用strncmp() 限制比较的字符数
  • 虽然strncpy() 防范数组边界,但它不能保证以 NUL 结尾的目标字符串
  • strcpy() 不尊重数组边界;您有责任确保目标数组足够大以接收复制到其中的字符串

【讨论】:

  • 在 else-if 块内发生分段错误。我相信实际的段错误发生在这一行:strncpy(holder[0], args[2], MAX_LINE - 1);谢谢你的提示!
  • "... 您将 args 声明为 char*。这意味着 args[0] 是 char,而不是 char* ..." 至少从 OP 的当前版本来看,这是错误的。 args 被声明为(char*)[],这导致args[0] 成为char *,这完全可以传递给strcmp()。事实上('r' != args[0]) 会导致编译器发出“类型不匹配”警告。
  • 正确 - 我的错误。我错过了变量名之后的额外数组维度。我喜欢 Java 的语法,将数组括号放在类型而不是变量上:)。
【解决方案2】:

这里的 args 是字符指针数组。

但是strcpy 需要两个参数——应该是arraycharacter pointer to which memory allocated by malloc

但是您的strcpy(historyArray[position],args[0]); 将一个参数作为character pointer 将不被接受。

因此您可以将args[] 更改为args[][]args[0] = malloc(some_no)segfault 将被删除。

【讨论】:

  • 没有像args[] 这样的声明。并且args[][] 不会为有问题的指针分配任何内存,甚至不会编译。
【解决方案3】:

您在分配内存时缺少argsholder 中保存的char 指针。

因此,通过str*() 系列函数将它们称为指向以 0 结尾的字符数组(“字符串”)的指针会导致未定义的行为,因为 str*() 函数试图取消引用那些不指向有效内存的指针.

【讨论】:

    猜你喜欢
    • 2014-10-21
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-15
    • 1970-01-01
    • 1970-01-01
    • 2020-10-05
    相关资源
    最近更新 更多