| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1094 人关注过本帖
标题:链表结点的创建问题
只看楼主 加入收藏
第二周杰伦
Rank: 2
等 级:论坛游民
帖 子:55
专家分:20
注 册:2013-3-23
结帖率:88.89%
收藏
已结贴  问题点数:20 回复次数:15 
链表结点的创建问题
程序代码:
#include <stdio.h>
#include <stdlib.h>
#include "malloc.h"
#define NULL 0
   struct student
   {
       long int number;
       char name[20];
       float score;
       struct student *next;
  
   };
   struct student *creat(struct student *head);
   void output(struct student *head);
   void main(void)
   {
       struct student *head;
       head=NULL;
       head=creat(head);
       output(head);
   }
   struct student *creat(struct student *head)
   {
       int n=1;
       struct student *p1,*p2;
       p1=p2=(struct student*)malloc(sizeof(struct student));
       printf("input %dth number,name,score:\n",n++);
       scanf("%d%s%f",&p1->number,&p1->name,&p1->score);
       p1->next=NULL;
       while(p1->number>0)
       {
           if(head==NULL)
               head=p1;
           else
               p2->next=p1;
           p2=p1;/****/
           p1=(struct student*)malloc(sizeof(struct student));
           printf("input %dth name,score:\n",n++);
           scanf("%d%s%f",&p1->number,&p1->name,&p1->score);
           p1->next=NULL;
       }
       free(p1);
       return head;
  
   }
void output(struct student *head)
{
    while(head!=NULL)
    {
        printf("学号:%ld,姓名:%s,成绩:%5.2f\n",head->number,head->name,head->score);
        head=head->next;
   
    }

}
求解释心中的疑问。
上面的“struct student *creat(*head)”函数的作用是创建链表结点,在开始的时候指针p1 p2都指向申请好的“struct student”型的地址单元,在给p1所指的空间赋值之后,进入while循环体中,起初判断头指针为空后,后将头指针指向新的结点p1,然后又把p1的地址赋给p2。我的问题是起初申请的空间不是p1 p2 共同指向吗?为何还要再赋?还有头指针非空,执行一次循环体之后回来,通过语句“p2->next=p1”将新创建的结点与上一个结点链接起来,这是p2所指结点的指针域中存放p1,也就是使p2指向了p1,为何还要有“p2=p1'',将p1赋给p2呢?好像怪怪的?
求解释
搜索更多相关主题的帖子: number color 
2013-04-04 19:33
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:0 
create(你的单词拼写也不对)的逻辑是错误的,它只能在head为NULL时算是正确运行,但如果每次只是重新创建一个新的链表那还要形参何用?

关于这一点你可以在main函数里再重复一遍最后那两行看看。

最后,记得释放内存。

重剑无锋,大巧不工
2013-04-04 19:55
第二周杰伦
Rank: 2
等 级:论坛游民
帖 子:55
专家分:20
注 册:2013-3-23
收藏
得分:0 
回复 楼主 第二周杰伦
听不懂啊。这是书上的,逻辑上应该没问题吧。它是通过循环体的第一次执行先创建头结点,然后再通过其他次的循环体执行创建其它结点。就是那就几句没有理解糊里糊涂。我还想问一下其它创建方式的的思路有事怎样的?请指点一二。
2013-04-04 20:39
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:0 
逻辑上的问题非常大。你说是书上的,那告诉我书名、作者、这段代码出现的位置。我倒想看看是谁写的什么书里会有这么不堪的东西。

重剑无锋,大巧不工
2013-04-04 20:49
邓士林
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:淮河河畔
等 级:贵宾
威 望:61
帖 子:2392
专家分:13384
注 册:2013-3-3
收藏
得分:0 
你好好研究下书上的思路,可能是你没理解好吧

Maybe
2013-04-04 21:04
第二周杰伦
Rank: 2
等 级:论坛游民
帖 子:55
专家分:20
注 册:2013-3-23
收藏
得分:0 
回复 4楼 beyondyf
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册

