当前位置: 首页 > article >正文

C语言小项目——通讯录

功能介绍:

1.联系人信息:姓名+年龄+性别+地址+电话

2.通讯录中可以存放100个人的信息

3.功能:

1>增加联系人

2>删除指定联系人

3>查找指定联系人的信息

4>修改指定联系人的信息

5显示所有联系人的信息

6>排序(名字)

  我们将采用模块化设计,分为三个模块:

1. test.c         ———        测试通讯录

2. contact.c   ———        通讯录的声明

3. contact.h    ———       函数的声明

  首先,我们需要一个菜单,以及主函数选择功能的部分。

```test.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
 void menu()
{
    printf("*******************欢迎来到你的通讯录*******************\n");
    printf("**********1.添加联系人************2.删除联系人**********\n");
    printf("**********3.查找联系人************4.修改联系人**********\n");
    printf("**********5.显示联系人************6.联系人排序**********\n");
    printf("**********0.退出通讯录*********************************\n");
    printf("*******************欢迎来到你的通讯录*******************\n");
}
int main()
{
    int input = 0;
    do {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
 
    switch (input)
    {
    case 1:
        break;
    case 2:
        break;
    case 3:
        break;
    case 4:
        break;
    case 5:
        break;
    case 6:
        break;
    case 0:
        printf("退出通讯录");
        break;
    default:
        printf("选择错误\n");
        break;
    }
   } while (input);
	return 0;
}
```
  • main函数中,使用do-while循环不断调用menu函数显示菜单,并使用scanf函数获取用户的输入。然后通过switch语句根据用户的输入执行相应的操作,如果输入为0,则输出 “退出通讯录” 并结束程序;如果输入为其他值,则输出 “选择错误”。

那么通讯录中肯定需要人的信息,那么这些人的信息,我们可以把他封装成一个结构体。我们将这些类型信息放进头文件中,在这里我们将它放进已经创建好的contact.h中。

```contact.h
//人的信息
typedef struct Peopleinform
{
	char name[40];
	int age;
	char sex[5];
	char addr[20];
	char telephone[20];
}Peopleinform;
```

在这里,我们定义了一个名为Peopleinform的结构体类型,用于存储人员的信息。我们通过使用typedef关键字,可以为这个结构体类型定义一个别名Peopleinform,这样在后续的代码中就可以直接使用Peopleinform来声明该类型的变量,而不需要每次都写完整的struct Peopleinform

我们继续往下写,接下来我们创建通讯录,我们可以声明一个名为data的数组,数组的元素类型为Peopleinform结构体,当然我们在这里必须添加contact.h头文件才能使用它。代码部分如下:

```test.c
#include<stdio.h>
#include"contact.h"
/* --省略void menu部分--*/
int main()
{
    int input = 0;
    //创建通讯录
    Peopleinform data[100];
    do {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
    
    /*-- 省略switch部分 --*/
        } while (input);
    return 0;
}
```

 在我们的项目中,自己创建的头文件通常用双引号''"包裹起来,这样我们就可以在.c文件中使用它啦!当然,我们如果把这个通讯录存放人的信息的容量,以及可以显示的当前创建的人的信息封装起来,变成一个结构体。为了方便之后修改我们增加一个预处理器指令#define MAX 100

```contact.h
#define MAX 100
typedef struct Contact
{
	Peopleinform data[MAX];//存放人的信息的容量
	int sz;//当前存放信息的个数
}Contact;
```

那么我们如果想在主函数中使用,只需要创建一个名为conContact类型的对象。这样就可以使用con来存储和操作通讯录相关的数据了。接着我们初始化通讯录。并在contact.h头文件中为他声明。

```test.c
int main()
{
    int input = 0;
    //创建通讯录
    Contact con;//创建一个名为con的Contact对象
    //初始化通讯录
    InitContact(&con);
    do {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        /*-- 省略switch部分 --*/
    } while (input);
```
```contact.h
void InitContact(Contact *pc);
```

