请问下面这个代码怎么改正

下面这个代码是实现一个自己的shell中的一段代码,但是运行后发生了段错误,请问应该怎么改正呢


#include "shell.h"
#define TOK_DELIM " "
#define TOK_BUFFER_SIZE 64
#include <malloc.h>

char ** split_line(char *buffer);
int search_command(char **tokens);
int change_directory(char **tokens);
int exit_command(char* buffer);
int display_former_command(node* n);
int find_command_with_prefix(char **tokens);
int list_files();

/**
 * shell的入口
 */
void prefix() {
    char cwd[255];
    getcwd(cwd, sizeof(cwd));
    printf("%s$ ", cwd);
}

int execute(char* buffer) {
    char **tokens = split_line(buffer);
    if(strcmp(tokens[0] , "cd") == 0) {       
        return change_directory(tokens);
    }else if(strcmp(tokens[0] , "exit") == 0) {
        return exit_command(buffer);
    }else if(strcmp(tokens[0] , "!#") == 0) {
        return display_former_command(Log.head);
    }else if(tokens[0][0] == '!' && tokens[0][1] != '#') {
        return find_command_with_prefix(tokens);
    }else if(strcmp(tokens[0] , "ls") == 0) {
        return list_files();
    }else{
        return search_command(tokens);
    }
    free(tokens);
    tokens=NULL;
    return 1;
}

char ** split_line(char *buffer){
    int buffer_size = TOK_BUFFER_SIZE;
    char **tokens = (char **)malloc(buffer_size*sizeof(char *));
    int id = 0;
    char *token = (char *)malloc(buffer_size*sizeof(char));
    token = strtok(buffer, TOK_DELIM);
    for(id=0; token != NULL; id++){
        strcpy(tokens[id], token);
        token = strtok(NULL, TOK_DELIM);
    }
    free(token);
    token = NULL;
    tokens[id]=NULL;
    return tokens;
}

int search_command(char **tokens){  
    char tokens_sh[100]={'\0'};
    if(strcmp(tokens[0], "args") != 0){        
        strcpy(tokens_sh, "./");
    }     
    strcat(tokens_sh, tokens[0]);
    int pid = fork();
    if(pid == 0){  // child process
        if(execvp(tokens_sh, tokens[0]) < 0){
            printf("%s: no such command\n", tokens[0]);
        }
        exit(1);
    }else{
        log_push(&Log, tokens[0]);
        wait(pid);
    }
    return 1;
}

int change_directory(char **tokens){
    char dir[255];
        strcpy(dir, tokens[1]);
        if(chdir(dir)) {
            printf("%s: No such file or directory\n", tokens[1]);
        }
        log_push(&Log,tokens[1]);
    return 1;
}

int exit_command(char* buffer){
    free(buffer);
    return 0;
}

int display_former_command(node* n) {
    if(n==NULL)
        return 1;
    display_former_command(n->next);
    printf("%s\n",n->cmd);
    return 1;
}

int find_command_with_prefix(char **tokens){
    char* search = log_search(&Log, tokens[0]+1);
    if(search != NULL) {
        log_push(&Log, search);
        execute(search);
    } else {
        printf("No Match\n");
    }
    return 1;
}

int list_files(){
    log_push(&Log, "ls");
    system("ls");
    return 1;
}

贴出错误信息啊,是异常还是代码自己给的错误提示?

报错信息 提供一下呦

shell程序要特别注意内存管理,谨慎使用malloc/free,避免频繁的内存分配和释放。适当使用Valgrind等工具帮助检测内存错误。

  • split_line()函数在分割命令行时,没有正确释放内存,造成内存泄漏。
  • execute()函数在执行系统命令时,没有释放split_line()函数分配的内存,也会导致内存泄漏。
  • search_command()函数在使用execvp执行系统命令时,传入的参数tokens[0]不正确,应该传入tokens数组。
// 在split_line()中,释放为token分配的内存
free(token);

// 在execute()结束时,释放tokens内存
free(tokens);

//  在search_command()中,将execvp的参数改为tokens
execvp(tokens_sh, tokens);

错误显示在哪

错误信息和截图发出来,这样看怎么定位?

哪里错误,是啥错误

运行报错说下,再改

在split_line函数中,你没有为tokens[id]分配内存,而是直接使用strcpy函数。这会导致内存访问越界,导致段错误。你应该在循环中为每个tokens[id]分配足够的空间,或者使用strdup函数来复制字符串
看下是不是这个问题

char ** split_line(char *buffer){
    int buffer_size = TOK_BUFFER_SIZE;
    char **tokens = (char **)malloc(buffer_size*sizeof(char *));
    int id = 0;
    char *token = (char *)malloc(buffer_size*sizeof(char));
    token = strtok(buffer, TOK_DELIM);
    for(id=0; token != NULL; id++){
        // 为tokens[id]分配内存
        tokens[id] = (char *)malloc(strlen(token) + 1);
        // 或者使用strdup函数
        // tokens[id] = strdup(token);
        strcpy(tokens[id], token);
        token = strtok(NULL, TOK_DELIM);
    }
    free(token);
    token = NULL;
    tokens[id]=NULL;
    return tokens;
}


把你运行报错得贴出来,不然不好整


Compile error: /storage/emulated/0/Android/data/com.cjkj.clanide/files/CJ_IDE/CProject/CIDEExample/src/Main.c:2:10: fatal error: shell.h: No such file or directory
 #include "shell.h"
          ^~~~~~~~~
compilation terminated.


以上为你的代码的错误信息