像素不好,拍的不清晰
2013-04-05 00:09
第二周杰伦
Rank: 2
等 级:论坛游民
帖 子:55
专家分:20
注 册:2013-3-23
收藏
得分:0 
回复 4楼 beyondyf
程序代码:
#include "malloc.h"
#include <stdlib.h>
#include <stdio.h>
#define NULL 0
   struct student
   {
       long int number;
       char name[20];
       float score;
       struct student *next;
   };
   struct student *creat(struct student *head);
   void putout(struct student *head);
   void main(void)
   {
       struct student *head;
       head=NULL;
       head=creat(head);
       putout(head);
  
   }
   struct student *creat(struct student *head)
   {
       int n=1;
       struct student *p1,*p2;
       p1=p2=(struct student*)malloc(sizeof(struct student));
       printf("Input %dth number,name,score:\n",n++);
       scanf("%d%s%f",&p1->number,&p1->name,&p1->score);
       p1->next=NULL;
       while(p1->number>0)
       {
           if(head==NULL)
               head=p1;
           else
               p2->next=p1;
           p2=p1;
           p1=(struct student*)malloc(sizeof(struct student));
           printf("Input %dth number,name,score:\n",n++);
           scanf("%d%s%f",&p1->number,&p1->name,&p1->score);
           p1->next=NULL;
       }
       free(p1);
       return head;
   }
   void putout(struct student *head)
   {
       while(head!=NULL)
       {
           printf("学号:%ld,姓名:%s,成绩:%5.2f\n",head->number,head->name,head->score);
           head=head->next;
       }
   }
大师,这是那段代码,完全一样。还有我在网上找了那本书的图片在下面
图片附件: 游客没有浏览图片的权限,请 登录注册
2013-04-05 00:48
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:18 
呵呵,辛苦你了杰伦,看了照片我真的相信那确实是书上的代码,而它出现在一本书里我无法掩饰我的失望。

倒是让我萌生了也写本书的念头。

下面我来一一点出我的失望之处。

#include "malloc.h"
#include <stdlib.h>
#include <stdio.h>


就从这头文件说起吧,引用头文件时用尖括号包含和用双引号包含的意义你知道吧。一般来说我以及大部分人的习惯用法是标准库的头文件用尖括号包含,个人编写的头文件用双引号包含。也有全用双引号的,也挺好。

但都是标准库却有用尖括号的、有用双引号的。不是不可以,只是这种作法出现在一本专业的书籍里就显得太不专业了。由此我可以断定这代码是张莉找学生代写的,还没仔细校对,或者校对的水平太差,亦或张莉也只是为了完成任务而匆匆攒了这么一本书。

失望之余,接着往下看。

#define NULL 0

关于这句,继续失望。我想往好的方面想,也许张莉是想让读者明确地知道NULL的值是多少。但我自己都觉得这个想法牵强。

NULL的定义就在stdio.h里为什么要重新定义一次?而且这个常量在C语言里是如此重要,使用是如此频繁,怎可轻意的改变它的定义?

虽然张莉并没有改变NULL的值,但把它拿出来重新定义就是错的。初学者写成这样,我会善意地提醒他。一教学的本书里这样写,我就不能忍了。这不是误人子弟么!


程序代码:
   struct student
   {
       long int number;
       char name[20];
       float score;
       struct student *next;
   };
   struct student *creat(struct student *head);
   void putout(struct student *head);
   void main(void)
   {
       struct student *head;
       head=NULL;
       head=creat(head);
       putout(head);

 
   }


这段代码没什么大问题,只是前面空出的一个制表符看着不爽。原来我以为是你自己排版成这样的,结果看照片上原来书里也是这么写的。唉,各种不专业已经懒得再费口舌了,好好说说下一段吧。


程序代码:
   struct student *creat(struct student *head)
   {
       int n=1;
       struct student *p1,*p2;
       p1=p2=(struct student*)malloc(sizeof(struct student));
       printf("Input %dth number,name,score:\n",n++);
       scanf("%d%s%f",&p1->number,&p1->name,&p1->score);
       p1->next=NULL;
       while(p1->number>0)
       {
           if(head==NULL)
               head=p1;
           else
               p2->next=p1;
           p2=p1;
           p1=(struct student*)malloc(sizeof(struct student));
           printf("Input %dth number,name,score:\n",n++);
           scanf("%d%s%f",&p1->number,&p1->name,&p1->score);
           p1->next=NULL;
       }
       free(p1);
       return head;
   }


