开饭了,之前写的通讯录,是否会有人觉得申请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();
}
👍 总结
使用动态内存管理,以及文件操作优化了静态通讯录不足,加上了背景音乐,如果对你有帮助的话,请一键三连,谢谢大家了