【c语言】通讯录(动态版+文件+背景音乐)含源码

news2024/12/22 6:25:06

开饭了,之前写的通讯录,是否会有人觉得申请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();

}

👍 总结

使用动态内存管理,以及文件操作优化了静态通讯录不足,加上了背景音乐,如果对你有帮助的话,请一键三连,谢谢大家了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/894036.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python异常处理:优雅应对错误与异常

文章目录 &#x1f340;引言&#x1f340;异常的概念&#x1f340; try-except块&#x1f340;多个except块&#x1f340;else块&#x1f340;finally块&#x1f340;异常类型&#x1f340;抛出异常&#x1f340;异常处理的最佳实践&#x1f340;异常处理的现实应用&#x1f34…

设计模式之代理模式(Proxy)的C++实现

1、代理模式的提出 在组件的开发过程中&#xff0c;有些对象由于某种原因&#xff08;比如对象创建的开销很大&#xff0c;或者对象的一些操作需要做安全控制&#xff0c;或者需要进程外的访问等&#xff09;&#xff0c;会使Client使用者在操作这类对象时可能会存在问题&…

k8s ingress

一、浅谈ingress &#xff08;ingress 是与service配合使用的&#xff09; Ingress能把Service&#xff08;Kubernetes的服务&#xff09;配置成外网能够访问的URL&#xff0c;流量负载均衡&#xff0c;及SSL&#xff0c;并提供域名访问的虚拟主机等&#xff0c;客户通过访问UR…

【C++学习手札】一文带你认识C++虚函数(内层剖析)

食用指南&#xff1a;本文在有C基础的情况下食用更佳 &#x1f340;本文前置知识&#xff1a; C初识继承 ♈️今日夜电波&#xff1a;No title —REOL 1:02 ━━━━━━️&#x1f49f;──────── 4:03 …

无涯教程-Perl - use函数

描述 此函数将MODULE导出的所有功能(或仅LIST引用的功能)导入当前包的名称空间。有效等效于- BEGIN { require "Module.pm"; Module->import(); }也用于在当前脚本上强加编译器指令(编译指示),尽管从本质上讲它们只是模块。 请注意,use语句在编译时进行判断。在…

【网络】网络层——IP协议

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《网络》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 网络层中&#xff0c;IP协议首部和有效载荷组成的完整数据称为数据报。 IP协议 &#x1f349;TCP和IP的…

文件批量管理,如何将文件进行一一复制备份并删除原文件里的文件

您是否经常需要对大量的文件进行复制备份和删除操作&#xff1f;是时候拥有一款高效的文件批量管理工具了&#xff01;我们的一键批量管理软件为您提供了简单而强大的解决方案&#xff0c;让您轻松地进行文件复制备份并删除原文件&#xff0c;让存储空间得到高效整理&#xff0…

为什么浙大MBA项目提前批面试要控制优秀人数比例?

大家好&#xff01;时间来到八月份&#xff0c;不知道今年浙大MBA项目的提前批面试你是否已经申请参加过&#xff1f;从剩余批次来看&#xff0c;留给考生做选择的时间确实不是很多了&#xff0c;仅剩的几个批次中&#xff0c;只有杭州第五批目前时间上还算充裕&#xff0c;其余…

Talk | ACL‘23 杰出论文奖上海交通大学吴蔚琪:预训练语言模型对本体知识的记忆与理解

本期为TechBeat人工智能社区第523期线上Talk&#xff01; 北京时间8月17日(周四)20:00&#xff0c;上海交通大学硕士研究生—吴蔚琪的Talk已准时在TechBeat人工智能社区开播&#xff01; 她与大家分享的主题是: “预训练语言模型对本体知识的记忆与理解”&#xff0c;分享了预训…

八股文之八大排序(C++)

目录 1.直接插入排序 2.希尔排序 3.简单选择排序 4.堆排序 5.冒泡排序 6.快速排序 7.归并排序 8.基数排序&#xff08;桶排序&#xff09; 9.主函数 10.画图总结 1.直接插入排序 int ai[] 为需要排序的数组 start 为起始位置&#xff0c;要求 start>1 ,因为 ai[0…

python基础4——类、异常处理、常用模块