接下来,contact.c文件终于出场了,由于我们在contact.h头文件声明过void InitContact(Contact *pc); 接下来,我们就可以在contact.c直接使用它。

我们给这个Contact结构体的函数初始化一下:

```contact.c
#include"contact.h"
void InitContact(Contact* pc)
{
    pc->sz=0;
   memset(pc->data,0,sizeof(pc->data));
}
```

这里我们选择使用memset函数进行初始化,

(注:memset函数是 C 标准库中的一个函数,定义在<string.h>头文件中。它的作用是将一段内存区域设置为指定的值。函数原型为void *memset(void *s, int c, size_t n),其中s是指向要填充的内存块的指针,c是要设置的值,n是要填充的字节数。) 

紧接着,我们在Switch()语句中,加入我们目前需要的语句,我们现在来写添加联系人模块。

添加联系人模块

```contact.h
//增加联系人
void AddContact(Contact* pc);
```
```contact.c
void AddContact(Contact* pc)
{
	if (pc->sz == MAX)
	{
		printf("通讯录已满!无法添加!\n");
		return;
	}
	//增加一个人的信息
	printf("请输入名字:>");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:>");
	scanf("%s", &pc->data[pc->sz].age);
	printf("请输入性别:>");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入地址:>");
	scanf("%s", pc->data[pc->sz].addr);
	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sz].telephone);
	pc->sz++;
}
```

(注:在InitContactAddContact函数中,pc用于访问和修改调用者提供的Contact结构体实例。当调用这些函数时,传递的是Contact结构体变量的地址,函数内部通过这个指针来操作外部传入的结构体。)

pc-sz++; 的作用 

假设 sz 初始值为 5,执行 pc->sz++; 后,sz 的值变为 6 ,表示通讯录中联系人的数量从 5 个增加到了 6 个。 这对于跟踪通讯录中实际存储的联系人数量非常重要,在后续的操作,如显示联系人列表、检查通讯录是否已满等功能中,都依赖这个计数。

 显示联系人模块

显示联系人模块也是一样,我们现将函数声明放在头文件当中,

void ShowContact(const Contact* pc);

然后我们用一个for循环遍历pc->data数组,其中,pc->data数组存储了所有联系人的信息,循环条件i < pc->sz确保只遍历已存储联系人的部分,pc->sz表示当前通讯录中实际存储的联系人数量。

```contact.c
void ShowContact(Contact* pc)
{
	int i = 0;
    printf("%s\t%-5s\t%-5s\t%-5s\t%-5s\t\n", "姓名","年齡","性別","地址","電話");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%s\t%d\t%s\t%s\t%s\t",pc->data[i].name,
									  pc->data[i].age,
									  pc->data[i].sex,
									  pc->data[i].addr,
									  pc->data[i].telephone);
	}
}
```

这样,我们就基本完成了这个显示联系人的设计啦!那么紧接着,我们如果想要删除这个指定的联系人,该怎么办呢?和上面一样,我们先在头文件中添加一个声明。

void DelContact(Contact* pc);

接着,我们在contact.c文件中去构建这个删除联系人模块,

删除联系人模块

void DelContact(Contact* pc)
{
	if (pc->sz ==0)
	{
		printf("无可删除的联系人");
		return;
	}
	//删除
	//找到要删除的人
	printf("请输入要删除的人的名字:");
	scanf("%s", name);
	int i = 0;
	int del = 0;
	for (i = 0; i<pc->sz; i++)
	{
		if(strcmp(pc->data[i].name,name))==0
		{
			del = i;
			break;
		}
		//删除
		for (i = 0; i < pc->sz; i++)
		{
			pc->data[i] = pc->data[i + 1];
		}
		pc->sz--;
		printf("删除成功");
	}
}

