【问题标题】:Bad address error with execvpexecvp 出现错误的地址错误
【发布时间】:2017-07-21 07:51:02
【问题描述】:

我正在尝试制作一个 shell“bosh>”,它接收 Unix 命令并不断收到错误的地址错误。我知道我的代码会读取命令并解析它们,但由于某种原因,我无法让它们执行,而是出现“错误地址”错误。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
#define MAX_LINE 128
#define MAX_ARGS 10



int main(){
    pid_t pid;
    char command[MAX_LINE]; /*command line buffer*/
    char *commandArgs[MAX_ARGS]; /*command line arg*/
    int i;
    char *sPtr=strtok(command," ");
    int n=0;


    printf("bosh>");
    fgets(command, MAX_LINE-1,stdin);
    command[strlen(command)-1]='\0';


    while(strcmp(command,"quit")!=0)
    {
        n=0;

        sPtr=strtok(command," ");
        while(sPtr&&n<MAX_ARGS)
        {
            sPtr=strtok(NULL," ");
            n++;
        }

        commandArgs[0]=malloc(strlen(command)+1);
        strcpy(commandArgs[0],command);

        if(fork()==0)
        {
            execvp(commandArgs[0],commandArgs);
            perror("execvp failed");
            exit(2);
        }
        pid=wait(NULL);


        printf("%s",">" );
        fgets(command, MAX_LINE-1,stdin);
        command[strlen(command)-1]='\0';
    }

    printf("Command (%d) done\n", pid);

    return 0;


}

【问题讨论】:

  • 首先,图片中的狗不错。在fgets 读取的缓冲区中的最后一个字符之后存储一个终止空字节('\0')。所以你不必输入'\0'
  • @TonyTannous 就是去掉换行符...(虽然它也不正确)。
  • 在砍掉它之前,您需要检查最后一个字符是否确实是 '\n'
  • 我不确定,但我认为您将参数放入 commandArgs 的方式存在问题。您只存储第一个参数。最后一个参数必须为 NULL。

标签: c shell unix operating-system execvp


【解决方案1】:

这两行是罪魁祸首:

commandArgs[0]=malloc(strlen(command)+1);
strcpy(commandArgs[0],command);

首先,malloc(strlen(...)) 后跟 strcpy 是 POSIX 函数 strdup 已经做的事情。但是,您甚至不需要复制字符串 - 只需将指向原始字符串的指针存储到 commandArgs[0] 中就足够了:

commandArgs[0] = command;

但是,execvp 命令将采用多少个参数?如果你仔细阅读手册,他们会说:

execv()execvp()execvpe() 函数提供了一个指向以 null 结尾的字符串的指针数组,这些字符串表示新程序可用的参数列表。按照惯例,第一个参数应该指向与正在执行的文件关联的文件名。 指针数组必须以 NULL 指针终止。

您的参数数组不是以 NULL 结尾的。要修复它,请使用

commandArgs[0] = command;
commandArgs[1] = NULL; // !!!!

(然后你会注意到你实际上想要在strtok解析循环中分配参数within,这样你就可以将所有参数分配到commandArgs数组中; 并在启用所有警告的情况下编译并解决这些问题,等等)。

【讨论】:

    【解决方案2】:

    您在其声明中初始化sPtr,您不需要这样做,因为您从不使用初始值。但是初始化会产生未定义的行为,因为它依赖于 command 数组的内容,此时该数组是不确定的。

    作为第二个参数传递给execvp() 的数组应该在最后一个参数之后包含一个空指针。你不能保证你的。

    此外,由于未能将令牌分配给commandArgs[],您似乎放弃了输入命令的所有参数。标记化后,您确实复制了第一个标记(仅)并将副本分配给commandArgs 的第一个元素,但任何其他标记都将被忽略。

    【讨论】:

    • 我已经在 cmets 中指出了这一点。参数初始化有问题。只有第一个参数可能被分配,并且在最后一个参数之后没有 NULL。 +1
    猜你喜欢
    • 2013-12-25
    • 2019-06-12
    • 1970-01-01
    • 1970-01-01
    • 2021-10-09
    • 1970-01-01
    • 2016-01-19
    • 2011-01-12
    • 2010-09-08
    相关资源
    最近更新 更多