C语言小项目之“究极无敌螺旋丸极爆炸狂拽炫酷五彩棒的”通讯录之*派小猩*作品

本文介绍了一个使用C语言开发的多功能通讯录系统,包括添加、删除、查找、修改、显示、排序、保存和清空等功能。通过结构体和动态内存管理实现数据存储,提供用户交互菜单,并具备错误处理和文件保存。项目中还涉及了内存管理、文件操作和排序算法等技术。
摘要由CSDN通过智能技术生成

C语言小项目之“究极无敌螺旋丸极爆炸狂拽炫酷五彩棒的”通讯录之派小猩作品

项目概述

基于C语言开发一个多功能的通讯录

功能目录

1.增加

2.删除

3.查找

4.修改

5.显示

6.排序

7.保存

8.清空

设计思路

test.c
AddContact
Contact.c
DelContact
SearchContact
ModifyContact
ShowContact
SortContact
SaveContact
EmptyContact

废话不多说直接开整代码

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"//引用自己创建的头文件要用双引号

void menu()
{
	printf("++              0.Exit                  ++\n");
	printf("++     1.Add            2.Del           ++\n");
	printf("++     3.Search         4.Modify        ++\n");
	printf("++     5.Show           6.Sort          ++\n");
	printf("++     7.Save           8.Empty         ++\n");
	printf("++                                      ++\n");
}
int main()
{	
	Contact con;//创建通讯录
	InitContact(&con);//初始化(动态)
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case Add:
			AddContact(&con);
			break;
		case Del:
			DelContact(&con);
			break;
		case Modify:
			ModifyContact(&con);
			break;
		case Search:
			SearchContact(&con);
			break;
		case Show:
			ShowContact(&con);
			break;
		case Sort:
			SortContact(&con);
			break;
		case Save:
			SaveContact(&con);
			break;
		case Empty:
			EmptyContact(&con);
			break;
		case Exit:
			SaveContact(&con);//退出的时候先保存再释放动态内存
			FreeContact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入!\n");
			break;
		}
	} while (input);

	return 0;
}

Contact.c

#define _CRT_SECURE_NO_WARNINGS 
#include "Contact.h"

static void CheckCapacity(Contact* ps);
void LoadContact(Contact* ps)
{
	assert(ps);
	PeoInfo tmp = { 0 };
	FILE* pfRead = fopen("Contact.dat", "rb");//以二进制方式打开读取
	if (!pfRead)//如果NULL
	{
		printf("LoadContact::%s", strerror(errno));
		return;
	}
	//读取文件,加载到通讯录种
	//fread(读取的放到哪个地址,读的元素大小每个,个数,从哪读)返回的时读取到的实际个数
	while (fread(&tmp, sizeof(PeoInfo), 1, pfRead))//返回0代表全部读完了
	{
		//先判断当前容量够不够存
		CheckCapacity(ps);
		//再写入
		ps->data[ps->size] = tmp;
		ps->size++;//计数
	}

	fclose(pfRead);
	pfRead = NULL;
}

void InitContact(Contact* ps)
{
	assert(ps);
	//初始化
	//刚开始默认存放3个人的信息
	ps->data =(PeoInfo*) malloc(DEFAULT_SZ * sizeof(PeoInfo));
	if (!ps->data)//->和.操作符优先级高先结合!!!
	{
		return;//开辟失败
	}
	//初始化计数
	ps->size = 0;
	ps->capacity = DEFAULT_SZ;

	//将本地文件存放的信息加载到通讯录中
	LoadContact(ps);
}