这段代码是我最不能忍的,问题这么多都不知从何说起了。先捋一遍代码吧

n是个可有可无的东西,仅仅是一个序号(我不承认它记录的是元素个数)

先申请一个元素空间,同时让p1、p2都指向它。

然后对这个新元素进行赋值。

如果这个新元素的number字段被赋予小于等于0的值则不进入循环,释放这个元素,返回head指针。

如果新元素的number字段满足要求则进入循环。

如果head为空指针,则head指向新元素,否则将新元素追加到链表的末尾。p1 p2倒腾的就是这么一个过程。

之后申请新元素空间、赋值判断,如果往复,直到number小于零,退出,返回head指针。


你要是把书上的代码原封不动的编译执行还真能得到预期的结果,但其中存在着太多的不合理的地方。

首先,当传入的形参head为NULL时,才会执行if(head == NULL) head = p1;这一句。而这一句也只会被执行一次,因为只要执行一次后head就不为NULL了。

问题是当传入的形参head一开始就不为NULL呢?if(head == NULL)这一句永远不会被执行,只会执行else部分。结果是p1 p2倒腾出一个链表但永远不会和head链在一起。最后返回的head还是原来的head,而p1 p2倒腾出的链表也被抛弃了,还没释放内存。

也就是说这个函数只有在head为NULL时才能正确执行,一个确定的常量还用得着拿参数来传递么?

如果这段代码的本意是在head指向的链表末尾追加元素,那显然这逻辑是错误的。

再说说这元素的申请赋值过程。是先申请空间,然后赋值到这个空间,之后才判断值是否满足要求,如果不满足则释放这个元素空间。

我不知道该怎么形容这种做法。愚蠢这个词似乎有点过,也有人身攻击之嫌。

正常的做法应该是先得到输入的值,然后判断是否满足要求,满足则申请空间赋值,否则直接退出。这在逻辑上更简单,效率上也不用释放最后那个没用的元素。

即使就按他的逻辑,实现时怎么就选了个while循环?都开始讲链表了,不会没学到do while循环吧?do while循环不正是来做这种先办事再判断的合适结构么!


output函数就不讲了,不判断动态申请的空间是否成功不说了。最后再说一个让我失望之处,代码最终也没释放链表申请的空间。作为专业书籍中的例子,这实在让人忍无可忍。

由于时间关系,我就不继续失望了。有这吐槽的时间不如给你写一个更有价值的例子。

程序代码:
#include<stdio.h>
#include<malloc.h>

struct student
{
    long int number;
    char name[20];
    float score;
    struct student * next;
};

struct student * create()
{
    struct student t, * tail, * p;
    int i;
   
    tail = &t;
    for(i = 1;; i++)
    {
        printf("input %dth number,name,score:\n", i);
        scanf("%d%s%f", &t.number, t.name, &t.score);
        if(t.number <= 0) break;
        p = (struct student *)malloc(sizeof(struct student));//这里也不作申请判断了,以简化代码逻辑
        *p = t;
        p->next = NULL;
        tail->next = p;
        tail = p;
    }
    return t.next;
}

void del(struct student * head)
{
    struct student * p;
    while(head != NULL)
    {
        p = head;
        head = head->next;
        free(p);
    }
}

void output(struct student * head)
{
    while(head != NULL)
    {
        printf("学号:%ld,姓名:%s,成绩:%5.2f\n", head->number, head->name, head->score);
        head = head->next;
    }
}

int main(void)
{
    struct student * head;
    head=create();
    output(head);
    del(head);
    return 0;
}

重剑无锋,大巧不工
2013-04-05 09:28
embed_xuel
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:58
帖 子:3845
专家分:11385
注 册:2011-9-13
收藏
得分:0 
原来写书这么容易呀

总有那身价贱的人给作业贴回复完整的代码
2013-04-05 09:52
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:0 
此张莉不知是不是北航的张莉教授? 还有“主编”是什么意思?

重剑无锋,大巧不工
2013-04-05 10:06
快速回复:链表结点的创建问题
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.022220 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved