c - 我的 minishell 程序收到段错误

标签 c pointers segmentation-fault

我正在编写一个迷你 shell 程序。它给了我“args = my_str2vect(line);”行中的段错误。不过,“my_str2vect”函数以及 my_strncpy 函数和 my_strlen 函数(返回 char 数组的长度)都可以正常工作。那么这条线有什么问题呢?

#define _POSIX_SOURCE
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>  
#include <signal.h>
#include "../../include/my.h"




pid_t pid;
int childrunning = 0;
void minishell_loop();

/*
  Your shell must also support CTRL+C by using UNIX signals. 
  If you type CTRL+C your prompt must not exit 
  and instead kill the currently running process (or do nothing if there is none).
*/

void int_handler(int sig){
  if(childrunning == 1){
    kill(pid, SIGUSR2);
  }else{
    my_str("\n");
    minishell_loop();
  }
}

void killkillkill(int sig){
    exit(0);
}
/*
  Function Declarations for builtin shell commands:
 */
int minishell_cd(char **args);
int minishell_help(char **args);
int minishell_exit(char **args);

/*
  List of builtin commands, followed by their corresponding functions.
 */
char *builtin_str[] = {
  "cd",
  "help",
  "exit"
};

int (*builtin_func[]) (char **) = {
  &minishell_cd,
  &minishell_help,
  &minishell_exit
};

int minishell_mum_bultins() {
  return sizeof(builtin_str) / sizeof(char *);
}

/*
  Builtin function implementations.
*/

/**
   @brief Bultin command: change directory.
   @param args List of args.  args[0] is "cd".  args[1] is the directory.
   @return Always returns 1, to continue executing.
 */
int minishell_cd(char **args)
{
  if (args[1] == NULL) {
    fprintf(stderr, "minishell: expected argument to \"cd\"\n");
  } else {
    if (chdir(args[1]) != 0) {
      perror("minishell");
    }
  }
  return 1;
}

/**
   @brief Builtin command: print help.
   @param args List of args.  Not examined.
   @return Always returns 1, to continue executing.
 */
int minishell_help(char **args)
{
  int i;
  printf("Tianwei's minishell, version 1.01\n");
  printf("These shell commands are defined internally.\n");

  for (i = 0; i < minishell_mum_bultins(); i++) {
    printf("  %s\n", builtin_str[i]);
  }
  return 1;
}

/**
   @brief Builtin command: exit.
   @param args List of args.  Not examined.
   @return Always returns 0, to terminate execution.
 */
int minishell_exit(char **args)
{
  return 0;
}


/**
  @brief Launch a program and wait for it to terminate.
  @param args Null terminated list of arguments (including program).
  @return Always returns 1, to continue execution.
 */
int minishell_launch(char **args)
{
  signal(SIGUSR2, killkillkill);
  int status;

  pid = fork();
  if (pid == 0) {
    // Child process
    childrunning = 1;
    if (execvp(args[0], args) == -1) {
      perror("minishell");
    }
    exit(EXIT_FAILURE);
  } else if (pid < 0) {
    // Error forking
    perror("minishell");
  } else {
    // Parent process
    do {
      waitpid(pid, &status, WUNTRACED);
    } while (!WIFEXITED(status) && !WIFSIGNALED(status));
  }

  return 1;
}

/**
   @brief Execute shell built-in or launch program.
   @param args Null terminated list of arguments.
   @return 1 if the shell should continue running, 0 if it should terminate
 */
int minishell_execute(char **args)
{
  int i;
  my_str(args[0]);
  if (args[0] == NULL) {
    my_str("args[0] is NULL\n");
    // An empty command was entered.
    return 1;
  }
  for (i = 0; i < minishell_mum_bultins(); i++) {
    if (strcmp(args[0], builtin_str[i]) == 0) {
        my_str("1\n");
      return (*builtin_func[i])(args);
    }
  }
  my_str("0\n");
  return minishell_launch(args);
}

#define MINISHELL_RL_BUFSIZE 1024
/**
   @brief Read a line of input from stdin.
   @return The line from stdin.
 */
char *minishell_readln(void)
{
  int bufsize = MINISHELL_RL_BUFSIZE;
  int position = 0;
  char* buffer = malloc(1024 * sizeof(char));
  int c;

  while (1) {
    // Read a character
    c = getchar();

    // If we hit EOF, replace it with a null character and return.
    if (c == EOF || c == '\n') {
      buffer[position] = '\0';
      return buffer;
    } else {
      buffer[position] = c;
    }
    position++;

    // If we have exceeded the buffer, reallocate.
    if (position >= bufsize) {
      fprintf(stderr, "minishell: Command line too long!\n");
      exit(EXIT_FAILURE);
    }
  }
}


/**
   @brief Loop getting input and executing it.
 */
void minishell_loop(void)
{
  signal(SIGINT, int_handler);
  char* line;
  char** args;
  int status;
  do {
    printf("MINISHELL: /home/tianwei/$ ");
    line = minishell_readln();
    my_str("0\n");
    my_str(line);
    args = my_str2vect(line);
    my_str(args[0]);
    my_str("0\n");
    status = minishell_execute(args);
    my_str("1\n");

    free(line);
    free(*args);
    free(args);
  } while (status);
}

/**
   @brief Main entry point.
   @param argc Argument count.
   @param argv Argument vector.
   @return status code
 */
int main(int argc, char **argv)
{
  // Load config files, if any.
  // Run command loop.
    minishell_loop();

  // Perform any shutdown/cleanup.

  return EXIT_SUCCESS;
}

这是 my_str2vect 函数的代码

#include "../../include/my.h"

char** my_str2vect(char* str){
 // Takes a string 
 // Allocates a new vector (array of string ended by a NULL), 
 // Splits apart the input string x at each space character 
 // Returns the newly allocated array of strings
 // Any number of ' ','\t', and '\n's can separate words.
 // I.e. "hello \t\t\n class,\nhow are you?" -> {"hello", "class,", "how", "are","you?", NULL}
    int max_num_words = 0;
    int a = 0;
    int b = 0;
    int max_num_char = 0;
    while(str[a] != '\0'){ // find the number of words and the length of the longest word
        if(str[a] != ' ' && str[a] != '\t' && str[a] != '\n'){
            ++max_num_words;
            ++a;
            ++b;
            while((str[a] != ' ' && str[a] != '\t' && str[a] != '\n') && str[a] != '\0'){
                ++a;
                ++b;
            }
            if(b > max_num_char){
                max_num_char = b;
            }
            b = 0;
            while((str[a] == ' ' || str[a] == '\t' || str[a] == '\n') && str[a] != '\0'){
                ++a;
            }   
        }
    }
    char** output = (char **)malloc(sizeof(char *) * (max_num_words + 1)); // Allocate a 2D array first.
    for(int c = 0; c < max_num_words + 1; ++c){
        output[c] = (char *)malloc(sizeof(char) * (max_num_char + 1));
    }
    int i = 0;
    int j = 0;
    while(i < my_strlen(str) && j < max_num_words){ // Put the characters into the 2D array.
        int k = 0;
        while(i < my_strlen(str) && (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')){
            ++i;
        }
        while(i < my_strlen(str) && (!(str[i] == ' ' || str[i] == '\t' || str[i] == '\n'))){
            ++i;
            ++k;
        }
        if(i-k < my_strlen(str) && j < max_num_words){
            my_strncpy(output[j], &str[i-k], k);
        }
        ++j;
    }
    output[j] = NULL;
    return output;
}

这是 my_strncpy 函数

#include "../../include/my.h"


char *my_strncpy(char *dst, char *src, int n)
{
    /* Same as my_strcpy except:
     *  Only copies n chars or until the end of src*/

    if(src != NULL && dst != NULL){
        int i = 0;
        while(i < n && src[i] != '\0'){
            dst[i] = src[i];
            ++i;
        }
        dst[i] = '\0';
    }
    return dst;
}

最佳答案

我没有尝试执行您的代码,但是 my_str2vect 函数中的第一眼给我留下了深刻的印象:

  • 在第一个 while 循环中,a 仅在 if 中递增。如果您的行以空格开头,您可能会遇到永远循环
  • 在第二个 while 循环中,您不会检查字符串 '\0' 的结尾。这很可能是您崩溃的原因,但也可能有其他原因。

PS:既然你正在解析字符串,你应该看看 strtoksscanf,它们会让你的生活更轻松

关于c - 我的 minishell 程序收到段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41031008/

相关文章:

c - 从 GtkListStore 检索数据

c++ - 继承和指向 protected 成员的指针

c - gdb:程序退出,代码为 030000000375

mySQL 和 C 的麻烦

c - 让我的局域网中的主机监听特定端口

c - C 中的二维数组和指针 - 如何访问元素?

c - C如何保护指针内存?

opencv - 像素处理中的段错误(核心已转储)

c - 使用 char 指针退出函数后出现段错误

c - 在C中离开for循环后丢失结构数组中的值