C语言课程设计

作为刚刚学习C的新手,水平较低,难免出错。希望各位前辈不吝赐教,批评指正。



    在C语言学习了一段时间之后,我们开始入了课程设计。初学了一些简单的语法之后,感觉要完成一项工程还是有些困难的。
    听说在写课程设计时,比起一下子打出来完,不如分模块,分功能的有步骤的去写。
    课程设计的核心,是对链表的操作,实现动态链表的增、删、改、查。这里主要说一下课程设计的思路和想法。
    对于链表的具体操作,诸君都比我水平高,不敢赘言,就简单提一下。

1.显示主菜单

在复杂面前,先做一些微不足道的小工作。先把菜单的内容写了出来,在主函数里调动menu()就会出来这个直接显示的界面。

1.png

    其实一开始,考虑到menu()只是用来显示,我就把它定义成了void型,后来在学长的提醒下,把void改为了int,原来在一些其他的编译器里,void型被淘汰或者是会报错。为了养成良好的编程习惯,就把剩下的void都改成了int或其他。

2.操作菜单

接下来,在操作菜单里,填写以下内容 :

2.png

    这个就是提供一个选择功能的途径,至于功能,之后再补全,总之先把位置留出来。
   通过输入数字的方式来选择功能,在1--8的范围内(图中的printf是添加读档功能前的7个,不必在意),输入正确就让flag=1,如果输入其他的,那就循环回来重输。
    至于那个while里的判断(真or假),只要n不在1--8,就一直为真,一直循环,当然你要是高兴,把(flag==0)换成(1)也行。


3.png

上一步对flag的操作,目的就是为了引出下面的循环,在正确的选择功能里,通过swich实现相关功能的函数调动,n也就是用到这里,当然在一开始并没有这些函数,我只是写了printf和break而已。

为了方便起见,我把switch里的内容先折叠一下。