void ShowContact(const Contact* ps)
{
	assert(ps);
	//先判断能不能显示出来(空or不空)
	if (0 == ps->size)
	{
		printf("通讯录内容为空\n");
	}
	else
	{
		//显示标题 内容
		//标题都是字符串不能%d
		int i = 0;
		printf("%-20s\t%-5s\t%-4s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "住址");
		for (i = 0; i < ps->size; i++)//遍历一个一个打印(左对齐-)
		{
			//要与标题栏对齐
			printf("%-20s\t%-5s\t%-4d\t%-12s\t%-30s\n",
				ps->data[i].Name,
				ps->data[i].Sex,
				ps->data[i].Age,
				ps->data[i].Tel,
				ps->data[i].Address);
		}
	}
}
static void CheckCapacity(Contact* ps)
{
	assert(ps);
	//如果满了->增容
	if (ps->capacity == ps->size)
	{
		PeoInfo* ptr=realloc(ps->data, (ps->capacity + 2) * sizeof(PeoInfo));//先交给临时的ptr再去判断是否为空指针不为空才能赋给data
		if (ptr)
		{
			ps->data = ptr;
			ps->capacity += 2;//每次加完都要计数
			printf("扩容成功\n");
		}
		else
		{
			printf("增容失败\n");
		}
	}
	//没满就出去增加数据

}

void DelContact(Contact* ps);//引用声明
void AddContact(Contact* ps)
{
	assert(ps);
	//1.检查容量判断是否超出容量
	int input = 0;
	int i = 0;
	CheckCapacity(ps);
	printf("请输入要添加加联系人的个数:>");
	scanf("%d", &input);
	if (input < 0)
	{
		DelContact(ps);
	}
	//增加数据
	else if(input>0)
	{
		for (i = 0; i < input; i++)
		{
			printf("请输入姓名:>");
			scanf("%s", ps->data[ps->size].Name);
			printf("请输入性别:>");
			scanf("%s", ps->data[ps->size].Sex);
			printf("请输入年龄:>");
			scanf("%d", &(ps->data[ps->size].Age));
			printf("请输入电话:>");
			scanf("%s", ps->data[ps->size].Tel);
			printf("请输入住址:>");
			scanf("%s", ps->data[ps->size].Address);

			ps->size++;
			printf("添加成功!\n");
			CheckCapacity(ps);
		}
	}
	else
	{
		printf("输入错误,请重新输入\n");
	}

}
//FindByName只能在这函数定义里使用用Static修饰
static int FindByName(const Contact* ps, const char name[Name_max])
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (0 == strcmp(name, ps->data[i].Name))
		{
			return i;
		}
	}
	return -1;


}

void DelContact(Contact* ps)
{
	assert(ps);
	//输入要删除的信息的人的名字
	char name[Name_max];
	printf("请输入你所要删除的人的姓名:>");
	scanf("%s", &name);
	//再查找此人的信息(遍历)
	int pos = FindByName(ps, name);
		if (pos == ps->size)
		{
			printf("要删除的人不存在");
		}
	
	//再删除(把要删的数据后面的数据往前面覆盖)
		else
		{
			int j = 0;
			for (j = pos; j < ps->size - 1; j++)
			{
				ps->data[j] = ps->data[j + 1];
			}
			//计数
			ps->size--;
			printf("删除成功\n");
		}
}

void ModifyContact(Contact* ps)
{
	assert(ps);
	char name[Name_max];
	int i = 0;
	printf("请输入要修改的人的名字:>");
	scanf("%s", &name);
	//遍历查找(出现了2次要封装成函数)
	int pos=FindByName(ps, name);//找到就返回下标
	if (-1==pos)
	{
		printf("要修改的人不存在\n");
	}
	else
	{
		//找到了先显示给用户看show
		printf("%-20s\t%-5s\t%-4s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "住址");
		printf("%-20s\t%-5s\t%-4d\t%-12s\t%-30s\n",
			ps->data[pos].Name,
			ps->data[pos].Sex,
			ps->data[pos].Age,
			ps->data[pos].Tel,
			ps->data[pos].Address);
		//修改
		printf("请输入姓名:>");
		scanf("%s", ps->data[ps->size].Name);
		printf("请输入性别:>");
		scanf("%s", ps->data[ps->size].Sex);
		printf("请输入年龄:>");
		scanf("%d", &(ps->data[ps->size].Age));
		printf("请输入电话:>");
		scanf("%s", ps->data[ps->size].Tel);
		printf("请输入住址:>");
		scanf("%s", ps->data[ps->size].Address);

		printf("修改成功!\n");
	}

}


void SearchContact(const Contact* ps)
{
	assert(ps);
	char name[Name_max];
	printf("请输入要查找人的姓名:>");
	scanf("%s", & name);
	int pos=FindByName(ps, name);//找到返回下标,否则返回-1
	if (-1 == pos)//先排除不存在的情况剩下的情况就是找到了
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		printf("%-20s\t%-5s\t%-4s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "住址");
		printf("%-20s\t%-5s\t%-4d\t%-12s\t%-30s\n",
			ps->data[pos].Name,
			ps->data[pos].Sex,
			ps->data[pos].Age,
			ps->data[pos].Tel,
			ps->data[pos].Address);
	}
}

void SortContact(Contact* ps)
{
	//按升序排列
	assert(ps);
	int i = 0;//趟数
	int j = 0;//每一趟在do what?!
	for (i = 0; i <ps->size-1; i++)
	{
		for (j = 0; j < ps->size - 1-i; j++)
		{
			int ret = strcmp(ps->data[j].Name, ps->data[j + 1].Name);
			if (ret>0)
			{
				//交换
				//strcpy(ps->data[j + 1].Name, ps->data[j].Name);//字符交换
				//交换结构体要用结构体变量且类型必须是要交换的结构体的类型
				PeoInfo tmp = ps->data[j];
				ps->data[j] = ps->data[j+1];
				ps->data[j + 1] = tmp;
			}
		}
	}
	printf("排序成功\n");
}

void SaveContact(Contact* ps)
{
	FILE* pfWrite = fopen("Contact.dat", "wb");//以二进制形式写入本地文件
	//判断是否打开成功
	if (!pfWrite)
	{
		printf("SaveContact::%s", strerror(errno));//前面加上函数名和其他的报错作出区分
		return;//失败就出去
	}
	//打开成功开始写入(遍历)一个一个写进去
	else
	{
		int i = 0;
		for (i = 0; i < ps->size; i++)
		{
			fwrite(&(ps->data[i]),sizeof(PeoInfo),1,pfWrite);
			//写入的源头地址,data[i]下标为i的元素,每个元素的大小,一次写入的个数,写到哪个流

		}
		printf("保存成功!\n");
	}
	fclose(pfWrite);//打开之后就关闭文件
	pfWrite = NULL;
}

static void Destroy(Contact* ps)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		PeoInfo tmp = { 0 };
		ps->data[i] = tmp;//把空的人物信息赋给原数据就是全部清空
	}
	ps->size = 0;
	ps->capacity = 0;
	printf("删除成功!\n");
	return;
}
void EmptyContact(Contact* ps)

