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

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

}

👍 总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决 adb install 错误INSTALL_FAILED_UPDATE_INCOMPATIBLE

最近给游戏出包&#xff0c;平台要求 v1 签名吧&#xff0c;AS 打包后&#xff0c;adb 执行安装到手机&#xff0c;我用的设备是google pixel6 , android 系统 13&#xff0c; 提示如下&#xff1a; adb install -r v5_android_202308161046.apk Performing Streamed Install a…

kali linux查看局域网下所有IP,并对指定IP攻击

kali linux查看局域网下所有IP&#xff0c;并对指定IP实施局域网内攻击 首先我们打开我们熟悉的kali linux操作系统&#xff0c;利用指令&#xff1a; ifconfig来确认本机的ip地址 确认了本机的ip地址之后&#xff0c;利用一下的指令查看局域网下所有ip: fping -g 本机IP地址…

C# Linq源码分析之Take (三)

概要 本文在前两篇Take源码分析的基础上&#xff0c;着重分析Range参数中有倒数的情况&#xff0c;即分析TakeRangeFromEndIterator的源码实现。 源码及分析 TakeRangeFromEndIterator方法用于处理Range中的开始和结束索引存在倒数的情况。该方法位于Take.cs文件中。通过yie…

【Windows系统编程】06.HotFixHook与进程通信(详解HotFixHook)

上一讲讲到的InlineHook&#xff0c;每次Hook的时候&#xff0c;都要读写两次内存&#xff08;先Hook&#xff0c;再还原&#xff09;这种Hook方式&#xff0c;性能比较低&#xff0c;今天我们讲的这种Hook方式&#xff0c;可以说是InlineHook的升级版本 HotFix&#xff08;热…

[JavaWeb]【七】web后端开发-MYSQL

前言&#xff1a;MySQL是一种流行的关系型数据库管理系统,它的作用是存储和管理数据。在Web开发中,MySQL是必备的数据库技能之一,因为它可以帮助Web开发人员处理大量的数据,并且提供了强大的数据查询和管理功能。 一 数据库介绍 1.1 什么是数据库 1.2 数据库产品 二 MySQL概述…

NLPR、SenseTime 和 NTU 加速自动视频纵向编辑

视频人像编辑技术已经在电视、视频和电影制作中得到了应用&#xff0c;并有望在不断发展的网真场景中发挥关键作用。最先进的方法已经可以逼真地将同源音频合成为视频。现在&#xff0c;来自北京模式识别国家实验室&#xff08;NLPR&#xff09;、商汤科技研究和南洋理工大学的…

深度分析纳斯达克上市公司慧择的竞争优势和投资价值

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 一、保险行业的现状、竞争与机遇 在疫情期间&#xff0c;很多行业的经营理念与经营方式&#xff0c;甚至客户行为、客户需求都发生了变化&#xff0c;进而催生出新的机遇。保险行业亦是如此&#xff0c;受疫情影响&#xf…

借助 AI 工具,真的能成为 10x 工程师?

或许你听说过 10x 工程师吗&#xff1f; 如果你问猎头公司 10x 工程师是什么意思&#xff0c;他们可能会说 “生产力”&#xff01;10x 是指完成任务比别人快 10 倍的工程师。 2019 年&#xff0c;Twitter 上就曾经对 10 x 工程师这一议题有过一次空前热烈的讨论&#xff0c;引…

解决电脑声音正常但就是某些游戏没声音问题

电脑声音正常&#xff0c;玩普遍游戏也正常&#xff0c;就有游戏不出声音 详细介绍经过&#xff0c;不喜欢的请直接跳 第三部分。 一、先说下起因现象。 1 大富翁11 没声音。 前段时间无聊怀旧就买了个大富翁11玩玩&#xff0c;近二十年前的老台式机正常无问题。后来想在性能…

【网络编程(二)】NIO快速入门

NIO Java NIO 三大核心组件 Buffer&#xff08;缓冲区&#xff09;&#xff1a;每个客户端连接都会对应一个Buffer&#xff0c;读写数据通过缓冲区读写。Channel&#xff08;通道&#xff09;&#xff1a;每个channel用于连接Buffer和Selector&#xff0c;通道可以进行双向读…

