通讯录小项目

通讯录

​ 本文是根据鹏哥的c语言程序设计课程跟着做出来的小项目。写此内容就是为了,记录在做这个小项目的时候遇到的问题。当然,因为是根据自己的思路写的,所以和鹏哥做的还是有点小出入的。鹏哥是用了一个结构体对通讯录进行了维护,但是,一开始没有想到,用的是全局变量。觉得还是用结构体好。因为全局变量的话,任何代码都是可以修改的,但是如果用结构体的话,可以减少误操作。因为这个小项目没有经过很具体且详细的测试,可能是存在一些bug没有被我发现。如果有发现错误的地方。请不吝赐教!!

​ 本次通讯录分为三个版本。首先是普通版(就是固定了内存大小),然后是进阶版的(可以动态开辟空间存放),最后是比较完善的版本(结合文件将内容保存起来)。

1、普通版通讯录

由于是刚开始写,所以有很多写法都是不规范的。不建议这样,刚开始还是要规范些,要不然后面修改代码就很麻烦,最好就是可以封装起来,降低各个模块的耦合程度,这样需要改的东西就不会很多,不会无从下手

1.1 实现思路:

开辟一段固定大小的内存空间来存放。这样通讯录占用的内存就是固定的。

1.2 遇到的问题

1、使用 scanf 从键盘输入要操作的序号。因为考虑到一个字节就可以存下这个变量,所以用的是char类型来接收。

那么问题就来了:用char类型接收的话,’ \n ‘ 也会从缓冲区里面被读出来。导致下次循环打印菜单的时候,\n 被读取出来。结果就是:第二次什么都没有输入,就又打印一遍菜单。

解决办法:用getchar(),把 \n 读出来就可以了。

2、实现排序功能的时候,无从下手,不知道从哪里开始

解决办法:使用strcmp(),(这就是基本函数不了解的下场)。strcmp的排序规则:比较的是首个字符的ASCII码,如strcmp(“abcd”,“bbcd”)返回的是-1.

3、格式化输出数据:

printf(“\n%-5s\t%-5s\t%-10s\t%-5s\t%-10s\t%-4s\n”,
“序号”,
“名字”,
“电话”,
“性别”,
“地址”,
“年龄”);

2、进阶版通讯录

2.1 改进

  1. 加上了枚举

    增加代码的可读性。因为在后面编写功能时,只看1,2这些数字不知道要实现什么功能。

    enum Option
    {
    	EXIT,    //0
    	ADD,     //1
    	DELETE,  //2
    	SEARCH,  //3
    	MODIFY,  //4
    	SHOW,    //5
    	SORT     //6
    };
    
  2. 将静态的通讯录变成了动态的。

    使用了malloc函数。将原先直接创建的数组变成了一个指针

  3. 增加了一个释放通讯录的功能。

    因为在程序结束了之后,要手动释放自己动态开辟的内存。否则会造成内存泄漏的问题。

  4. 还需要增加一个全局变量来记录通讯录的容量。

2.2 收获

1、使用realloc可以在数组后面追加空间。

值得注意的点有:

  1. 它不是直接在数组后面增加空间,而是另外再开辟一个更大的空间,原来的空间将会被释放掉,它的返回值就是新开辟空间的地址,数组前面的元素,它也会复制过去。

  2. 示例:

    原来是4个int元素的空间大小,现在变成了6个int元素空间的大小

    int* arr = (int*)malloc(4*sizeof(int));
    arr = (int*)realloc(arr,6*sizeof(int));
    

2、内存泄漏:

如下所示:因为ptr本来是指向了一块已经开辟好了的空间,但是,后面ptr又指向了别的空间。这就导致原来开辟的那个空间找不到了,也释放不了。那块空间里的信息没有任何作用,就是垃圾。那块空间就浪费掉了。

int* ptr = (int *)malloc(4*sizeof);
int arr[10] = {0}
ptr = arr;

3、使用free()释放空间的时,下一步一定要把指针置成null

free(pf);
pf = NULL;

如果不置成NULL,那么pf就变成了非法的指针了。如果程序太多了,可能忘记已经释放过了这个指针,又对其进行释放。如果重复释放同一个指针,这就会导致程序崩溃。但是,可以对空指针进行重复的释放,这样是允许的。

3、文件版通讯录

3.1 改进

前面不管是动态开辟空间还是静态开辟,都是无法将信息存储下来的。程序一退出来,信息就会丢失。

所以,现在使用了文件将信息存起来。

3.2 收获

1、读写文件的基本操作:

1.1 打开文件

FILE* pf = fopen("Contact.dat","rb");
if(pf == NULL){
    
    perror("open Contact.dat error");
    return;
}

1.2 读/写文件

fread/fwrite......

1.3 关闭文件

fclose(pf);
pf = NULL;

2、写文件时:

每次打开文件都是从头开始,所以每次都是从头开始写入

3、定位文件指针:fseek

4、返回文件指针相对于起始位置的偏移量:ftell

5、让文件指针回到文件的其实位置:rewind

6、文件结束的判断:feof

其返回值的含义,是在文件读取结束之后,判断是读取失败结束的还是,遇到了文件结尾结束的时候返回非0.

文件结束标志:EOF = -1

1、二进制文件结束的标志:实际读取的数,和我要读取的数不一样

2、文本文件结束的标志:fgetc(pf) == EOF / fgets(pf) == NULL

7、perror和strerror

strerror:把错误码对应的错误信息的字符串地址返回

printf("%s",strerror(errno));

perror:更加直观,不用传递错误码

perror("open Contact.dat error");
//得到的结果:open Contact.dat error:xxxxxx(错误信息)

当然还是有改进的空间。比如讲数据放到数据库里面,这样数据更安全。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值