所以我写了一些代码来实现shell(Linux,GCC,C语言),这一切都有效,但是由于某种原因,当我添加history选项时代码崩溃了: 它真的没有(其他代码)所以我只会把你需要的东西放在这里。
问题是当我在一个需要保存在历史记录中的旧命令之后键入quit
时,当我键入退出时,它只会破坏分段错误(核心转储)。
历史记录保存在链表,命令串和下一个节点的节点的结构中,我也将头部保存在主页中。关键是我只想保存最后15个命令,而且我不关心其他命令,因此每次我想要打印列表时,我只是移动了循环中的前15个节点。
当我使用GDB调试时,我发现代码崩溃的行是他将第一个命令添加到历史记录后的行,但当前行与历史记录无关:
主:
int main()
{
history_ll* top;
char userInput [CHOICE_LENGTH];
char buff[PATH_MAX];
int flag=1;
cmdLine * head;
while (flag)
{
getcwd(buff, PATH_MAX);
printf("%s:~$ ",buff);
fgets(userInput,MAX_INPUT, stdin);
userInput[strlen(userInput)-1]=0;
historyAdder(userInput,&top);
if(strcmp(userInput,QUIT_OPTION)==0) //segmentation fault here!
{
flag=0;
}
else
{
//doesn't matter
}
}
return 0;
}
historyAdder看起来像这样:
void historyAdder(const char *command,history_ll** top)
{
history_ll* node;
strcpy(node->command,command);
node->command[strlen(command)]=0;
if(historyLength!=0)
{
node->next= *top;
}
else
{
node->next= NULL;
}
*top = node;
historyLength++;
}
注意:historyLength是一个全局变量
这是结构:
typedef struct history_ll{
char command[CHOICE_LENGTH];
struct history_ll *next;
}history_ll;
谢谢助手!
答案 0 :(得分:1)
此代码中至少存在两个重要问题。 一个是从stdin读取时缓冲区长度可能太短: 定义:
char userInput [CHOICE_LENGTH];
但用法是:
fgets(userInput,MAX_INPUT, stdin);
您应该使用相同的缓冲区大小或断言MAX_INPUT
小于或等于CHOICE_LENGTH
。
其次,通过在此处取消引用未初始化的指针来触发未定义的行为:
void historyAdder(const char *command,history_ll** top)
{
history_ll* node;
strcpy(node->command,command); /* bad... */
答案 1 :(得分:0)
这里(及以下几行)
void historyAdder(const char *command,history_ll** top)
{
history_ll* node;
strcpy(node->command,command);
...
代码取消引用未初始化的指针:node
这样做会调用UB,并且很可能会使程序崩溃。
答案 2 :(得分:0)
这可能是 你的问题:
grep -R '^DocumentRoot' /etc/httpd/ 2>/dev/null ; grep -R '^DocumentRoot' /etc/apache2/ 2>/dev/null
除非char userInput [CHOICE_LENGTH];
...
fgets(userInput,MAX_INPUT, stdin);
大于或等于CHOICE_LENGTH
,否则MAX_INPUT
可以写入fgets
数组的末尾,这会破坏内存,从而导致崩溃。但是,由于您没有显示我可以为自己编译并观看崩溃的完整程序,我无法确定。
给你两条建议: