开饭了,之前写的通讯录,是否会有人觉得申请1000人的空间是不是有点用不上呀,怎么才能做到要多少申请多少个呢??我们学完动态内存管理,和文件的相关操作,终于可以继续完善我们的通讯录了
船新版本:
为了适应各个用户的体验,8.18日,系统升级,请各位用户查看最新的安装包,做出以下修改
1.为了不占用更多的空间,通讯录容量满时,进行扩容操作。
2.通讯录初始化,会加载文件中的通讯录成员信息,防止出现程序结束后,通讯录销毁问题。
3.增加背景音乐功能,用户在使用该通讯录时,有更好的用户体验,别人有的 咱们必须有
4.增加销毁通讯录功能。
5.增加将通讯录保存到文件功能。
👍 静态版链接
通讯录(静态版)
👍 通讯录结构体的修改
typedef struct pp { struct peoinfo *arr; int sz; int size; }pp;
size:通讯录容量大小,区别于sz(当前存了多少个人)
将struct peoinfo arr[1000]修改为struct peoinfo *arr
对arr指针指向的地方进行动态内存分配,将分配好的地址放到arr中去
👍 扩容函数
void Addbig(pp* p) { if (p->sz == p->size) { peoinfo* tmp = (peoinfo*)realloc(p->arr, (p->size + 2) * sizeof(peoinfo)); if (tmp != NULL) { p->arr = tmp; } p->size+= 2; printf("增容 + 2\n"); } }
当通讯录实际容纳的用户大小通讯录的当前容量时,开始扩容,使用realloc函数,参数1(要扩容空间的起始地址)参数2(扩容后总空间字节大小),将开辟的空间首地址放到tmp指针变量中去,如果扩容成功,将扩容好的首地址放到p->arr指针里面去,p->size+= 2,每次增加两个容量大小
👍 文件加载到通讯录函数
void Loadcontact(pp* p) { FILE* fp=fopen("contact.txt", "rb"); if (fp == NULL) { perror("Loadcontact:"); return; } peoinfo tmp = { 0 }; while (fread(&tmp,sizeof(peoinfo),1,fp)) { Addbig(p); p->arr[p->sz] = tmp; p->sz++; } fclose(fp); fp = NULL; }
用二进制读的方式打开文件,如果未打开,返回空指针给fp,然后打印出错误,定义一个人信息的结构体变量,使用fread函数参数1(目标地址),参数2(一次读多少个字节,这里读一个人信息结构体的字节),参数3(每次读几个这样结构体),参数4(从那里读,文件指针),返回值是每次读多少个人信息结构体,如果小于参数3(0).则读完了,读不到一个完整人的结构体.每次从文件中读取数据,调用扩容函数,防止读取数据大于总容量,扩容函数会增加总容量大小,每次将一个人的信息读到结构体tmp中,将tmp里面的一个人信息赋值给p->arr[p->sz];然后当前存储的数目sz++;
然后关闭文件,将文件指针置空
👍 初始化通讯录函数
void Initcontanct(pp* p) { /*p->sz = 0; memset(p->arr, 0, sizeof(p->arr));*/ p->sz = 0; p->size = SIZE; p->arr = (peoinfo*)malloc(p->size * sizeof(peoinfo)); if (p->arr == NULL) { perror(" Initcontanct:malloc"); return; } memset(p->arr, 0, p->size * sizeof(peoinfo)); Loadcontact(p); }
初始化通讯录没有存入信息,p->sz=0;开始通讯录的容量可以存三个人,p->size = SIZE;前面定义 SIZE 为3,动态开辟三个人信息结构体大小的空间,将开辟空间的首地址传给指针变量p->arr;如果传的为空指针,则打印错误,memset,内存操作函数将创建三个容量大小的数据置为0,调用Loadcontact§;加载文件中的数据
👍 保存进文件函数
void Savecontact(pp* p) { FILE* fp = fopen("contact.txt", "wb"); if (fp == NULL) { perror("Savecontact:"); return; } int i = 0; for (i = 0; i < p->sz; i++) { fwrite(p->arr+i, sizeof(peoinfo), 1, fp); } fclose(fp); fp = NULL; printf("保存成功\n"); }
以二进制写的方式打开文件,打开失败返回空指针,打印错误,使用fwrite函数参数(要写入文件的数据起始地址),参数2(每次写入的字节大小,)参数3(每次写1个人信息结构体大小),参数3(写入文件的地址,文件指针)循环向文件中写入通讯录每个用户信息,循环次数为p->sz,当前通讯录用户人数
👍 通讯录销毁函数
void DestroyContanct(pp* p) { free(p->arr); p->arr = NULL; p->size = 0; p->sz = 0; printf("销毁成功\n"); }
free释放动态申请的内存,参数(动态申请空间的地址),指针置空,
容量清0,当前用户人数清0
👍背景音乐函数
头文件
#include<windows.h> #include<mmsystem.h>//包含多媒体设备接口头文件 #pragma comment(lib,"winmm.lib")//加载静态库
函数实现
void bgm() { //打开音乐 mciSendString("open ./music.MP3", 0, 0, 0);//后面参数不用管,写0即可 //播放音乐 mciSendString("play ./music.MP3", 0, 0, 0);//后面参数不用管 }
注意:上面路径是相对./文件名.文件类型,./是在当前目录下,也可以使用绝对路径,不能出现空格,文件类型最好用大写,使用qq音乐下载好音乐,点击主菜单,音频转码转成MP3格式
使用其他的音乐软件播放不出来(qq音乐打钱)
将音频文件放到当前目录下,在vs中找到解决方案,右击鼠标,找到在文件资源管理器中打开文件夹,放到图示位置即可
使用绝对路径复制上面的复制路径"D:\C-code\1\elementary-stage-of-c-language\通讯录(动态加文件)\通讯录(动态加文件)\music.mp3",将反斜杠改成双反‘'或者/也行。
如果出现以下错误
调试找到调试属性
高级-字符集
使用多字节字符集就ok了
#源码展示
contanct.h
#pragma once #define _CRT_SECURE_NO_WARNINGS #include<windows.h> #include<mmsystem.h>//包含多媒体设备接口头文件 #include<stdio.h> #include <string.h> #include <stdlib.h> #pragma comment(lib,"winmm.lib")//加载静态库 #define MAX_NAME 20 #define MAX_SEX 6 #define MAX_TEL 12 #define MAX_ADDR 20 #define SIZE 3 enum opion { EXIT, ADD, DEL, SEARCH, MODIFY, SORT, PRINT, SAVE, MUSIC, DESTROY }; typedef struct peoinfo { char name[MAX_NAME]; char sex[MAX_SEX]; int age; char tel[MAX_TEL]; char addr[MAX_ADDR]; }peoinfo; typedef struct pp { struct peoinfo *arr; int sz; int size; }pp; void Initcontanct(pp* p); void Addcontanct(pp* p); void Printcontanct(pp* p); void Delcontanct(pp* p); void findcontanct(pp* p); void modifycontanct(pp* p); void Sortcontanct(pp* p); void Addbig(pp* p); void Loadcontact(pp* p); void Savecontact(pp* p); void bgm(); void DestroyContanct(pp* p);
contanct.c
#include"contanct.h" //#include<windows.h> #include<graphics.h>//包含图形库头文件 //#include<mmsystem.h>//包含多媒体设备接口头文件 //#pragma comment(lib,"winmm.lib")//加载静态库 void DestroyContanct(pp* p) { free(p->arr); p->arr = NULL; p->size = 0; p->sz = 0; printf("销毁成功\n"); } void Addbig(pp* p) { if (p->sz == p->size) { peoinfo* tmp = (peoinfo*)realloc(p->arr, (p->size + 2) * sizeof(peoinfo)); if (tmp != NULL) { p->arr = tmp; } p->size+= 2; printf("增容 + 2\n"); } } void Loadcontact(pp* p) { FILE* fp=fopen("contact.txt", "r"); if (fp == NULL) { perror("Loadcontact:"); return; } peoinfo tmp = { 0 }; while (fread(&tmp,sizeof(peoinfo),1,fp)) { Addbig(p); p->arr[p->sz] = tmp; p->sz++; } fclose(fp); fp = NULL; } void Savecontact(pp* p) { FILE* fp = fopen("contact.txt", "wb"); if (fp == NULL) { perror("Savecontact:"); return; } int i = 0; for (i = 0; i < p->sz; i++) { fwrite(p->arr+i, sizeof(peoinfo), 1, fp); } fclose(fp); fp = NULL; printf("保存成功\n"); } void Initcontanct(pp* p) { /*p->sz = 0; memset(p->arr, 0, sizeof(p->arr));*/ p->sz = 0; p->size = SIZE; p->arr = (peoinfo*)malloc(p->size * sizeof(peoinfo)); if (p->arr == NULL) { perror(" Initcontanct:malloc"); return; } memset(p->arr, 0, p->size * sizeof(peoinfo)); Loadcontact(p); } void Addcontanct(pp* p) { Addbig(p); printf("请输入姓名\n"); scanf("%s", p->arr[p->sz].name); printf("请输入性别\n"); scanf("%s", p->arr[p->sz].sex); printf("请输入年龄\n"); scanf("%d", &(p->arr[p->sz].age)); printf("请输入电话\n"); scanf("%s", p->arr[p->sz].tel); printf("请输入地址\n"); scanf("%s", p->arr[p->sz].addr); p->sz++; printf("录入成功\n"); } void Printcontanct(pp* p) { int i = 0; printf("******************************************************\n"); printf("%-10s %-5s %-5s %-12s %-20s\n", "姓名", "性别", "年龄", "电话", "地址"); printf("******************************************************\n"); for (i = 0; i < p->sz; i++) { printf("%-10s %-5s %-5d %-12s %-20s\n", p->arr[i].name, p->arr[i].sex, p->arr[i].age, p->arr[i].tel, p->arr[i].addr); printf("******************************************************\n"); } } int find(pp* p, char name[]) { int i = 0; for (int i = 0; i < p->sz; i++) { if (!strcmp(p->arr[i].name, name)) return i; } return -1; } void Delcontanct(pp* p) { char name[MAX_NAME]; printf("请输入要删除朋友的名字\n"); scanf("%s", name); if (find(p, name) == -1) { printf("查无此人\n"); } else { int k = find(p, name); for (int j = k; j < p->sz - 1; j++) { p->arr[j] = p->arr[j + 1]; } p->sz--; printf("删除成功\n"); } } void findcontanct(pp* p) { char name[MAX_NAME]; if (p->sz == 0) { printf("通讯录为空\n"); return; } printf("请输入要查找朋友的名字\n"); scanf("%s", name); if (find(p, name) == -1) { printf("查无此人\n"); } else { int k = find(p, name); printf("******************************************************\n"); printf("%-10s %-5s %-5s %-12s %-20s\n", "姓名", "性别", "年龄", "电话", "地址"); printf("%-10s %-5s %-5d %-12s %-20s\n", p->arr[k].name, p->arr[k].sex, p->arr[k].age, p->arr[k].tel, p->arr[k].addr); printf("******************************************************\n"); } } void modifycontanct(pp* p) { char name[MAX_NAME]; printf("请输入修改朋友的名字\n"); scanf("%s", name); if (find(p, name) == -1) { printf("查无此人\n"); } else { int k = find(p, name); printf("请输入要修改朋友的信息\n"); printf("修改性别->"); scanf("%s", p->arr[k].sex); printf("修改年龄->"); scanf("%d", &(p->arr[k].age)); printf("修改电话->"); scanf("%s", p->arr[k].tel); printf("修改地址->"); scanf("%s", p->arr[k].addr); printf("修改成功\n"); } } int int_cmp_age(const void* p1, const void* p2)//按年龄比较 { return ((struct peoinfo*)p1)->age - ((struct peoinfo*)p2)->age; } void Sortcontanct(pp* p) { qsort(p->arr, p->sz, sizeof(peoinfo), int_cmp_age); printf("按年龄排序成功,快去打印吧\n"); } void bgm() { //打开音乐 mciSendString("open ./music.MP3", 0, 0, 0);//后面参数不用管 //播放音乐 mciSendString("play ./music.MP3", 0, 0, 0);//后面参数不用管 }
test.c
#include"contanct.h" void menu() { printf("#######################################\n"); printf("#********* 1.add ***************#\n"); printf("#********* 2.del ***************#\n"); printf("#********* 3.search ***************#\n"); printf("#********* 4.modify ***************#\n"); printf("#********* 5.sort ***************#\n"); printf("#********* 6.print ***************#\n"); printf("#********* 7.save ***************#\n"); printf("#********* 8.music ***************#\n"); printf("#********* 9.Destroy***************#\n"); printf("########## 0.exit ################\n"); } void test() { pp pro; Initcontanct(&pro); int input; do { menu(); scanf_s("%d", &input); switch (input) { case ADD: Addcontanct(&pro); break; case DEL: Delcontanct(&pro); break; case SEARCH: findcontanct(&pro); break; case MODIFY: modifycontanct(&pro); break; case SORT: Sortcontanct(&pro); break; case PRINT: Printcontanct(&pro); break; case SAVE: Savecontact(&pro); break; case MUSIC: bgm(); break; case DESTROY: DestroyContanct(&pro); break; case EXIT: printf("退出通讯录\n"); break; default: printf("输入错误,请重新输入\n"); break; } } while (input); } void main() { test(); }
👍 总结
使用动态内存管理,以及文件操作优化了静态通讯录不足,加上了背景音乐,如果对你有帮助的话,请一键三连,谢谢大家了