您的位置:首页 > 编程语言 > C语言/C++

C语言 动态链表的注意点(出现0xcdcdcdcd的情形)

2018-12-20 22:31 85 查看

背景

     最近学习了一下动态链表,第一次编的时候感觉不太对劲,输出结果后光标一直闪着卡在那里,没有显示那个press any button to continue.于是我仔细跟书本核对了一下,果然发现了错误。

具体分析

     先看看我第一次写的代码。(输入多个学号与姓名,组成链表,学号为0表示结束,然后全部输出)

[code]#include<stdio.h>
#include<stdlib.h>
struct Student
{	int num;
char name[10];
struct Student* ptr;
}  ;
int main()
{
//head 头指针 p1 p2用于链表建立 p用于输出
struct Student *head=0,*p1,*p2,*p;
//n来计算节点数量
int n=0;
//先申请第一个节点  返回给p1 p2
p1=p2=(struct Student*)malloc(sizeof(struct Student));
while(1)
{
scanf("%d",&(p1->num));//输入学号
if(p1->num==0) //输入0 就结束
{
p1->ptr=NULL;//最后一个为空指针
break;
}
scanf("%s",p1->name);//输入姓名
n++;
if(n==1) head=p1;
else p2->ptr=p1;
p2=p1;  //p2指向p1
p1=(struct Student*)malloc(sizeof(struct Student));//继续申请
}
p=head;
do  //输出链表
{
printf("%d %s\n",p->num,p->name);
p=p->ptr;
}while(p->ptr!=NULL);
return 0;
}

接着我们运行程序,输入 12 wang   45 li  ,结果如左图:

                 

过了一会儿 ,才终于显示 press any button to continue ,如右图。

      虽然程序能正常显示,但显然是出现了一定的问题,于是我们来对代码进行检查。 不难发现其中一个错误在倒数第二行的while条件,即

                                           while(p->ptr!=NULL) 

这里应该改为 while(p!=NULL),原因应该很简单,而错误造成的后果等一下会提到。

      此时我们再运行一下程序,然而并没有任何改善,并且我们产生了一个更大的疑问,没有修改之前我们应该只能输出第一行数据,可为什么两行都输出了呢?

      带着疑问,我进行了单步调试。

调试

      调试过程中,12 wang申请的地址为0x007f1780,45 li 申请的地址为0x007f1740 (申请的地址是由大到小的)。

      也就是理想状态下,链表应该是这样的:

  num name ptr
head - - 0x007f1780
  12 wang 0x007f1740
  45 li NULL

而实际上,调试出来的结果是这样的:

  num name ptr
head - - 0x007f1780
  12 wang 0x007f1740
  45 li 0xcdcdcdcd
  0 - NULL

造成第一次时两行都输出的原因无疑是 0xcdcdcdcd的出现,毕竟他也不是空指针,那么它到底是什么呢?

0xcdcdcdcd

       查阅资料,我发现0xcdcdcdcd是表示未被初始化的地址,为一个非法地址。所以调试过程中弹出了这个窗口:

       既然他是未初始化的(它理应是NULL,但NULL在下一个指针),说明我们程序运行时将NULL的赋值下移了一位。具体地说,就是这一段的p1->ptr=NULL出现了问题:

[code]if(p1->num==0) //输入为0时
{
p1->ptr=NULL;//最后一个为空指针
break;
}

应该改为 p2->ptr=NULL;修改后结果输出就一切正常了。

释放链表

          很多人强调,使用了malloc函数一定要记得free,但是谭浩强的c教材并没有示范如何释放链表,其实释放链表的函数也挺好写的。那就直接上代码吧。

[code]void freeList(struct Student *head)//释放链表
{     struct Student *p1,*p2=head;
while(p1!=NULL)
{
p1=p2->ptr;
free(p2);
p2=p1;
}
}

感觉核心思想跟链表的建立差不多。把freeList()函数放在printf函数之前,看看它是否真正释放掉,如图:

乱码了,说明链表已经被释放了!

 

 

 

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: