使用 strcmp 和 char *arr[] 的分段错误

Segmentation fault using strcmp and char *arr[]

我正在努力创建一个 shell,但我已经有一段时间没有使用 C 语言了。我有 shell 正确初始化,但是当我尝试将用户输入与字符串数组进行比较时,我遇到了分段错误。我计划在 for 循环中添加 casce 语句,以便在用户调用它们后启动每个进程。我没有包括那些,因为我一直在试图弄清楚如何让用户输入与我的字符串数组中的值匹配。在调试下,我只收到了 builtins[j] 值的第一个字符,因为它是一个正确的指针。但是我被卡住了,可以使用一些想法来解释为什么当我输入 "exit" 时它不返回 0。谢谢

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

//This code is for creating a basic shell
void init_shell(int num, char *prompt[]){
    char s1[] = "-p"; 
    int result;
    if(num>1){
    result = strcmp(s1, prompt[1]);
        if(result==0){
            printf("%s>$", prompt[2]);

        }else{
        printf("308sh>$");
        }
    }
    //printf("%s\n %s\n %s\n %d\n", prompt[0], prompt[1], prompt[2], result);
    else{
        printf("308sh>$");
    }

}

//接受用户输入的无限循环直到关闭

int main(int argc, char *argv[]){


    const char *builtins[7];    
    builtins[0] = "exit\n";
    builtins[1] = "pid\n";
    builtins[2] = "ppid\n";
    builtins[3] = "cd\n";
    builtins[4] = "pwd\n";
    builtins[5] = "set\n";
    builtins[6] = "get\n";

    char usr_in[]="";
    char cmp[]="";
    while(1==1){
        init_shell(argc, argv);//intial prompt for the shell
        fgets(usr_in,100,stdin); 

    //Check for builtin Commands

        int cmds_size = 7;
        int j=0;
        int res;

        for(j; j<cmds_size; j++){

            res=strcmp(usr_in, hold);
            if(res==0){

            printf("Execucting\n");
            }
            else{
                printf("no command\n");
            }
        }

    }

    return(0);
}

这里的问题是您正在将用户的输入写入缓冲区,该缓冲区不够大,无法容纳空终止符以外的任何内容。

char user_in[] = "";

上面这行告诉 C 编译器你只需要 space 来存储 [ '[=13=]' ],这是一个单字节。 C 编译器不知道您稍后可能会向该缓冲区写入一个 100 字节的字符串。

当您写入缓冲区时,用户的输入会溢出并将覆盖堆栈中的其他值。由于堆栈中的其他值是指针,因此您将 运行 陷入段错误,因为您将字符值写入这些字节,但将它们解释为字符指针。

您正确地将允许的用户输入大小限制为 100 个字符,但您应确保缓冲区足够大以容纳您正在读取的值:

char user_in[101];
for(int i = 0; i < sizeof(user_in) / sizeof(user_in[0]); i++) {
  user_in[i] = 0; // Since this is allocated on the stack *in main*, this
                  // shouldn't be necessary
}

下面是一个如何重写 main 方法的例子:

#include <stdio.h>
#include <string.h>

typedef enum { false, true } bool; // If you don't have this
                                   // defined already

int main(int argc, char *argv[]) {

  const char *builtins[7];    
  builtins[0] = "exit\n";
  builtins[1] = "pid\n";
  builtins[2] = "ppid\n";
  builtins[3] = "cd\n";
  builtins[4] = "pwd\n";
  builtins[5] = "set\n";
  builtins[6] = "get\n";

  char user_in[101];
  for(int i = 0; i < sizeof(user_in) / sizeof(user_in[0]); i++) {
    user_in[i] = 0;
  }

  while(1) {
    printf("Enter a command: ");
    fgets(user_in, 100, stdin);

    bool found = false;
    for(int i = 0; i < sizeof(builtins) / sizeof(builtins[0]); i++) {
      if (!strcmp(user_in, builtins[i])) {
        printf("Found command %s", builtins[i]);
        found = true;
        break;
      }
    }

    if (!found) {
      printf("Didn't find command\n");
    }
  }

  return 0;
}

此外,关于您的函数 init_shell:您正在检查 argc 是否大于 1,但这只能保证定义了 argv[1];它不保证 argv[2] 已定义。 (记住,argc 是 argv 数组的大小,其中第一个元素是正在执行的程序的名称)。在按照您的方式检查提示标志之前,您要确保 argc 至少为 3。

对于您的用例来说,这可能有点矫枉过正,但请考虑使用 getopt 函数从用户那里获取自定义提示值。有关该方法的文档,请参阅 http://man7.org/linux/man-pages/man3/getopt.3.html