当我们通讯录里面没有联系人的时候,我们输出“无可删除的联系人”。接着,我们使用 for 循环遍历联系人列表,使用 strcmp 函数比较每个联系人的名字和输入的名字,如果相等则将该元素的索引存储在 del 中并跳出循环。

那么接下来,我们可以发现的是,无论是删除模块、查找模块和修改模块中,我们都需要先找到联系人,才能进行下一步的操作,既然都需要,我们似乎就可以把这个查找部分封装成一个函数,

// 根据姓名查找联系人在数组中的位置,如果找到返回对应索引,未找到返回 -1
int FINDBY_NAME(const Contact* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0) // 比较字符串是否相等
		{
			return i; // 找到返回索引
		}
	}
	return -1; // 未找到返回 -1
}

 替换后代码如下:

// 删除联系人的函数
void DelContact(Contact* pc)
{
	if (pc->sz == 0)
	{
		printf("没有联系人可删除\n");
		return;
	}
	// 输入要删除的联系人姓名
	char name[40] = { 0 };
	printf("请输入要删除的联系人姓名: ");
	scanf("%s", name);

	int ret = FINDBY_NAME(pc, name);
	if (ret == -1)
	{
		printf("要删除的联系人不存在\n");
		return;
	}

	// 删除操作,将后面的元素依次往前移
	for (int i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

我们来看查找联系人模块,

查找联系人模块

void SerContact(const Contact* pc)
{
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找人的名字:");
		scanf("%s",name);
	int pos = FINDBY_NAME(pc, name);
	if (-1 == pos)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//打印信息
	printf("%s\t%-5s\t%-5s\t%-5s\t%-5s\t\n", "姓名", "年齡", "性別", "地址", "電話");
	printf("%s\t%-5d\t%-5s\t%-5s\t%-5s\t\n", pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].addr,
		pc->data[pos].telephone);
}

 我们查找模块,首先输入要查找的联系人姓名,调用 FINDBY_NAME 函数查找该联系人的位置,如果不存在则提示联系人不存在并返回。否则,打印该联系人的详细信息。

紧接着,我们再来看修改联系人,

修改联系人模块

//修改联系人
void ReviContact(Contact* pc)
{
	char name[NAME_MAX] = { 0 };
	printf("请输入要修改人的名字:");
		scanf("%s", name);
	int pos = FINDBY_NAME(pc, name);
	if (-1 == pos)
	{
		printf("要修改的人不存在\n");
		return;
	}
	printf("请输入名字:>");
	scanf("%s", pc->data[pos].name);
	printf("请输入年龄:>");
	scanf("%d", &pc->data[pos].age);
	printf("请输入性别:>");
	scanf("%s", pc->data[pos].sex);
	printf("请输入地址:>");
	scanf("%s", pc->data[pos].addr);
	printf("请输入电话:>");
	scanf("%s", pc->data[pos].telephone);

	printf("修改完成\n");
}

我们想要修改联系人,首先肯定需要找到这个联系人,所以我们首先要查找,输入要修改的联系人姓名,调用FINDBY_NAME函数可以查找该联系人的位置,如果不存在则提示联系人不存在并返回。否则,依次输入新的联系人信息。

排序联系人模块

最后一个模块,就是对这些联系人进行排序,这里使用使用冒泡排序算法,比较相邻联系人的姓名,如果前一个联系人的姓名大于后一个联系人的姓名,则交换它们的位置。

// 排序联系人(按姓名升序排序)
void SortContact(Contact* pc)
{
	int i, j;
	Peopleinform temp;
	for (i = 0; i < pc->sz - 1; i++)
	{
		for (j = 0; j < pc->sz - i - 1; j++)
		{
			if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
			{
				temp = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = temp;
			}
		}
	}
	printf("联系人已按姓名排序\n");
}

strcmp 是 C 语言标准库 <string.h> 中的一个字符串比较函数,用于比较两个字符串的大小。

函数原型int strcmp(const char *str1, const char *str2);

在 SortContact 函数中,strcmp(pc->data[j].name, pc->data[j + 1].name) > 0 表示如果 pc->data[j].name 这个字符串在字典序上大于 pc->data[j + 1].name 这个字符串,就交换这两个联系人的信息,从而实现按姓名排序的功能。

源代码如下:

```contact.h
#pragma once
#include<stdio.h>
#include<string.h>
#define MAX 100
#define NAME_MAX 40  // 定义 NAME_MAX 的大小
// 个人信息
typedef struct Peopleinform
{
    char name[40];
    int age;
    char sex[5];
    char addr[20];
    char telephone[20];
}Peopleinform;
typedef struct Contact
{
    Peopleinform data[MAX];// 存储个人信息的数组
    int sz;// 当前存储信息的数量
}Contact;

// 初始化通讯录
void InitContact(Contact* pc);
// 添加联系人
void AddContact(Contact* pc);
// 删除联系人
void DelContact(Contact* pc);
// 查找联系人
void SerContact(const Contact* pc);
// 修改联系人
void ReviContact(Contact* pc);
// 排序联系人
void SortContact(Contact* pc);
// 显示联系人
void ShowContact(const Contact* pc);
```
```contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"
void InitContact(Contact* pc)
{
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}
void AddContact(Contact* pc)
{
	char name[NAME_MAX] = { 0 };
	if (pc->sz == MAX)
	{
		printf("通讯录已满!无法添加!\n");
		return;
	}
	//增加一个人的信息
	printf("请输入名字:>");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:>");
	scanf("%d", &pc->data[pc->sz].age);
	printf("请输入性别:>");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入地址:>");
	scanf("%s", pc->data[pc->sz].addr);
	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sz].telephone);
	pc->sz++;
}

// 根据姓名查找联系人在数组中的位置,如果找到返回对应索引,未找到返回 -1
int FINDBY_NAME(const Contact* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0) // 比较字符串是否相等
		{
			return i; // 找到返回索引
		}
	}
	return -1; // 未找到返回 -1
}

// 删除联系人的函数
void DelContact(Contact* pc)
{
	if (pc->sz == 0)
	{
		printf("没有联系人可删除\n");
		return;
	}
	// 输入要删除的联系人姓名
	char name[40] = { 0 };
	printf("请输入要删除的联系人姓名: ");
	scanf("%s", name);

	int ret = FINDBY_NAME(pc, name);
	if (ret == -1)
	{
		printf("要删除的联系人不存在\n");
		return;
	}

	// 删除操作,将后面的元素依次往前移
	for (int i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}
//查找联系人
void SerContact(const Contact* pc)
{
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找人的名字:");
		scanf("%s",name);
	int pos = FINDBY_NAME(pc, name);
	if (-1 == pos)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//打印信息
	printf("%s\t%-5s\t%-5s\t%-5s\t%-5s\t\n", "姓名", "年齡", "性別", "地址", "電話");
	printf("%s\t%-5d\t%-5s\t%-5s\t%-5s\t\n", pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].addr,
		pc->data[pos].telephone);
}
//修改联系人
void ReviContact(Contact* pc)
{
	char name[NAME_MAX] = { 0 };
	printf("请输入要修改人的名字:");
		scanf("%s", name);
	int pos = FINDBY_NAME(pc, name);
	if (-1 == pos)
	{
		printf("要修改的人不存在\n");
		return;
	}
	printf("请输入名字:>");
	scanf("%s", pc->data[pos].name);
	printf("请输入年龄:>");
	scanf("%d", &pc->data[pos].age);
	printf("请输入性别:>");
	scanf("%s", pc->data[pos].sex);
	printf("请输入地址:>");
	scanf("%s", pc->data[pos].addr);
	printf("请输入电话:>");
	scanf("%s", pc->data[pos].telephone);

	printf("修改完成\n");
}
// 排序联系人(按姓名升序排序)
void SortContact(Contact* pc)
{
	int i, j;
	Peopleinform temp;
	for (i = 0; i < pc->sz - 1; i++)
	{
		for (j = 0; j < pc->sz - i - 1; j++)
		{
			if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
			{
				temp = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = temp;
			}
		}
	}
	printf("联系人已按姓名排序\n");
}

// 显示所有联系人信息的函数
void ShowContact(const Contact* pc)
{
	int i = 0;
	printf("%s\t%-5s\t%-5s\t%-5s\t%-5s\t\n", "姓名", "年龄", "性别", "地址", "电话");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%s\t%d\t%s\t%s\t%s\n", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].addr,
			pc->data[i].telephone);
	}
}
```
```test.c
#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"
 void menu()
{
    printf("*******************欢迎来到你的通讯录*******************\n");
    printf("**********1.添加联系人************2.删除联系人**********\n");
    printf("**********3.查找联系人************4.修改联系人**********\n");
    printf("**********5.显示联系人************6.联系人排序**********\n");
    printf("**********0.退出通讯录**********************************\n");
    printf("*******************欢迎来到你的通讯录*******************\n");
}
int main()
{
    int input = 0;
    //创建通讯录
    Contact con;//创建一个名为con的Contact对象
    //初始化通讯录
    InitContact(&con);
    do {
        menu();
        printf("请选择:>");
        if (scanf("%d", &input) != 1) {
            // 处理输入错误的情况,例如提示用户重新输入
            printf("输入错误,请重新输入\n");
            // 清空输入缓冲区
            while (getchar() != '\n');
            
            continue;
        }
    
    switch (input)
    {
    case 1:
        AddContact(&con);
        break;
   case 2:
        DelContact(&con);
        break;
   case 3:
        SerContact(&con);
        break;
    case 4:
        ReviContact(&con);
        break;
    case 5:
        ShowContact(&con);
        break;
    case 6:
        SortContact(&con);
    case 0:
        printf("退出通讯录");
        break;
    default:
        printf("选择错误\n");
        break;
    }
   } while (input!=0);
}
```


http://www.kler.cn/a/513817.html

相关文章:

  • HTML 表单和输入标签详解
  • Flink 使用 Kafka 作为数据源时遇到了偏移量提交失败的问题
  • Kafka-常见的问题解答
  • 【重庆市乡镇界】面图层shp格式arcgis数据乡镇名称和编码wgs84坐标无偏移内容测评
  • 游戏引擎学习第80天
  • 阿里云 Serverless 助力盟主直播:高并发下的稳定性和成本优化
  • PIC单片机设置bootloader程序和app程序地址方法
  • 海康C++开发面试题及参考答案
  • Flink 的核心特点和概念
  • 基于Redis实现短信验证码登录
  • 解决 Django 5.1 中的 TemplateSyntaxError 错误
  • 基于微信小程序的手机银行系统
  • 32V/4A,降压DCDC转换器CP8384百分百占空比输出ESOP8封装,可适用HUB等电路设计
  • 物联网网关Web服务器--CGI开发实例BMI计算
  • C# 以管理员方式启动程序全解析
  • 如何在oracle关闭情况下如何修改spfile的参数
  • 三分钟内快速完成MySQL到达梦数据库的迁移
  • 深度学习中的通道(Channel)概念详解
  • H3CNE-17-DHCP动态主机配置协议
  • CapsNet :用于图像识别的神经网络结构,包含胶囊层
  • 用edge浏览器追剧音量太小?安装音量增强器可解忧
  • 【Java计算机毕业设计】基于SSM圣宠宠物领养网站【源代码+数据库+LW文档+开题报告+答辩稿+部署教程+代码讲解】
  • Word2Vec如何优化从中间层到输出层的计算?
  • 逐笔成交逐笔委托Level2高频数据下载和分析:20250121
  • Next.js 实战 (十):中间件的魅力,打造更快更安全的应用
  • 【时时三省】(C语言基础)文件的打开和关闭