Linux下Docker安装及卸载

文章目录 Linux下Docker安装及卸载1 Docker安装及卸载1.1 安装前准备1.2 安装docker软件2.4.3 启动docker2.2.4 测试2.2.5 卸载 Linux下Docker安装及卸载 1 Docker安装及卸载 官方网址&#xff1a;https://docs.docker.com/engine/install/centos/ 1.1 安装前准备 确定你是C…

zookeeper安装配置采坑流程

安装 wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.2/apache-zookeeper-3.8.2-bin.tar.gz解压&#xff1a; tar -zxvf apache-zookeeper-3.8.2-bin.tar.gz如下 bin目录下文件是可执行文件 conf目录文件是配置文件 修改zoo.cfg&#xff08;复制zoo_sample&#x…

【学习FreeRTOS】第12章——FreeRTOS时间管理

1.FreeRTOS系统时钟节拍 FreeRTOS的系统时钟节拍计数器是全局变量xTickCount&#xff0c;一般来源于系统的SysTick。在STM32F1中&#xff0c;SysTick的时钟源是72MHz/89MHz&#xff0c;如下代码&#xff0c;RELOAD 9MHz/1000-1 8999&#xff0c;所以时钟节拍是1ms。 portNV…

jvm类文件结构

一 概述 在 Java 中&#xff0c;JVM 可以理解的代码就叫做字节码&#xff08;即扩展名为 .class 的文件&#xff09;&#xff0c;它不面向任何特定的处理器&#xff0c;只面向虚拟机。Java 语言通过字节码的方式&#xff0c;在一定程度上解决了传统解释型语言执行效率低的问题…

学渣的愤怒!自考本科能不能不考英语和数学?

英语和高数哪个更难&#xff1f; 这是自考生们最头大的两个科目。 自考高数有多难&#xff1f; 高数主要有微积分、线性代数和概率论三个部分。 其中微积分是基础、也是重要的一部分&#xff0c;不仅涉及到很多抽象概念和符号运算&#xff0c;还需要具备良好的计算能力和逻…

简单的洗牌算法

目录 前言 问题 代码展现及分析 poker类 game类 Text类 前言 洗牌算法为ArrayList具体使用的典例&#xff0c;可以很好的让我们快速熟系ArrayList的用法。如果你对ArrayList还不太了解除&#xff0c;推荐先看本博主的ArrayList的详解。 ArrayList的详解_WHabcwu的博客-CSD…

C++笔记之单例模式

C笔记之单例模式 参考笔记&#xff1a;C笔记之call_once和once_flag code review 文章目录 C笔记之单例模式1.返回实例引用2.返回实例指针3.单例和智能指针share_ptr结合4.单例和std::call_once结合5.单例和std::call_once、unique_ptr结合 1.返回实例引用 代码 #include <…

数据结构之队列详解(包含例题)

一、队列的概念 队列是一种特殊的线性表&#xff0c;特殊之处在于它只允许在表的前端&#xff08;front&#xff09;进行删除操作&#xff0c;而在表的后端&#xff08;rear&#xff09;进行插入操作&#xff0c;和栈一样&#xff0c;队列是一种操作受限制的线性表。进行插入操…

亿发创新中医药信息化解决方案,自动化煎煮+调剂,打造智能中药房

传统中医药行业逐步复兴&#xff0c;同时互联网科技和人工智能等信息科技助力中医药行业逐步实现数字化转型。利用互联网、物联网、大数据等科技&#xff0c;实现现代科学与传统中医药的结合&#xff0c;提供智能配方颗粒调配系统、中药自动化调剂系统、中药煎配智能管理系统、…

【Docker报错】docker拉取镜像时报错:no such host

报错信息 [rootSoft soft]# docker pull mysql Using default tag: latest Error response from daemon: Head "https://registry-1.docker.io/v2/library/mysql/manifests/latest": dial tcp: lookup registry-1.docker.io on 192.168.80.2:53: no such host解决方法…