{
	int input = 0;
	printf("请确定是否要删除通讯录的所有信息\n");
	printf("    1.Ensure        0.Cancel  \n  ");
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		Destroy(ps);
		break;
	case 0:
		return;
	}

}

void FreeContact(Contact* ps)
{
	assert(ps);
	free(ps->data);
	ps->data = NULL;
}

Contact.h 头文件

#pragma once
#define Name_max 5
#define Sex_max 5
//#define Age_max 4
#define Tel_max 12
#define Address_max 50
#define DEFAULT_SZ 3

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<errno.h>
//声明类型
typedef struct PeoInfo
{
	//姓名 性别 年龄 电话号码 住址
	char Name[Name_max];
	char Sex[Sex_max];
	char Tel[Tel_max];
	char Address[Address_max];
	int Age;
}PeoInfo;

typedef struct Contact
{
	PeoInfo* data;//结构体指针指向动态开辟的空间
	int size;//记录当前已有信息数量
	int capacity;//当前最大容量 size==capacity时要进行动态扩容
}Contact;

enum Options//枚举选项可能的取值
{
	Exit,//0
	Add,//1
	Del,//2
	Modify,//3
	Search,//4
	Show,//5
	Sort,//6
	Save,//7
	Empty//8
};

//初始化
void InitContact(Contact* ps);

//增加信息
void AddContact(Contact* ps);

//删除信息
void DelContact(Contact* ps);

//修改信息
void ModifyContact(Contact* ps);

//查找信息
void SearchContact(const Contact* ps);

//排序
void SortContact(Contact* ps);

//展示信息
void ShowContact(const Contact* ps);

//保存通讯录
void SaveContact(Contact* ps);

//清空通讯录信息
void EmptyContact(Contact* ps);

//释放动态内存
void FreeContact(Contact* ps);//free作动词有释放的意思

//加载通讯录信息
void LoadContact(Contact* ps);

总结

这次的小项目在实现过程中我也遇到了一些问题还有待改善,同时也注意到了很多细节,下面我将一 一总结出来

1.比如查找特定联系人时如果有重名情况该怎么处理

2.结构体内让占用内存小的变量聚集在一起,更节省空间

3.结构体指针类型的活用

3.动态开辟的内存记得释放

4.打开文件后最后记得关闭及赋成空指针

5.分配动态内存及文件操作都要进行判断减少Debug次数

5.能不能采用MySQL数据库提高项目的安全性

6.……

好了,这次的小项目分享到这里,这是我第一次写博客,如果有任何问题欢迎大佬指正,我也特别希望大家能够喜欢我创作的内容!!
by_派小猩

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值