完美C语言通讯录(含代码)

C语言通讯录大作业,支持永久数据储存,无内存浪费。

相关部分介绍

本工程用到库文件stdio.h 、stdlib.h 、string.h 、error.h
对于内存的管理使用了动态内存分配,每存入一个人的信息,就分配相应大小的空间。
相对于其他工程关闭程序后就会丢失信息,本工程支持文件操作,关闭系统时会将录入的信息写入一个contact.txt文件中,下次打开系统时又会录入信息。

代码详解

contact.h

项目头文件,声明了两个结构体

struct contact
{
	char name[8];	//姓名
	char sex[8];	//性别
	int age;		//年龄
	char ID[12];	//电话
};

struct NumofCon
{
	int Num;	//作用是表示现在有几个人的信息被存到通讯录中,方便开辟内存
	struct contact p[];//柔性数组,可以使用动态内存开辟空间
};

contact.c

这个源文件是代码的主要部分,相关功能的函数全都存储在这里

第一个函数:通讯录初始化函数
struct NumofCon* Contact_Init(void)
{
	struct NumofCon* ps = (struct NumofCon*) malloc(4+32*1);
	if(ps == NULL)
	{
		printf("%s\n",strerror(errno));
	}
	ps->Num = 0;
	return ps;
}

该函数返回一个struct NumofCon型的指针,对应第二个声明的结构体第一行就是这个代码最重要的一部分,开辟一个4+321字节大小的内存,并把他的指针传给ps,如果开辟失败就返回空指针,printf就会打印失败原因。注意,strerror(errno);函数使用需要应用errno.h头文件。
开辟字节的大小要取决于struct NumofCon结构体的大小。
将ps指向的结构体里的Num成员赋值成0,因为还没有信息被储存。

第二个函数:向通讯录中增加信息
struct NumofCon* contact_add(struct NumofCon* ps)
{
	ps->Num++;
	struct NumofCon* ps2 = (struct NumofCon*) realloc(ps,4+32*(ps->Num));
	if(ps2 == NULL)
	{
		printf("%s\n",strerror(errno));
	}
	int i = ps2->Num-1;
	printf("请输入姓名:");
	scanf("%s",ps2->p[i].name);
	printf("请输入姓别:");
	scanf("%s",ps2->p[i].sex);
	printf("请输入年龄:");
	scanf("%d",&(ps2->p[i].age));
	printf("请输入电话:");
	scanf("%s",ps2->p[i].ID);
	ps = ps2;
	ps2 = NULL;
	return ps;
}

Num加一,告诉系统有新人要存入。Num的值取决于通讯录内有多少人。
使用realloc函数调整开辟内存的大小,并把新的地址传给ps2,用if语句判断是否开辟成功。
定义i作为柔性数组的下标,下标的值为Num-1。
接下来就是信息录入过程,使用了结构体嵌套调用,没有什么可讲的。
我重点要说一下最后几行,为什么要多定义一个ps2来储存地址呢?这和realloc函数的特性有关。realloc函数是调整动态内存空间大小的函数,他的参数有两个,一个是你要修改的地址,二是要修改的大小。假如要增加十个字节,如果ps指向的空间后面有足够大小的空间,那新修改的地址就不会改变,但是如果后面空间不够增加10个字节,系统就会在其他位置另起炉灶,并把原先的内容拷贝到新的地址里,并且释放原来的空间。当内存调整失败,返回空指针,直接用ps接受,那我们就没法找回原先空间的地址,程序崩溃。所以ps2是一个保险选项,防止由于内存开辟失败导致原有空间位置丢失。当函数执行到最后,ps2的使命结束,在置为空指针,防止越界访问。

第三个函数,查询,第四个函数,打印所有成员
void contact_find(struct NumofCon* ps)
{
	int i=0;
	char name[8];
	printf("请输入要寻找的人物姓名:");
	scanf("%s",name);
	while(strcmp(name,ps->p[i].name))
	{
		i++;
	}
	printf("姓名:%s\n",ps->p[i].name);
	printf("姓别:%s\n",ps->p[i].sex);
	printf("年龄:%d\n",ps->p[i].age);
	printf("电话:%s\n",ps->p[i].ID);
}

void contact_Printall(struct NumofCon* ps)
{
	for(int i = 0;i<ps->Num; i++)
	{
		printf("Num:%d\n",i+1);
		printf("姓名:%s\n",ps->p[i].name);
		printf("姓别:%s\n",ps->p[i].sex);
		printf("年龄:%d\n",ps->p[i].age);
		printf("电话:%s\n",ps->p[i].ID);
	}
}

没有什么好说的,只有查询函数用了一个库函数strcmp,声明在string.h中

第五个函数,删除
struct NumofCon* contact_delete(struct NumofCon* ps)
{
	int i=0;
	char name[8];
	printf("请输入要删除的人物姓名:");
	scanf("%s",name);
	while(strcmp(name,ps->p[i].name))
	{
		i++;
		if(i>ps->Num-1)
		{
			printf("没有此人信息\n");
			return ps;
		}
	}
	for(;i < ps->Num; i++)
	{
		strcpy(ps->p[i].name, ps->p[i+1].name);
		strcpy(ps->p[i].sex, ps->p[i+1].sex);
		ps->p[i].age = ps->p[i+1].age;
		strcpy(ps->p[i].ID, ps->p[i+1].ID);
	}
	ps->Num = ps->Num - 1;
	struct NumofCon* ps2 = (struct NumofCon*) realloc(ps,4+32*(ps->Num));
	if(ps2 == NULL)
	{
		printf("%s\n",strerror(errno));
	}
	ps = ps2;
	ps2 = NULL;
	printf("%s的信息已经移除\n",name);
	return ps;
}

