通讯录源代码详解

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

首先,对于stdlib.h头文件,你们不需要知道别的,只要了解,它里面高喊有申请动态内存空间的函数malloc() 就可以了。所以,想要使用该函数,必须加此头文件,就像想要使用printf() 和scanf()必须要加上stdio.h一样。同样,string.h头文件里也包含有好多函数,在本程序里面用的是strcmp() strcpy(),strlen()等等。

下面讲讲#define。这就是传说中的宏定义了。(额外讲一点,之所以称之为“传说中”,是因为我在接触它之前,感觉有多么多么神秘,但真正了解了,其实也没啥神秘可言)。好了不废话了,举个例子#define MAXQQ11.其中,MAXQQ 是宏名,11 是宏体,用宏名可以代替宏体。如若有一下语句:#define M 10 int a =M;则a的值就为10了;理解了吧?或许你们会问:为什么要用那么一大串字母代替一个数字呢?不麻烦么?直接a = 10;不更简单么?呵呵,其实这正是为了修改的方便才用的。比如,一个很大的程序里面多次用到常量10,但后来需要把10改为11,那么只要修改开头部分的#define M 11就可以了,而大可不必在程序中一个一个的闷着头在那里一个劲的傻找。是吧?

下面是结构体,tpyedef struct _person {…}person;至于typedef语句,我想,理论是不能解开困惑的,还是举个例子吧:如有typedef int LIKAI;LIKAI a; 语句就等同于:int a; 两位聪明的三姐四姐,明白了没?总之一句话:typedef就是为数据类型取个别名,(刚刚讲的宏定义是给常量(或表达式)取个别名);所以,我们看到下面的一个结构体里的person per;语句就等同于struct _person per; 还有再下面的addr_book *head =NULL;就等同于struct addr_book *head =NULL啦!这样可以少写一些代码(这里其实也就是少写了一个单词而已)再下面从void add()~void input_person(person *p); 都是函数声明,这一点徐慧丽同学比较了解,有疑问可以问她。

再下面是定义的多个字符串数组,其长度已经隐式的指出,就是下面所以字符个数之和。再下面就是主函数main()了,对了,关于函数的调用,三位同学还是有必要再了解一下的,但是限于篇幅,老师在这里就不再赘述。希望掌握欠佳的同学课后自行温习一下。main()函数开头,调用perint_welcome()函数,我们跳到这个函数里面看一看它的运行机制:外重for 循环内的变量i控制着屏幕的行数,在第四行(i从0~3),开始打印,if里面的三个打印字符串都打印完了呢,就直接跳到第七行,退出外重for循环,打印“回车键进入…”,等用户敲回车时,该函数执行完毕,返回到main()里调用它的地方。

然后进入while循环,循环条件永远为真,因为里面的switch语句里包含很多break语句,所以我们并不怕陷入死循环的泥沼中,嘿嘿,(因为我们不知道用户会输入多少条命令,所以要用while循环),在switch语句里,开关的钥匙是一个函数的返回值,这样可以少定义一个变量,代码也变得精简多了,好了,我们再跳到print_menu()函数里面看看:首先,清屏函数system(“cls”),(我帮你们想好了。要是老师问你们,你们只需说这是个清屏函数,是你们需要清除Dos窗口内的字符的时候,请教高人才得以知道的,嘿嘿),printf(menu);函数打印主菜单界面,并等待用户选择命令,若不在1~8的命令范围只内,提示有误,并请求再次输入,当输入命令合法的时候,返回该命令数字。然后我们在跳回主函数的switch 语句里,可以看到,无论用户选择那个命令,都会调用一个函数,这就是面向过程程序设计的一个特点,(徐慧丽同学现在知道了所谓的函数串的概念了吧?)而C++则不同,它所操作的都是由一个个类所定义的对象,而每个对象都有自己的“方法”(“方法”就是成员函数的一种牛叉的叫法,即专业名词,呵呵),体现了C++不同于C的一个特点:封装性。其实我想我们以开始学C的相对于一开始学C++的同学还是很幸运的,因为我们首先接触的是面向过程程序设计,C++ 我们以后一定会学(会了C还怕不会C++?),而我们有C的基础,可以透过语法结构,从思想上、跟不上区别于二者,对照其异同点,效果会更好,而对于他们一开始就学C++的同学,此生恐怕没有机会接触C了…所以….唉,都是题外话,不说了。