你的错误可能是头文件引入的问题,检查下头文件是否能够正确引入并使用。其次,检查下在 split_line 函数的最后,你释放了 token 指针,但是之前分配的 tokens 指针并没有被释放。这里可能也会有问题。

具体报什么错呢,看看报错信息

1.在split_line()函数中,将分割后的子字符串存储到tokens数组时,应该使用动态分配的内存。当前代码中,只是将指针赋值给tokens数组中的元素,这可能导致访问非法内存或者出现未定义的行为。你可以使用malloc()来动态分配内存,然后使用strcpy()将分割后的字符串复制到分配的内存空间中。
2.在search_command()函数中,execvp()函数的第一个参数应该是可执行文件的路径,而不仅仅是命令的名称。当前代码中,将命令名称直接传递给了execvp(),这可能导致找不到命令。你可以构建完整的路径,如./command,然后将其作为execvp()的第一个参数。
3.在exit_command()函数中,释放内存时使用了错误的函数。buffer是通过malloc()动态分配的,应该使用free()来释放,而不是直接使用delete。
4.在display_former_command()函数中,递归调用时,应该先打印出当前节点的命令,然后再递归调用下一个节点,以保证按照倒序显示命令。
5.在execute()函数最后释放tokens的操作,永远不会执行到,因为在之前的分支中都已经return了。所以这行代码实际上是无用的。

采用chatgpt:
在代码中有几个问题需要修正:

1、malloc.h 库已经过时,应该使用 stdlib.h 库来包含 malloc 函数的声明。

2、split_line 函数中,你分配了 tokens 数组来存储分割后的字符串,但是没有为每个元素分配内存空间。在循环中使用 strcpy 函数之前,需要为 tokens[id] 分配内存空间。你可以使用 malloc 函数来为每个元素分配适当的内存空间。

3、在 search_command 函数中,execvp 函数的第二个参数应该传递整个 tokens 数组,而不仅仅是 tokens[0]。修改为 execvp(tokens_sh, tokens)。

4、wait 函数应该传递一个指向整型变量的指针作为参数,而不是进程ID。你可以使用 waitpid 函数来等待子进程结束,如下所示:

waitpid(pid, NULL, 0);

在 execute 函数的末尾,释放 tokens 数组的内存应该放在最后一行的前面。
修改后的代码如下所示:

#include "shell.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define TOK_DELIM " "
#define TOK_BUFFER_SIZE 64

char **split_line(char *buffer);
int search_command(char **tokens);
int change_directory(char **tokens);
int exit_command(char *buffer);
int display_former_command(node *n);
int find_command_with_prefix(char **tokens);
int list_files();

/**
 * shell的入口
 */
void prefix() {
    char cwd[255];
    getcwd(cwd, sizeof(cwd));
    printf("%s$ ", cwd);
}

int execute(char *buffer) {
    char **tokens = split_line(buffer);
    if (strcmp(tokens[0], "cd") == 0) {
        return change_directory(tokens);
    } else if (strcmp(tokens[0], "exit") == 0) {
        return exit_command(buffer);
    } else if (strcmp(tokens[0], "!#") == 0) {
        return display_former_command(Log.head);
    } else if (tokens[0][0] == '!' && tokens[0][1] != '#') {
        return find_command_with_prefix(tokens);
    } else if (strcmp(tokens[0], "ls") == 0) {
        return list_files();
    } else {
        return search_command(tokens);
    }
    free(tokens);
    return 1;
}

char **split_line(char *buffer) {
    int buffer_size = TOK_BUFFER_SIZE;
    char **tokens = (char **)malloc(buffer_size * sizeof(char *));
    int id = 0;
    char *token;
    token = strtok(buffer, TOK_DELIM);
    while (token != NULL) {
        tokens[id] = (char *)malloc(strlen(token) + 1);
        strcpy(tokens[id], token);
        token = strtok(NULL, TOK_DELIM);
        id++;
    }
    tokens[id] = NULL;
    return tokens;
}

int search_command(char **tokens) {
    char tokens_sh[100] = {'\0'};
    if (strcmp(tokens[0], "args") != 0) {
        strcpy(tokens_sh, "./");
    }
    strcat(tokens_sh, tokens[0]);
    int pid = fork();
    if (pid == 0) {  // child process
        if (execvp(tokens_sh, tokens) < 0) {
            printf("%s: no such command\n", tokens[0]);
        }
        exit(1);
    } else {
        log_push(&Log, tokens[0]);
        waitpid(pid, NULL, 0);
    }
    return 1;
}

int change_directory(char **tokens) {
    char dir[255];
    strcpy(dir, tokens[1]);
    if (chdir(dir)) {
        printf("%s: No such file or directory\n", tokens[1]);
    }
    log_push(&Log, tokens[1]);
    return 1;
}

int exit_command(char *buffer) {
    free(buffer);
    return 0;
}

int display_former_command(node *n) {
    if (n == NULL)
        return 1;
    display_former_command(n->next);
    printf("%s\n", n->cmd);
    return 1;
}

int find_command_with_prefix(char **tokens) {
    char *search = log_search(&Log, tokens[0] + 1);
    if (search != NULL) {
        log_push(&Log, search);
        execute(search);
    } else {
        printf("No Match\n");
    }
    return 1;
}

int list_files() {
    log_push(&Log, "ls");
    system("ls");
    return 1;
}

这些修改应该能够解决段错误问题。但请注意,在修改代码之前,最好先确认段错误的原因,并检查其他可能导致问题的因素。