首页 > 解决方案 > C中的链表给出分段错误

问题描述

我一直致力于在 C for linux 中实现命令行提示符。基本上它使用系统调用执行命令。到目前为止所有这些都有效,但下一部分是实现历史命令,所以我通常会使用链表命令。

我得到了链表的概念,我知道它们,但我对 C 毫无希望。我似乎无法将我的小豌豆大脑包裹在它周围。所以每个节点结构都将包含命令(这是一个字符串数组),然后是指向下一个节点的指针。

我哪里错了?

节点结构定义

struct Node {
    char** storedCommand;
    struct Node* next;
};

全球主管定义

struct Node* head = NULL;

其余方法

struct Node* createNode(char** command) {
    struct Node* returnNode = malloc(sizeof(struct Node));
    returnNode->storedCommand = command;
    returnNode->next = NULL;
    return returnNode;
}

void addNode(char** command) {
    struct Node* tempNode = createNode(command);

    if(head == NULL) {
        head = malloc(sizeof(struct Node));
        head = tempNode;
    } else {
        struct Node* pointerNode = head;

        while(pointerNode->next != NULL) {
            pointerNode = pointerNode->next;
        }

        pointerNode->next = tempNode;
    }
}

void traverseList() {
    struct Node* p = (struct Node*)malloc(sizeof(struct Node));
    p = head;
    printf("%s", head->storedCommand[0]); // This line fails but why; I thought I have already defined head
    while(p != NULL) {
        printf("%s", p->storedCommand[0]);
        p = p->next;
    }
}

所以我在错误的地方发表了评论,但我真的不知道为什么。

这是我的主要

int main() {

    while(TRUE) {
        printPrompt();
        cmdLine = readCommandLine();
        cmd = parseCommandLine(cmdLine);

        if(strcmp(cmd[0], "history") != 0) {
            addNode(cmd);
        }

        if(isInternalCommand(cmd)) {
            executeInternalCommand(cmd);
        } else {
            pid = fork();

            if(pid == 0) {
                executeCommand(cmd);
            } else if(pid > 0){
                child = waitpid(pid, &status, 0);
            } else {
                printf("There was an error\n");
            }
        }

        free(cmdLine);
        int walk = 0;
        while(cmd[walk] != NULL) {
            free(cmd[walk]);
            walk++;
        }
        free(cmd);
    }

    return 0;

}

这就是所谓的 traverselist 函数

/**
 * Executes the given internal command; Nothing is returned since this is all executed on the address space
 * @param cmd The command to be executed
 */
void executeInternalCommand(char** cmd) {
    if(strcmp(cmd[0], "exit") == 0) {
        exit(0);
    } else if(strcmp(cmd[0], "cd") == 0) {
        if(cmd[1] != NULL) {
            chdir(cmd[1]);
        }
    } else if(strcmp(cmd[0], "echo") == 0) {
        int temp_index = 1;
        while(cmd[temp_index] != NULL) {
            if(cmd[temp_index + 1] != NULL) {
                snprintf(message, WRITE_BUFFER, "%s ", cmd[temp_index]);
                write(STDOUT_FILENO, message, strlen(message));
            } else if(cmd[temp_index] != NULL && cmd[temp_index + 1] == NULL) {
                snprintf(message, WRITE_BUFFER, "%s\n", cmd[temp_index]);
                write(STDOUT_FILENO, message, strlen(message));
            } else {
                snprintf(message, WRITE_BUFFER, "\n");
                write(STDOUT_FILENO, message, strlen(message));
            }
            temp_index++;
        }
    } else if(strcmp(cmd[0], "help") == 0) {
        if(cmd[1] == NULL) {
            snprintf(message, WRITE_BUFFER, "GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)\n");
            write(STDOUT_FILENO, message, strlen(message));
            snprintf(message, WRITE_BUFFER, "These shell commands are defined internally. 'Type help' to see this list.\n");
            write(STDOUT_FILENO, message, strlen(message));
            snprintf(message, WRITE_BUFFER, "Type 'help name' to find out more about the function 'name'.\n\n");
            write(STDOUT_FILENO, message, strlen(message));
            snprintf(message, WRITE_BUFFER, "%-30s %-30s\n", "cd [File Path]", "help name");
            write(STDOUT_FILENO, message, strlen(message));
            snprintf(message, WRITE_BUFFER, "%-30s %-30s\n", "echo [Text]", "exit");
            write(STDOUT_FILENO, message, strlen(message));
        } else {
            if(strcmp(cmd[1], "exit") == 0) {
                snprintf(message, WRITE_BUFFER, "exit\nExits the program with status code 0\n");
                write(STDOUT_FILENO, message, strlen(message));
            } else if(strcmp(cmd[1], "cd") == 0) {
                snprintf(message, WRITE_BUFFER, "cd [File Path]\nChange the current directory. Accepts argument 'File Path' to change the present working directory to the 'File Path'\n");
                write(STDOUT_FILENO, message, strlen(message));
            } else if(strcmp(cmd[1], "echo") == 0) {
                snprintf(message, WRITE_BUFFER, "echo [Text]\nPrints [Text] to the screen\n");
                write(STDOUT_FILENO, message, strlen(message));
            } else {
                snprintf(message, WRITE_BUFFER, "The help page for this command is currently not supported\n");
                write(STDOUT_FILENO, message, strlen(message));
            }
        }
    } else if(*cmd[0] == '!') {
        printf("Banger!!!!\n");
    } else if(strcmp(cmd[0], "history") == 0) {
        printf("History command\n");
        traverseList();
    }
}

编辑:我犯了一个非常新手的错误。在我的addNode函数中,我在那里为我的returnNodeAND 返回它分配了空间。因此,当我从函数返回一个局部变量并尝试在方法范围之外使用它时,我显然会弄乱内存引用。只是一个大的菜鸟错误弄乱了范围。

标签: clinked-listsegmentation-fault

解决方案


这不是您崩溃的根本原因,但这是一个错误。您在addnode函数中泄漏了一个对象:

void addNode(char** command) {
    struct Node* tempNode = createNode(command);

    if(head == NULL) {
        head = malloc(sizeof(struct Node));
        head = tempNode;
    }

应该:

    if(head == NULL) {
        head = tempNode;
    }

推荐阅读