因此,我正在编写一个创建动态列表的程序,它在最后一个节点之后插入一个新节点,并最终打印出新创建的列表。我希望当我打印它时,它实际上连续打印当前节点的编号(例如Info:1,Info:2,Info:3),但事实证明它总是打印最后一个节点。我猜这是一个指针错误,但实际上找不到。
#include <stdio.h>
#include <stdlib.h>
struct node{
int info;
struct node* pNext;
};
typedef struct node Node;
void tail_insertion(Node* pFirst, Node* pLast);
void print_list(Node* pFirst);
static int n=3;
int main()
{
Node *pFirst=NULL, *pLast=NULL;
tail_insertion(pFirst, pLast);
}
void tail_insertion(Node* pFirst, Node* pLast){
// Creation of a new node in the heap
Node *pNew = (Node*) malloc(sizeof(Node));
pNew->info=0;
pNew->pNext= NULL;
for(int i=0; i<3;i++){
if(pFirst == NULL){// No node in the list
pNew->info++;
pFirst = pNew; // The first node is the newly created one
pLast = pNew; // The last node is the newly created one
printf("Ok the list was empty\n");
}
else{
// Else, there is already at least one node in the list
pNew->info++;
pLast-> pNext= pNew; // the last node becomes the second one
pLast= pNew; // The last node is the newly created one
printf("Ok the list wasn't empty\n");
}
}
print_list(pFirst);
return;
}
void print_list(Node* pFirst){
if(pFirst == NULL){
printf("No node in the list!\n");
}
else{
// New pointer used to scan the list.
Node* pScan = pFirst;
do{
printf("Info: %d\n", pScan->info);
// ptrScan is updated to point to the next node in the
// list
pScan = pScan->pNext;
}while(pScan!= NULL && --n); //NULL when this was the last node
}
return;
}
打印如下:
Ok the list was empty
Ok the list wasn't empty
Ok the list wasn't empty
Info: 3
Info: 3
Info: 3
答案 0 :(得分:2)
两个问题:
Node *
-> Node **
)Node
插入3次(将malloc()
插入循环)我猜想static int n = 3
和while ... && --n)
可能是为了“修复” print_list()
中的无穷循环而进行的一次拼命尝试,因为pscan->pNext
产生了pscan
用原始代码...
修复并清理代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct node Node;
typedef struct node {
int info;
Node* pNext;
} Node;
static void print_list(Node* pFirst) {
// New pointer used to scan the list.
Node* pScan = pFirst;
while (pScan) {
printf("Info: %d\n", pScan->info);
// ptrScan is updated to point to the next node in the
// list
pScan = pScan->pNext;
}
}
static void tail_insertion(Node** pFirst, Node** pLast) {
for (int i=0; i<3; i++) {
// Creation of a new node in the heap
Node *pNew = malloc(sizeof(Node));
pNew->info = i + 1;
pNew->pNext = NULL;
if (*pFirst == NULL) { // No node in the list
*pFirst = pNew; // The first node is the newly created one
*pLast = pNew; // The last node is the newly created one
printf("Ok the list was empty\n");
} else { // Else, there is already at least one node in the list
(*pLast)->pNext = pNew; // the last node becomes the second one
*pLast = pNew; // The last node is the newly created one
printf("Ok the list wasn't empty\n");
}
}
print_list(*pFirst);
}
int main(int argc, char *argv[]) {
Node *pFirst = NULL;
Node *pLast = NULL;
tail_insertion(&pFirst, &pLast);
}
试运行:
$ gcc -Wall -Werror -o dummy dummy.c
$ ./dummy
Ok the list was empty
Ok the list wasn't empty
Ok the list wasn't empty
Info: 1
Info: 2
Info: 3
答案 1 :(得分:2)
让我们考虑 tail_insertion(...)
以及您要执行的操作:
for
循环的目的是根据特定条件创建更多节点; 现在,查看您的代码 tail_insertion(...)
功能(已删除注释):
Node *pNew = (Node*) malloc(sizeof(Node));
pNew->info=0;
pNew->pNext= NULL;
for(int i=0; i<3;i++){
if(pFirst == NULL){
pNew->info++;
pFirst = pNew;
pLast = pNew;
printf("Ok, the list was empty.\n");
} else {
pNew->info++;
pLast-> pNext= pNew;
pLast= pNew;
printf("Ok, the list wasn't empty.\n");
}
}
print_list(pFirst);
看到任何问题了吗?没有?好吧,让我们继续。
我们将逐步调试此功能。除了程序修复之外,它对于学习过程也很重要:
pNEW
。它是空的。 0x01
(虚构); 0
分配给pNew->info
; NULL
分配给pNew->pNext
; for
循环的开始-尝试为列表创建3个节点:
i = 0
:
1
添加到pNew->info
值中。 pNew
的地址为0x01
; pFirst
被分配为指向地址0x01
; pLast
被分配为指向地址0x01
; i = 0
的末尾,列表如下:
pFirst
指向地址0x01
; pLast
指向地址0x01
; 0x01->info
是1
; i = 1
1
添加到pNew->info
值中。 pNew
的地址为0x01
。从来没有创建另一个节点; pLast->pNext
被分配为指向地址0x01
; pLast
被分配为指向地址0x01
; i = 1
的末尾,列表如下:
pFirst
指向地址0x01
; pLast
指向地址0x01
; pLast->pNext
指向地址0x01
; 0x01->info
是2
; i = 2
1
添加到pNew->info
值中。 pNew
的地址为0x01
。从来没有创建另一个节点; pLast->pNext
被分配为指向地址0x01
; pLast
被分配为指向地址0x01
; i = 2
的末尾,列表如下:
pFirst
指向地址0x01
; pLast
指向地址0x01
; pLast->pNext
指向地址0x01
; pLast->pNext->pNext
指向地址0x01
; 0x01->info
是3
; for
循环的结尾; print_list(...)
到目前为止,您可能已经看到出了什么问题:您尚未在for
循环内创建新节点。您在循环之外创建了它。这样便进行了一个重复的过程,即将具有相同地址的相同节点添加到列表中。
此外,您在使用info
的值时遇到了问题。但这要归功于使用了与上述相同的节点。只需对此增量逻辑进行一些调整即可设置info
的值,以适应需要修改以修复同一节点的使用并使所有工作正常的情况。
使用您自己的代码,应修复tail_insertion(...)
使其类似于以下代码。有评论可帮助您了解更改。
Node *pNew; /* Declaring pNew *without* assignment. */
for(int i = 0; i < 3; i++){
pNew = (Node*) malloc(sizeof(Node)); /* Allocation of new memory address. */
pNew->info = i; /* pNew->info works like an ID in you current code. */
pNew->pNext = NULL; /* It is proper to assign NULL */
if(pFirst == NULL){
pNew->info++;
pFirst = pNew;
pLast = pNew;
printf("The list was empty.\n");
} else {
pNew->info++;
pLast->pNext = pNew;
pLast = pNew;
printf("The list wasn't empty.\n");
}
}
print_list(pFirst);
请注意,由于不必要,我已删除了return(...)
函数。没必要,因为tail_insertion(...)
的类型为void
。
此外,截至我阅读时,pNew->info
正在存储该节点的ID。因此,将i
分配给它应该不是问题。如有必要,请进行适当的更改。
有评论说您不需要pLast
。确实如此,您需要考虑:
pFirst
,则需要确保在pFirst->pNext
中插入新节点之后,您要执行pFirst->pNext->pNext = NULL
。这样,您可以通过与NULL
进行比较来知道何时到达列表末尾; pLast
,则可以与pLast
进行比较,以了解该地址是否是列表中的最后一个地址。显然,修复后,您也可以将其与NULL进行比较; pLast
可以大大简化操作并降低CPU使用率; 您可能知道,但应该将print_list(pFirst);
放在main(...)
函数中,以使事情井井有条。而且,这使我的“代码OCD”达到了绝望的新境界! ;-)