【问题标题】:Linked List in C gives Segmentation FaultC中的链表给出分段错误
【发布时间】:2021-07-10 02:10:32
【问题描述】:

我一直致力于在 C 中为 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 函数中,我为returnNode 分配了空间并返回。因此,当我从函数返回一个局部变量并尝试在方法范围之外使用它时,我显然会弄乱内存引用。只是一个大的菜鸟错误搞砸了范围。

【问题讨论】:

  • 你的main 是什么minimal reproducible example?你试过在调试器中运行它吗?
  • 为了简短起见,我省略了所有其他不适用于该问题的方法。我试图给调试器一个机会,但我真的很难为 C 弄清楚它
  • 您的main 函数甚至不会调用您的链表代码。你想让我们调试什么?
  • 当输入的命令不是历史时调用addNode。我更新为包含一个在调用 history 命令时相关的函数
  • 如果你有一个全局的struct Node* head; 你也可以有一个全局的struct Node* tail; 来允许O(1) 的顺序插入。在add() 中,它只是变成if(head == NULL) { ... head = tail = tempNode;,然后else 部分是tail->next = tempNode; tail = tempNode; 句点——没有迭代。请提供A Minimal, Complete, and Verifiable Example (MCVE) 和 10 行示例数据,以便我们提供其他帮助。见:Do I cast the result of malloc?

标签: c linked-list segmentation-fault


【解决方案1】:

这不是崩溃的根本原因,但这是一个错误。您在 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;
    }

【讨论】:

  • 是的,我之前确实抓住了它,但忘记了,哈哈,我想看看什么会起作用
猜你喜欢
  • 2021-06-08
  • 2018-05-07
  • 2013-10-21
  • 2012-06-12
  • 2020-09-10
  • 1970-01-01
  • 2018-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多