文章目录 一、类二、python异常处理三、自定义模块3.1 保留模块测试代码3.2 添加模块使用说明 四、内置模块4.1 os标准库4.2 os.path类4.3 sys库4.4 platform库4.5 glob库4.6 random库4.7 subprocess库4.8 pickle库4.9 JSON库4.10 time库4.11 datetime库4.12 urllib库4.12.1 re…

Unity Android 之 使用 HanLP 进行句子段落的分词处理(包括词的属性处理)的简单整理

Unity Android 之 使用 HanLP 进行句子段落的分词处理&#xff08;包括词的属性处理&#xff09;的简单整理 目录 Unity Android 之 使用 HanLP 进行句子段落的分词处理&#xff08;包括词的属性处理&#xff09;的简单整理 一、简单介绍 二、实现原理 三、注意事项 四、效…

水泥厂人员定位方案

水泥厂人员定位方案可以采用不同的技术和策略。以下是一个常见的水泥厂人员定位方案的步骤&#xff1a; 1.选择合适的定位技术&#xff1a;根据水泥厂的需求和运营环境&#xff0c;选择适合的定位技术&#xff0c;例如基于UWB&#xff08;Ultra-Wideband&#xff09;、RFID&am…

无涯教程-Perl - undef函数

描述 此函数未定义EXPR的值。用于标量,列表,哈希,函数或类型范围。在带有诸如undef $hash {$key}之类的语句的哈希上使用&#xff1b;实际上将指定键的值设置为未定义的值。 如果要从哈希中删除元素,请使用delete函数。 语法 以下是此函数的简单语法- undef EXPRundef返回…

windows ipv4 多ip地址设置,默认网关跃点和自动跃点是什么意思?(跃点数)

文章目录 Windows中的IPv4多IP地址设置以及默认网关跃点和自动跃点的含义引言IPv4和IPv6&#xff1a;简介多IP地址设置&#xff1a;Windows环境中的实现默认网关跃点&#xff1a;概念和作用自动跃点&#xff1a;何时使用&#xff1f;关于“跃点数”如何确定应该设置多少跃点数&…

【3Ds Max】布料命令的简单使用

简介 在3ds Max中&#xff0c;"布料"&#xff08;Cloth&#xff09;是一种模拟技术&#xff0c;用于模拟物体的布料、织物或软体的行为&#xff0c;例如衣物、帆布等。通过应用布料模拟&#xff0c;您可以模拟出物体在重力、碰撞和其他外力作用下的变形和动态效果。…

【学习FreeRTOS】第11章——FreeRTOS中任务相关的其他API函数

1.函数总览 序号函数描述1uxTaskPriorityGet()获取任务优先级2vTaskPrioritySet()设置任务优先级3uxTaskGetNumberOfTasks()获取系统中任务的数量4uxTaskGetSystemState()获取所有任务的状态信息5vTaskGetInfo()获取单个任务的状态信息6xTaskGetCurrentTaskHandle()获取当前任…

利用Velero对K8S备份还原与集群迁移实战

一、简介 Velero 是一款云原生时代的灾难恢复和迁移工具&#xff0c;采用 Go 语言编写&#xff0c;并在 github 上进行了开源&#xff0c;利用 velero 用户可以安全的备份、恢复和迁移 Kubernetes 集群资源和持久卷。 开源地址&#xff1a;https://github.com/vmware-tanzu/v…

Element通过v-for循环渲染的form表单校验

需求&#xff1a;有个表单信息是v-for渲染的&#xff0c;例如下图&#xff0c;通过循环遍历实现新增和删除模块&#xff0c;按照平时的写法实现校验&#xff0c;是不能实现我们想要的效果&#xff0c;根据这个需求&#xff0c;我找到了一个解决方法 1.HTML <el-form ref&qu…

【抓包工具】whistle抓包工具分享

一、使用场景 抓包请求转发 二、基础篇 官网&#xff1a;http://wproxy.org/whistle/ github: https://github.com/avwo/whistle 简介&#xff1a; whistle(读音[ˈwɪsəl]&#xff0c;拼音[wēisǒu])基于Node实现的跨平台web调试代理工具&#xff0c;类似的工具有Window…