我有一个链接列表,我试图反过来阅读,但是我这样做有问题。
这是我的结构。
typedef struct node{
int x;
struct node *next;
}node;
问题在于我的阅读功能。 这是功能:
void read(){
node *iter;
while(r->next!=NULL){
iter=r;
while(iter->next!=NULL) iter=iter->next;
printf("%d",iter->x);
free(iter);
}
printf("%d",r->x);
}
我迭代到列表的末尾,然后我读取数据并在之后删除它。并循环它。 但它不起作用。谁能请我解释一下我做错了什么? 该程序的输出也是:
*`./final'错误:双重免费或损坏(fasttop):0x00000000022e24a0 * ======= Backtrace:========= /lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7faccbe7b7e5] /lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7faccbe8437a] /lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7faccbe8853c] ./final[0x400942] ./ final [0x400a06] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7faccbe24830] ./final[0x4006b9] =======记忆地图:======== 00400000-00401000 r-xp 00000000 08:01 8257622 / home / r4g3 / Desktop / 2U / final 00600000-00601000 r - p 00000000 08:01 8257622
/ home / r4g3 / Desktop / 2U / final 00601000-00602000 rw-p 00001000 08:01 8257622 / home / r4g3 / Desktop / 2U / final 022d0000-02302000 rw-p 00000000 00:00 0
[堆] 7facc4000000-7facc4021000 rw-p 00000000 00:00 0 7facc4021000-7facc8000000 --- p 00000000 00:00 0 7faccb8e5000-7faccb8fb000 r-xp 00000000 08:01 39326162
/lib/x86_64-linux-gnu/libgcc_s.so.1 7faccb8fb000-7faccbafa000 --- p 00016000 08:01 39326162
/lib/x86_64-linux-gnu/libgcc_s.so.1 7faccbafa000-7faccbafb000 rw-p 00015000 08:01 39326162
/lib/x86_64-linux-gnu/libgcc_s.so.1 7faccbafb000-7faccbc03000 r-xp 00000000 08:01 39321605
/lib/x86_64-linux-gnu/libm-2.23.so 7faccbc03000-7faccbe02000 --- p 00108000 08:01 39321605
/lib/x86_64-linux-gnu/libm-2.23.so 7faccbe02000-7faccbe03000 r - p 00107000 08:01 39321605
/lib/x86_64-linux-gnu/libm-2.23.so 7faccbe03000-7faccbe04000 rw-p 00108000 08:01 39321605
/lib/x86_64-linux-gnu/libm-2.23.so 7faccbe04000-7faccbfc4000 r-xp 00000000 08:01 39321685
/lib/x86_64-linux-gnu/libc-2.23.so 7faccbfc4000-7faccc1c4000 --- p 001c0000 08:01 39321685
/lib/x86_64-linux-gnu/libc-2.23.so 7faccc1c4000-7faccc1c8000 r - p 001c0000 08:01 39321685
/lib/x86_64-linux-gnu/libc-2.23.so 7faccc1c8000-7faccc1ca000 rw-p 001c4000 08:01 39321685
/lib/x86_64-linux-gnu/libc-2.23.so 7faccc1ca000-7faccc1ce000 rw-p 00000000 00:00 0 7faccc1ce000-7faccc340000 r-xp 00000000 08:01 13631793个
/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 7faccc340000-7faccc540000 --- p 00172000 08:01 13631793
/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 7faccc540000-7faccc54a000 r - p 00172000 08:01 13631793
/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 7faccc54a000-7faccc54c000 rw-p 0017c000 08:01 13631793
/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 7faccc54c000-7faccc550000 rw-p 00000000 00:00 0 7faccc550000-7faccc576000 r-xp 00000000 08:01 39321617
/lib/x86_64-linux-gnu/ld-2.23.so 7faccc74f000-7faccc755000 rw-p 00000000 00:00 0 7faccc774000-7faccc775000 rw-p 00000000 00:00 0 7faccc775000-7faccc776000 r - p 00025000 08:01 39321617
/lib/x86_64-linux-gnu/ld-2.23.so 7faccc776000-7faccc777000 rw-p 00026000 08:01 39321617
/lib/x86_64-linux-gnu/ld-2.23.so 7faccc777000-7faccc778000 rw-p 00000000 00:00 0 7ffd85b05000-7ffd85b26000 rw-p 00000000 00:00 0
[stack] 7ffd85b97000-7ffd85b9a000 r - p 00000000 00:00 0
[vvar] 7ffd85b9a000-7ffd85b9c000 r-xp 00000000 00:00 0
[vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0
[vsyscall] 10Aborted
P.S:" r"是我的全局根变量
答案 0 :(得分:2)
释放节点后,将其指向它的前一个节点next
指针设置为NULL
。
所以,如果你这样做:
free(iter);
指向next
的上一个节点iter
指针应设置为NULL
。
free()
函数不会更改指针本身的值,因此前一个节点next
指针仍指向相同(现在无效)的位置。
循环:
while(iter->next!=NULL)
正在检查NULL
并且它找不到next
指针NULL
,并且您的程序最终释放已在外部while
循环的最后一次迭代中释放的内存如果。因此,您收到double free错误。
要解决此双重免费问题,请跟踪要释放的节点的上一个节点,并在调用free()
后将前一个节点next
指针设置为NULL
。像这样:
node *prev = NULL;
while(iter->next!=NULL) {
prev = iter;
iter = iter->next;
}
printf("%d", iter->x);
free(iter);
if (prev)
prev->next = NULL;
答案 1 :(得分:1)
你可以使用像
这样的递归函数
void read(node* p){
if(p->next != NULL)
read(p->next);
printf("%d ", p->x);
}
这将首先到达链表的末尾并显示从最后到第一个的值。它不会释放内存,但您的问题将解决以相反的顺序打印链接列表。
答案 2 :(得分:1)
正如@Sahyog Vishwakarma已经回答的那样,一个简单的递归打印函数在节点不为NULL时反复调用自身,这是一种反向打印链表的聪明方法。由于我已经做了一个简短的例子,我将提供它以及你可能在其中找到的任何其他好处。
该示例仅使用静态节点数组来创建列表和短打印函数,例如
#include <stdio.h>
#define NNODES 5
typedef struct node {
int x;
struct node *next;
} node;
/* simple recursive function to print list in reverse */
void prn (node *l)
{
if (l) { /* if not NULL */
if (l->next) /* if next not NULL */
prn (l->next); /* call prn (next node) */
printf (" %d", l->x); /* print values on way out */
}
}
int main (void) {
/* short example with static array of nodes */
node a[NNODES] = {{ .x = 0, .next = NULL }};
/* initialize the linked list */
for (int i = 0; i < NNODES; i++) {
a[i].x = i + 1;
if (i < NNODES - 1)
a[i].next = &a[i+1];
}
prn (a); /* reverse-print the list */
putchar ('\n'); /* tidy up with a newline */
return 0;
}
node->x
值填充1 - 5
,调用prn
时会按相反的顺序打印。
示例使用/输出
$ ./bin/prnrecrev
5 4 3 2 1
(注意:每次递归调用都需要创建自己的函数堆栈,因此当列表增长时,使用递归函数时函数调用开销随之增长。作为一般经验法则,你可以在迭代解决方案或程序解决方案之间进行选择,你最好选择程序解决方案 - 不总是,但通常都是这样)
答案 3 :(得分:0)
我刚刚意识到你是数据结构的新手,可能对递归并不那么熟悉。因此,我决定编写一个小程序,它可以帮助您理解链接列表并在没有递归的情况下将其反转。如果您对该区域有更多信息,请告知我们。
typedef struct node{
int x;
struct node *next;
}node;
void createList(node *h, int length)
{
int c = 0;
node *temp = h;
while(c < length)
{
temp->next = (node *)malloc(sizeof(node));
temp = temp->next;
temp->x = ++c;
temp->next = NULL;
}
}
void PrintList(node *h) //print all the nodes
{
while (h != NULL)
{
printf("%d\n", h->x);
h = h->next;
}
}
node * reverseList(node *h)
{
node *p, *q, *l;
p = h;
q = p->next;
l = q->next;
p->next = NULL;
while(l != NULL)
{
q->next = p;
p = q;
q = l;
l = l->next;
}
q->next = p;
return q;
}
void deleteList(node *h)
{
node *t = h;
h = h->next;
free(t);
while(h != NULL)
{
t = h;
h = h->next;
free(t);
}
}
int main(void)
{
node *head = (node *)malloc(sizeof(node));
head->x = 0;
head->next = NULL;
createList(head,10);//create a list with another 10 node total 11
PrintList(head);
printf("Now we are reversing the list\n");
head = reverseList(head);
PrintList(head);
deleteList(head);//finally delete the list
head = NULL;
return 0;
}
答案 4 :(得分:0)
你可能想要这个:
void read() {
node *iter;
while (r->next != NULL) {
iter = r;
node *current = NULL;
while (iter->next != NULL) {
current = iter;
iter = iter->next;
}
printf("%d ", iter->x);
current->next = NULL;
free(iter);
}
if (r != NULL)
{
printf("%d ", r->x);
free(r);
r = NULL;
}
}
read
函数从后面打印整个列表,删除整个列表。显然是您原始代码尝试(和失败)的原因。
这当然效率很低,因为你需要一遍又一遍地找到列表末尾的结尾,但是使用单链表你别无选择。
顺便说一句:拥有一个全局变量r
设计很差,选择像r
之类的名称是一个坏主意,我将其称为listHead
。