我一直在研究我正在创建的shell的代码,但由于某种原因它无法正常工作。我正在实现一个watchuser函数,在给出参数时监视用户(args [1])。但是,当给出“off”的第二个参数(args [2])时,应该从链表中删除用户,并且不应再观看用户。
struct userList * goList;
goList = userInventory;
do{
if (strcmp(userInventory->username, args[1]) == 0){
printf("%s\n", args[1]);
printf("%s\n",userInventory->username);
struct userList * temp2;
temp2 = userInventory->next;
if (userInventory->next != NULL){
userInventory->next = temp2->next;
userInventory->next->prev = userInventory;
}
free(temp2);
}
goList = goList->next;
}while (goList != userInventory);
我的全局结构如下:
struct userList{
char * username;
struct userList * prev;
struct userList * next;
}
由于这个原因,此代码不会从链接列表中删除用户节点。添加工作,但这个删除功能不会,我不知道为什么。 print语句只是为了确保它正在执行条件。
如果有人能帮我找到错误背后的原因,我会非常感激。直到那时,我将尝试调试这个。
感谢。
答案 0 :(得分:1)
如果我了解您的代码,
问题1(看似合理):
goList = userInventory;
do {
...
goList = goList->next;
} while (goList != userInventory);
这是一份循环清单吗?如果不是,那么while ()
中的条件就不会成真。
问题2:
goList = userInventory;
do {
if (strcmp(userInventory->username, args[1]) == 0) {
...
}
goList = goList->next;
} while (goList != userInventory);
在这里,您不断比较列表头部(或尾部)中的字符串,而不是比较当前节点goList
中的字符串。如果匹配位于userInventory
最初指向的第一个节点(头/尾),则查找匹配只能在上面的代码中成功。
问题3:
temp2 = userInventory->next;
if (userInventory->next != NULL) {
userInventory->next = temp2->next;
userInventory->next->prev = userInventory;
}
free(temp2);
我们假设userInventory
已经更正为goList
:
temp2 = goList->next;
if (goList->next != NULL) {
goList->next = temp2->next;
goList->next->prev = goList;
}
free(temp2);
首先,它不是匹配节点free()
,而是它之后的那个(或者甚至是NULL
),这是错误的。
其次,这段代码没有正确地取消链接和重新链接节点。应该是什么(假设列表不是循环的):
temp2 = goList;
if (goList->next != NULL) {
goList->next->prev = goList->prev; // now goList->next node points to goList->prev node
}
if (goList->prev != NULL) {
goList->prev->next = goList->next; // now goList->prev node points to goList->next node
}
free(temp2);
问题4:
do {
if (strcmp(goList->username, args[1]) == 0) {
temp2 = goList;
if (goList->next != NULL) {
goList->next->prev = goList->prev; // now goList->next node points to goList->prev node
}
if (goList->prev != NULL) {
goList->prev->next = goList->next; // now goList->prev node points to goList->next node
}
free(temp2);
}
goList = goList->next;
} while (...);
如果删除成功,此行将访问刚刚释放的节点,并可能导致程序崩溃:
goList = goList->next;
因此,您需要将代码更改为:
do {
if (strcmp(goList->username, args[1]) == 0) {
temp2 = goList;
if (goList->next != NULL) {
goList->next->prev = goList->prev; // now goList->next node points to goList->prev node
}
if (goList->prev != NULL) {
goList->prev->next = goList->next; // now goList->prev node points to goList->next node
}
goList = goList->next;
free(temp2);
}
else
{
goList = goList->next;
}
} while (...);
问题5:
goList = userInventory;
如果删除列表头(或尾部?)节点,则需要更新userInventory
以指向其后的下一个节点。如果不这样做,您将失去对列表的所有访问权限,因为userInventory
将指向已释放的内存而不是其余节点(如果有)。
问题6(似乎合理):
free(temp2);
以上行不free()
temp2->username
后面的内存。如果是free()
,您需要malloc()
。
你应该一步一步地解决问题(例如,首先,遍历列表,然后取消链接/重新链接节点,然后删除节点)。
当事情不清楚或不起作用时,请使用纸和铅笔(或绘图板和笔或粉笔)为自己想象问题。绘制对象,描绘指针的箭头或它们之间的一些其他连接等,在对象旁边涂写变量名称,这样您就可以清楚地看到如何从图表进展到代码。