为什么这段用于反向打印单向链表的代码段没有按预期工作?
Why does this code segment, used to reverse print a singly connected linked list, not work as expected?
int printRev(void *l)
{
list_sll *list= (list_sll *)l;
int i= list->noOfNodes-1;
node_sll *subject= malloc(sizeof(node_sll));
subject->next= list->start;
node_sll *front= NULL; /*node directly in front of subject*/
do {
while(subject->next!=front)
subject= subject->next;
printf("%d. %d\n", i, subject->data);
front= subject;
subject->next= list->start;
--i;
}
while(front!=list->start);
subject= NULL;
free(subject);
return 0;
}
我正在将用于存储链表(已创建)所需详细信息的结构(定义如下)的地址传递给 printRev() 函数,该函数接受它作为指向 void 的指针。
这是最小的可行代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct node_sll
{
int data;
struct node_sll *next;
} node_sll;
typedef struct list_sll
{
struct node_sll *start;
int noOfNodes;
} list_sll;
int printlist(void *);
int printRev(void *);
int insert(void *, int);
int main(void)
{
list_sll list1;
list1.noOfNodes= 1;
printf("Creating the first node\nEnter the data\n");
int d;
scanf("%d", &d);
node_sll node1;
node1.data= d;
node1.next= NULL;
list1.start= &node1;
int choice;
do {
printf( "\nEnter:\n1. INSERT: to insert the node\n"
"2. PRINT: print the list\n"
"3. PRINT@rev: print the list in reverse order\n"
"0. QUIT: quit this menu\n");
scanf("%d", &choice);
switch(choice) {
case 1:
printf("Enter the node data\n");
insert(&list1, list1.noOfNodes);
break;
case 2:
printlist(&list1);
break;
case 3:
printRev(&list1);
break;
}
}
while(choice);
return 0;
}
int printlist(void *l)
{
struct list_sll *list= (list_sll *)l;
struct node_sll *p= list->start;
int count= 0;
printf("no of nodes: %d\n", list->noOfNodes);
while(p!=NULL && count < list->noOfNodes) {
printf("%d. %d\n", count, p->data);
p=p->next;
++count;
}
return 0;
}
int insert(void *l, int pos)
{
struct list_sll *list= (list_sll *)l;
struct node_sll *current= malloc(sizeof(node_sll));
int n;
scanf("%d", &(current->data));
current->next= list->start;
struct node_sll *prev_node= NULL;
while(pos--) {
prev_node= current->next;
current->next= current->next->next;
}
if(prev_node==NULL)
list->start= current;
else
prev_node->next= current;
++(list->noOfNodes);
printf("No of nodes %d\n", list->noOfNodes);
return 0;
}
int printRev(void *l)
{
list_sll *list= (list_sll *)l;
int i= list->noOfNodes-1;
node_sll *subject= malloc(sizeof(node_sll));
subject->next= list->start;
node_sll *front= NULL; /*node directly in front of subject*/
do {
while(subject->next!=front)
subject= subject->next;
printf("%d. %d\n", i, subject->data);
front= subject;
subject->next= list->start;
--i;
}
while(front!=list->start);
subject= NULL;
free(subject);
return 0;
}
当我调用 printRev( ) 函数时,反转的列表被打印出来,但出于某种我无法弄清楚的原因,列表元素在打印完成后发生了变化。现在所有节点都存储相同的数据,该数据等于第一个节点的数据值。当我只更改一些指针时,为什么数据会发生变化?
为了调试,我创建了一个列表(节点 - 10、20、30、40)并在 printRev( ):
中添加了一些代码行
int printRev(void *l)
{
list_sll *list= (list_sll *)l;
int i= list->noOfNodes-1;
node_sll *subject= malloc(sizeof(node_sll));
subject->next= list->start;
node_sll *front= NULL; /*node directly in front of subject*/
do {
while(subject->next!=front)
subject= subject->next;
printf("%d. %d\n", i, subject->data);
//printing current list status
printf("%d", list->start->data);
printf("%d", list->start->next->data);
printf("%d", list->start->next->next->data);
printf("%d", list->start->next->next->next->data);
front= subject;
subject->next= list->start;
--i;
}
while(front!=list->start);
subject= NULL;
free(subject);
return 0;
}
这是我调用此函数时得到的输出:
3.40
10
20
30
40
2.30
10
20
30
40
1.20
10
20
30
10
0.10
10
20
10
20
我无法找出问题所在。请帮忙。
对于初学者来说,该函数已经有未定义的行为,因为它有 return 类型 int
但 return 什么都没有。
不需要动态分配节点subject
。可以声明为结构类型的对象。
如果列表为空,此 do-while 循环也会导致未定义的行为
do {
while(subject->next!=front)
subject= subject->next;
printf("%d. %d\n", i, subject->data);
//...
}
while(front!=list->start);
因为将尝试访问空指针的值。
同样在这个 do-while 循环中指针 subject
被改变
do {
while(subject->next!=front)
subject= subject->next;
// ...
subject->next= list->start;
// ...
}
这样原来的列表也变了
这些陈述
subject= NULL;
free(subject);
导致内存泄漏,因为指针subject
指向的原始动态分配对象没有被释放
如果使用您的方法,那么该函数可以如下所示(无需测试)。
void printRev( void *l )
{
list_sll *list = ( list_sll * )l;
int i = list->noOfNodes;
node_sll subject = { 0, list->start };
node_sll *front = NULL; /*node directly in front of subject*/
while ( i != 0 )
{
node_sll *current = &subject;
while ( current->next != front ) current = current->next;
--i;
printf( "%d. %d\n", i, current->data );
front = current;
}
}
这个语句有问题subject->next= list->start;
你在做的时候改变了列表。
您可以通过以下方式修改
int printRev(void *l)
{
list_sll *list= (list_sll *)l;
int i= list->noOfNodes-1;
node_sll *subject = list->start;
node_sll *front= NULL; /*node directly in front of subject*/
do {
while(subject->next!=front)
subject= subject->next;
printf("%d. %d\n", i, subject->data);
front= subject;
subject= list->start;
--i;
}
while(front!=list->start);
}
并且请考虑如果 Vlad 所说的列表为空时该怎么办
int printRev(void *l)
{
list_sll *list= (list_sll *)l;
int i= list->noOfNodes-1;
node_sll *subject= malloc(sizeof(node_sll));
subject->next= list->start;
node_sll *front= NULL; /*node directly in front of subject*/
do {
while(subject->next!=front)
subject= subject->next;
printf("%d. %d\n", i, subject->data);
front= subject;
subject->next= list->start;
--i;
}
while(front!=list->start);
subject= NULL;
free(subject);
return 0;
}
我正在将用于存储链表(已创建)所需详细信息的结构(定义如下)的地址传递给 printRev() 函数,该函数接受它作为指向 void 的指针。 这是最小的可行代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct node_sll
{
int data;
struct node_sll *next;
} node_sll;
typedef struct list_sll
{
struct node_sll *start;
int noOfNodes;
} list_sll;
int printlist(void *);
int printRev(void *);
int insert(void *, int);
int main(void)
{
list_sll list1;
list1.noOfNodes= 1;
printf("Creating the first node\nEnter the data\n");
int d;
scanf("%d", &d);
node_sll node1;
node1.data= d;
node1.next= NULL;
list1.start= &node1;
int choice;
do {
printf( "\nEnter:\n1. INSERT: to insert the node\n"
"2. PRINT: print the list\n"
"3. PRINT@rev: print the list in reverse order\n"
"0. QUIT: quit this menu\n");
scanf("%d", &choice);
switch(choice) {
case 1:
printf("Enter the node data\n");
insert(&list1, list1.noOfNodes);
break;
case 2:
printlist(&list1);
break;
case 3:
printRev(&list1);
break;
}
}
while(choice);
return 0;
}
int printlist(void *l)
{
struct list_sll *list= (list_sll *)l;
struct node_sll *p= list->start;
int count= 0;
printf("no of nodes: %d\n", list->noOfNodes);
while(p!=NULL && count < list->noOfNodes) {
printf("%d. %d\n", count, p->data);
p=p->next;
++count;
}
return 0;
}
int insert(void *l, int pos)
{
struct list_sll *list= (list_sll *)l;
struct node_sll *current= malloc(sizeof(node_sll));
int n;
scanf("%d", &(current->data));
current->next= list->start;
struct node_sll *prev_node= NULL;
while(pos--) {
prev_node= current->next;
current->next= current->next->next;
}
if(prev_node==NULL)
list->start= current;
else
prev_node->next= current;
++(list->noOfNodes);
printf("No of nodes %d\n", list->noOfNodes);
return 0;
}
int printRev(void *l)
{
list_sll *list= (list_sll *)l;
int i= list->noOfNodes-1;
node_sll *subject= malloc(sizeof(node_sll));
subject->next= list->start;
node_sll *front= NULL; /*node directly in front of subject*/
do {
while(subject->next!=front)
subject= subject->next;
printf("%d. %d\n", i, subject->data);
front= subject;
subject->next= list->start;
--i;
}
while(front!=list->start);
subject= NULL;
free(subject);
return 0;
}
当我调用 printRev( ) 函数时,反转的列表被打印出来,但出于某种我无法弄清楚的原因,列表元素在打印完成后发生了变化。现在所有节点都存储相同的数据,该数据等于第一个节点的数据值。当我只更改一些指针时,为什么数据会发生变化? 为了调试,我创建了一个列表(节点 - 10、20、30、40)并在 printRev( ):
中添加了一些代码行int printRev(void *l)
{
list_sll *list= (list_sll *)l;
int i= list->noOfNodes-1;
node_sll *subject= malloc(sizeof(node_sll));
subject->next= list->start;
node_sll *front= NULL; /*node directly in front of subject*/
do {
while(subject->next!=front)
subject= subject->next;
printf("%d. %d\n", i, subject->data);
//printing current list status
printf("%d", list->start->data);
printf("%d", list->start->next->data);
printf("%d", list->start->next->next->data);
printf("%d", list->start->next->next->next->data);
front= subject;
subject->next= list->start;
--i;
}
while(front!=list->start);
subject= NULL;
free(subject);
return 0;
}
这是我调用此函数时得到的输出:
3.40
10
20
30
402.30
10
20
30
401.20
10
20
30
100.10
10
20
10
20
我无法找出问题所在。请帮忙。
对于初学者来说,该函数已经有未定义的行为,因为它有 return 类型 int
但 return 什么都没有。
不需要动态分配节点subject
。可以声明为结构类型的对象。
如果列表为空,此 do-while 循环也会导致未定义的行为
do {
while(subject->next!=front)
subject= subject->next;
printf("%d. %d\n", i, subject->data);
//...
}
while(front!=list->start);
因为将尝试访问空指针的值。
同样在这个 do-while 循环中指针 subject
被改变
do {
while(subject->next!=front)
subject= subject->next;
// ...
subject->next= list->start;
// ...
}
这样原来的列表也变了
这些陈述
subject= NULL;
free(subject);
导致内存泄漏,因为指针subject
指向的原始动态分配对象没有被释放
如果使用您的方法,那么该函数可以如下所示(无需测试)。
void printRev( void *l )
{
list_sll *list = ( list_sll * )l;
int i = list->noOfNodes;
node_sll subject = { 0, list->start };
node_sll *front = NULL; /*node directly in front of subject*/
while ( i != 0 )
{
node_sll *current = &subject;
while ( current->next != front ) current = current->next;
--i;
printf( "%d. %d\n", i, current->data );
front = current;
}
}
这个语句有问题subject->next= list->start;
你在做的时候改变了列表。
您可以通过以下方式修改
int printRev(void *l)
{
list_sll *list= (list_sll *)l;
int i= list->noOfNodes-1;
node_sll *subject = list->start;
node_sll *front= NULL; /*node directly in front of subject*/
do {
while(subject->next!=front)
subject= subject->next;
printf("%d. %d\n", i, subject->data);
front= subject;
subject= list->start;
--i;
}
while(front!=list->start);
}
并且请考虑如果 Vlad 所说的列表为空时该怎么办