继续讲switch,若print_menu()返回值为1,则调用开关语句里的add(),我们再跳进来看看:addr_book *last;addr_book*_new=(addr_book*)malloc( sizeof(addr_book) );第一句是定义一个结构体指针变量last(这里在强调一下,无论C还是C++,指针是精华,十分、非常、极其、特别、尤为、至关重要,所以,以后以编程为饭碗的同学,必须搞得十分清晰十分熟悉,希望引起三位同学的重视),第二句,定义一个结构体指针变量_new,并指向刚刚用malloc()函数申请的内存块,需要讲一下,malloc()是一个void类型的函数,无返回值,我们想想,啥也不返回,那怎么赋值给_new呢?对吧?所以必须使用强制类型转换,即(addr_book*)malloc()来把它的返回值转换成跟_new一个类型的变量的地址,并赋给_new,对了,sizeof(addr_book) 需要我讲么?这个函数是计算括号内数据类型的字节长度的,我们想呀:要开辟一块空地,应该指出它的尺寸大小吧?(长多少,宽多少)是吧,其实有很多东西,我们都可以把它形象化的,如数组、指针、函数模板、类模板,淡然模板是C++的内容。不好意思,又跑题了。

然后,把刚刚申请的节点的指针域置空(为了防止它乱指,所以置空,但是其实这句是废话,不置空也行的)。面我们要做啥呢?呵呵,当然是把这个节点加到链表当中啦!所以首先判断链表是否为空(全局指针head是始终指向链表的头结点的,所以,单链表中,没事别乱懂head,更千万别乱给它赋值,这咱伤不起啊╮(╯3╰)╭,否则整个链表会没有头绪,整个程序会崩溃…然后…然后,我们就完蛋了)如果链表头为空,则说明链表没有建立起来,那么就把刚刚申请的那块内存当作头吧,即把_new的地址赋给head,若head 不为空,说明已经有了节点,有多少个呢?不知道,好吧,那咱们调用find_last()(顾名思义)找找吧,找到链表的尾巴,然后把刚刚申请的内存块加到它的尾巴上就OK啦!那咱再跳到find_last()里看看它是怎么工作的:想找到尾巴,我们从那里开始下手呢?嘿嘿,你答对了,当然先从头开始啦,所以,find_last()函数的实参就是head指针。需要注意的是,尾巴的一个特点就是:它的指针域是为空的,即:若p为尾节点,则p->next 的值为NULL Find_last()函数里,首先定义了一个结构指针p,将头head赋给他,然后head就可以回家吃饭去啦,哈哈,因为没它啥事了嘛!判断p所指的节点的下一个指向是否为空呢?这节链子下面挂的还有没有下一节呢?当然用眼睛是看不到的,我们上一段说过的,如果为尾巴,则指针域为空(NULL),立即结束find_last()函数,并将尾节点返回给调用它的地方,如果不为空,则把p的指向改为p当前所指的节点的下一个节点,继续判断,直到找到尾巴...找到了尾巴后,立即返回到add(),把尾巴赋值给last指针,并将该节点的指针域的nex指向申请的节点_new。然后呢?呵呵,当然啦,要往这个节点里装东西啦!(其实就跟火车一样),即调用input_person(),形参就是这个节点的数据域的地址,而数据域就是我们以前讲过的那个小结构的全部成员。现在,我们再跳到input_person()里看看:其实这个也没啥好讲的,就是简单的赋值嘛。依次为数据域变量赋值后,返回到add(),然后问是否继续添加,选择“是”,则递归调用(自身调用自身),选择“否”,退出。需要讲一下的是fflush(stdin) ;这个是清除内存缓冲区的函数,即把内存缓冲区的东西都清除掉,到时候老师要是提问你们的话,你们也说,是请教高人才知道的(目前只有这个理由能应付老师了,当然你们也可以自己想理由)。

好了,add()函数执行完毕,我们回到main()函数里调用add()的地方,呵呵它的下一条语句是break;所以,跳出了switch语句,进入while循环。执行条件为1(真),所以再次进入了switch语句,然后再次调用print_menu()打印屏幕主菜单,根据其返回值来选择需要使用的功能,第二个是显示函数show(),这个没什么,所以咱们跳过。第三个是查找函数search(),这里我就跟你们写了一种查找方式,其实可以写很多种的(比如:性别,年龄,手机,还有姓名模糊查找),这些功能就不添加了,否则代码会很长,老师会怀疑的(当然,

我这里不是轻视三姐四姐的能力,请不要误会哈!)。当然,如果你们很自信,并

相关文档
最新文档