4.png

    在你选择并实现了相关功能以后,顺序执行,在125行进行询问是否继续,并且通过getchar()来获取一个字符。如果y(yes),再次获取n,再次循环,周而复始。
     如果输入其他的,那就直接退出了exit(0)。
    (函数exit()通常是用在子程序中用来终结程序用的,要加上头文件#include<stdlib.h>)。

3.创建链表

    说起创建链表,大家都有自己的做法。我的做法就是定义了两个结构体指针,先共同赋了一片空间,为p1赋值,(图中的sca就是我调动赋值的函数)。
sca.png

其实再一开始,我就声明了一个全局变量:
                struct work*head=NULL;
    在之后的对链表操作都是在对头进行操作。让链表停止的操作,就是在初始化时,使工号为0。在第一个节点时,需要特殊处理一下,即令p和head指向同一片空间,这样就能起到 拿起链表头就能拿起一串的效果。

    之后的操作就司空见惯了,让p1申请空间并赋值,再让p2指向p1所开辟的新空间,循环往复的增加节点,直到工号为0时停止。

最后,别忘了单链表的尾要置空。最后的返回值就是把“头head”返回去了,因而可以实现case 1里的 head=creat(head)了。

    *那个system("cls")是后来为了美观加上的,在前期修改时为了及时的反馈问题,尽量不要加。

4.显示节点和链表

刚刚做了一套貌似复杂的操作,现在我们来看一些轻松的东西。

在我们对链表进行操作时,难免要经常查看节点和整个链表,要是每次都输出的话那是多么的繁琐,不如直接调动函数。我就写了两个方便自己查看的,一个是看单个节点
node.png

如你所见,传入参数结构体指针,把每一个数据成员都显示出来。


list.png

另一个是显示整个链表,把头head传进来,为了防止对head进行误操作,临时定义结构体指针p。令p和head指向同一片空间,再通过 do-while 对p进行遍历。在printnode()的基础上输出一个一个又一个的节点。

5.增加

毫无疑问,这是这里面最简单的功能操作。

在这个函数里面,你甚至不需要具体的完全遍历。
add.png

    如你所见,为了图方便,我甚至都没有去找最后的节点插入,而是就直接放到了头结点的后面。反正就算只有一个节点也可以放到后面。

6.查找

    除了增加以外,最简单的就算是查找了,因为这个遍历的过程,会是其他功能的基础。


find.png

图中for循环的过程,就是链表遍历的过程,在一遍的搜索之后,如果出现的需要的东西,那就停止搜索,可以拿出来操作了。这里只是作为显示,并不需要操作什么。

图中的continue是考虑到会有工号重复的情况。

7.删除

delete.png

    进入了删除模式之后,会有两个选项,按工号或者姓名删除,其实原理都一样,这里就以工号删除为例。

    令新的指针代替头指针实现遍历(213),判断出来要删除的节点之后,再进行一次判断:你要删除的,是头结点,还是其他的。

a.头结点删除:

    直接让指针指向下一位,释放掉原本的第一个,再让头指针重新指向原本的第二个。这里实现的过程就是pt比pt2多走了一位,以便进行操作。

b.其他节点:

    直接令p2的后继指向pt的后继,也就是把pt直接隔过去,再进行释放。
至于下面的if,如你所见,它的功能就是在while循环里,使指针不断向后推进,直至目标出现。

    当然了,按姓名删除的操作几乎一模一样,唯一的一点小区别就是,if的判断变成了这样:
        if( strcmp(name,pt->name)==0 )
需要判断这两个字符串是否一致,完全一致的话,返回值就是0了,就能找到该节点了。strcmp需要头文件<stdlib.h>.

7.修改
modify.png

    写之前感觉修改会很难,大概是不小心走了什么歪门邪道吧,写出来发现它的过程和遍历一样简单,无非是在我找到相关pt之后,又为它重新赋值了一遍而已(你当然会记得那个sca是我之前定义的赋值函数)。

排序!

    如果你特别熟练链表以及它的增删改查,那么前面写的实在是基础。而排序的确让我为难困惑了一番。

a.冒泡的错

    再最开始版本的排序里,我尝试了用冒泡排序对工号进行操作,排的过程也比较简略。可排出来之后感觉哪里好像有点不对,原来当时只是把num排了顺序,结果是其他的就乱了。
mp.png

如你所见,它繁琐而低效(关键是还不对...)。

    其实当时忘了一点,为什么不直接声明一个结构体变量,然后把它当做中间变量进行排序呢?

b.选择排序

并没有顺着那个思路想下去,换了个方法。

    思想:如果说,原本的链表是无序的,而我最终的目的是创造出有序的。而且我有能力去找到这里面最大的或最小的(遍历就可以了),那么我何不再去创建一个新的链表,它是由原本链表摘出来的节点所组成,那必然是有序的。

sort.png

    和其他操作的最开始一样,传入了头和它之后的一串链表,于以往不同的是,这次开始了直接对头指针的操作。
(366和367是为了防止传进来一个空头造成错误。

核心代码就是white里的循环了:

第一层循环

    目的是为了让头不断向后遍历,只不过这次的目的,就是遍历到终点。期间每执行一次,就让我定义的指针重新指向同一块。

第二层循环

    p(也就是头)的遍历,如果后一个大于前一个,就让后一个成为max,同时定位它的前一个节点,以这种方式标记过后,p再继续向后推进,以实现在循环过后,可以过滤出来最大的,找到了又怎样呢,我们来看接下来的操作。

第一个if(379)

    这时还要考虑到那种情况,也就是头结点万一最大该怎么操作,这也并不难想,直接让head指向下一位,同时断开max(也就是头)与原链表的联系。
其它情况就是,既然上一步(371 while)找出来了max,那么就在这里把它摘出来,令刚刚标记的前一项(pre)指向max的后继,在断开max与原表的联系。

第二个if(387)

    细心的你会发现,在每次的赋值里和之前的几步操作里,都没有用到pnew,不仅如此,它还在一开始就被置空了。
我的目的就是让它成为那个新的链表的头。在之前几步,我们分别找到了max,分离出了max,终于要在这一步为max找一个着落了。

    当然,if第一次肯定是会执行的(因为上来就让pnew置空了),我们让最大的那个节点成了新链表的第一个,那么可想而知的是,在之后几次的循环里,每次都会执行else,并且在里面新摘出来的max被一个个的连到了链表的后面。

    到最后,别忘了还有那个大循环的,它每次执行一遍里面的内容。如是,原本的无序链表每次少一个节点(最大的节点),而新有序链表每次会多一个。

    原链表终结之日,也就是新链表生成之时。届时,循环也就彻底结束了,于是我们令头指针指向那个新生链表(394),再让它们共同指向这条有序的链表,传回去就行了。


    到了这里,课程设计也就基本上结束了,增删改查带排序都说完了,如果你觉得意犹未尽,我们的学长学姐提出了一个新的要求:
    该怎么做,才可以让你的数据保存下来,让我下次打开时还能看到这次的数据,下次开机时它们还在这里?

emmm....

对文件的操作

    在学文件的时候,我总觉得这块的内容可以在今后用到的时候及搜及学。要实现如上功能,需要fwrite和fread :

(1)size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

其中,ptr:指向保存结果的指针;size:每个数据类型的大小;count:数据的个数;stream:文件指针
   函数返回读取数据的个数。

(2)size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
     其中,ptr:指向保存数据的指针;size:每
个数据类型的大小;count:数据的个数;stream:文件指针
    函数返回写入数据的个数。

举个小例子:
fwrite(p,sizeof(int),1,fp )
    这就是个每次向fp里存一个整型的,p就是那个要存到文件里的指针。
read同理,不表。

    原本是要在每个功能的后面都加上这么一个写入文件的,后来在学长的提醒下,把最后一个功能改成了“保存并退出”,合理了不少。

save

save.png

    如我这个save函数:fopen打开,司空见惯。利用for循环,使pt从头到尾的指一遍,每次把一个struct work存进去,也就是一个节点,以这种方式把整条链表存进去。

read

read.png

    你会发现,这是个没有穿入参数的结构体函数,在直至文件fp的结尾之前,一直进行着循环。fread的返回值是写入数据的个数,也就是说每次从文件里面读一个,直到最后一个.

else的作用是把每一个节点都显示出来,显得有那么一点合情合理...

那每次读出来的节点都去了哪里呢?
    这个和刚刚说的排序思路差不多,让head指向和pt一样的空间后,循环申请空间,每次都存入一个从文件里读出来的节点。形成了一条以head为头的新的链表(也就是上次你退出时的数据),被传回来得以继续操作。

    这样,你也就得到了一个,可以增删改查排序的,还能记
录数据的课程设计了。



over.png

写课程设计,对于初学者来说是个漫长而复杂的过程,一筹莫展和万念俱灰的想法总是交相辉映。虽然有时也会绝望(比如我第一次运行有好几十个错误),但这就是个从中学习的过程。
把代码一点一点的改对,是个愉悦而有成就感的事。

last but not least :

感谢敏学姐、浪浪学长的指导和审阅,祝学长和429学长的鼓励支持。
感谢图书馆,提供了几乎所有知识。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 第一章 Nginx简介 Nginx是什么 没有听过Nginx?那么一定听过它的“同行”Apache吧!Ngi...
    JokerW阅读 32,635评论 24 1,002
  • 本文内容:1、 什么是链表?2、 链表共分几类?3、 链表的 C 实现! 总表:《数据结构?》 工程代码 Gith...
    半纸渊阅读 39,914评论 0 54
  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,422评论 3 44
  • //leetcode中还有花样链表题,这里几个例子,冰山一角 求单链表中结点的个数----时间复杂度O(n)这是最...
    暗黑破坏球嘿哈阅读 1,509评论 0 6
  • 多线程、特别是NSOperation 和 GCD 的内部原理。运行时机制的原理和运用场景。SDWebImage的原...
    LZM轮回阅读 2,001评论 0 12