【发布时间】: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