这个函数的重点是删除一个人后要把ps->Num的值减一,并且调整内存大小,后面成员的位置依次向前36个字节

到这里通讯录的主要功能已经完成,现在要做数据的永久储存,也就是把信息导入文件中,防止关闭程序后信息丢失。

保存数据到contact.txt文件中
void contact_serve(struct NumofCon* ps)
{
	FILE* pf = fopen( "contact.txt", "w");
	int i = 0;
	if(pf == NULL)
	{
		printf("%s\n",strerror(errno));
	}
	while(i < ps->Num)
	{
		fprintf(pf, "%d ",i+1);
		fprintf(pf, "%s ",ps->p[i].name);
		fprintf(pf, "%s ",ps->p[i].sex);
		fprintf(pf, "%d ",ps->p[i].age);
		fprintf(pf, "%s\n",ps->p[i].ID);
		i++;
	}
	fclose(pf);
}

注意,要在代码当前路径建立一个文件contact.txt,否则程序报错。

读取文件信息
struct NumofCon* Contact_read(struct NumofCon* ps)
{
	struct contact file;
	int Num = 1;
	int check = Num-1;
	FILE* pf = fopen("contact.txt", "r");
	if(pf == NULL)
	{
		printf("%s\n",strerror(errno));
	}
	char ch = fgetc(pf);
	if(ch == EOF)
		Num = 0;
	rewind(pf);

	while(Num)
	{
		fscanf(pf, "%d", &Num);
		if(check == Num)
			break;
		check = Num;
		fscanf(pf, "%s", file.name);
		fscanf(pf, "%s", file.sex);
		fscanf(pf, "%d", &(file.age));
		fscanf(pf, "%s", file.ID);
		ps = (struct NumofCon*) realloc(ps,4+32*Num);
		ps->Num = Num;
		strcpy(ps->p[Num-1].name, file.name);
		strcpy(ps->p[Num-1].sex, file.sex);
		ps->p[Num-1].age = file.age;
		strcpy(ps->p[Num-1].ID, file.ID);
	}
	fclose(pf);
	return ps;
}

上面两个代码涉及到文件操作系统,较为复杂,篇幅原因,我会新写一篇文章来介绍。

main.c

将上面代码都放在头文件声明后就可以写主函数了,该系统为模块化,主函数相对简单

#include <stdio.h>
#include "contact.h"

int main()
{
	int i;
	struct NumofCon* Con = Contact_Init();
	Con = Contact_read(Con);

	do{
		system("pause");
		system("cls");
		printf("------------CONTACT-------------\n");
		printf("-----1.添加---------2.查询------\n");
		printf("-----3.显示---------4.删除------\n");
		printf("------------0.退出--------------\n");
		printf("--------------------------------\n");
		printf("输入指令");
		scanf("%d",&i);
		if(i == 1)
			Con = contact_add(Con);
		if(i == 2)
			contact_find(Con);
		if(i == 3)
			contact_Printall(Con);
		if(i == 4)
			Con = contact_delete(Con);
	}while(i);

	contact_serve(Con);

	return 0;
}

功能演示这是记事本文件,现在是空的

添加一个人
查询一个人

添加多个信息
按0退出
一定要通过指令0退出,不然无法保存信息
现在我们打开文件看看

信息已经录入
再次打开程序,直接使用3命令打印

我们没有录入信息,可是系统直接读取了信息,是因为系统将文件里的信息读取了。
也可以直接在contact文件中添加人物,但要遵守格式。

这就是相关代码的讲解,我会把工程上传,需要自取。
https://download.csdn.net/download/Mr_Hanc_Tiskor/15533285

有关文件的那两个函数和柔性数组我也会在下一篇文章讲解。
如果本文对你有帮助,别忘了点赞哦。欢迎大家留言讨论与大佬们的建议。

  • 17
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
当然可以帮您写一个简单的 C 语言通讯录代码。以下是一个示例: ```c #include <stdio.h> #include <string.h> struct Contact { char name[50]; char phone[20]; }; int main() { struct Contact contacts[100]; int numContacts = 0; int choice; do { printf("\n--- 通讯录菜单 ---\n"); printf("1. 添加联系人\n"); printf("2. 显示所有联系人\n"); printf("3. 退出\n"); printf("请选择操作:"); scanf("%d", &choice); switch (choice) { case 1: if (numContacts < 100) { printf("\n--- 添加联系人 ---\n"); printf("请输入姓名:"); scanf("%s", contacts[numContacts].name); printf("请输入电话号码:"); scanf("%s", contacts[numContacts].phone); numContacts++; printf("联系人添加成功!\n"); } else { printf("通讯录已满,无法再添加联系人!\n"); } break; case 2: if (numContacts > 0) { printf("\n--- 所有联系人 ---\n"); for (int i = 0; i < numContacts; i++) { printf("姓名:%s\n", contacts[i].name); printf("电话:%s\n", contacts[i].phone); printf("--------------------\n"); } } else { printf("通讯录为空!\n"); } break; case 3: printf("感谢使用通讯录程序,再见!\n"); break; default: printf("无效的选择,请重新输入!\n"); break; } } while (choice != 3); return 0; } ``` 这个程序实现了一个简单的通讯录功能,用户可以选择添加联系人、显示所有联系人或退出程序。通讯录最多可以存储100个联系人的姓名和电话号码。您可以根据自己的需求进行修改和扩展。祝您编程愉快!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值