C - 创建初级通讯录(详细解析一)

目录

一.代码框架

test.c

contact.h

优化

二.初始化通讯录

三、功能实现

1.增加联系人

5.显示通讯录中的信息

​编辑

优化:

2.删除指定联系人

[查找函数 contact.c](#查找函数 contact.c)

[删除 contact.c](#删除 contact.c)

3.查找指定联系人

4.修改指定联系人

四.整体代码

test.c

contact.h

contact.c


实现以下内容:

  • 人的信息:姓名+年龄+性别+地址+电话
  • 通讯录中可以存放100个人的信息
  • 功能:
  1. 增加联系人
  2. 删除指定联系人
  3. 查找指定联系人的信息
  4. 修改指定联系人的信息
  5. 显示所有联系人的信息
  6. 排序(名字、年龄)

通过3个文件实现:

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

  2. contact.c ------ 通讯录的实现

  3. contact.h ------ 函数的声明、类型的定义和声明



一.代码框架

test.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h" // 自己创建的头文件要用 " "

void menu()
{
	printf("************************************\n");
	printf("******  1. add    2. del      ******\n");
	printf("******  3. search 4. modify   ******\n");
	printf("******  5. show   6. sort     ******\n");
	printf("******  0. exit               ******\n");
	printf("************************************\n");
}

int main()
{
	int input = 0;
	//创建通讯录
	PeoInfo data[100];

	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;
}

contact.h

cpp 复制代码
#pragma once
#include <stdio.h>

//人的信息
typedef struct PeoInfo
{
	char name[20];
	int age;
	char sex[5];
	char addr[30];// 地址
	char tele[12];// 电话11个字符,还要给 \0 留位置
}PeoInfo;// 类型复杂,重命名

优化

疑问:添加联系人进去,放哪个下标位置?
答:必须知道已经放进去了几个,所以创建变量 sz

test.c

cpp 复制代码
int main()
{
	int input = 0;
	//创建通讯录
	PeoInfo data[100];
    int sz;
......

2个变量太分散?再分装到结构体

contact.h

cpp 复制代码
#pragma once
#include <stdio.h>

#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define TELE_MAX 12

//人的信息
typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char addr[ADDR_MAX];
	char tele[TELE_MAX];
}PeoInfo;

typedef struct Contact
{
	PeoInfo data[MAX];//存放人的信息
	int sz;//当前已经存入联系人的个数
}Contact; // 重命名

test.c

cpp 复制代码
int main()
{
	int input = 0;
	//创建通讯录
	Contact con;
......

二.初始化通讯录

不这样:Contact con = { 0 } ; 太粗暴。

要细致化,模块化。初始化时若自己有想法,按自己的逻辑,通过分装函数来实现。

test.c

cpp 复制代码
int main()
{
	int input = 0;
	//创建通讯录
	Contact con;
	//初始化通讯录
	InitContact(&con);
......

contact.h

cpp 复制代码
#pragma once
#include <stdio.h>
#include <assert.h>
#include <string.h>

#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define TELE_MAX 12

//人的信息
typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char addr[ADDR_MAX];
	char tele[TELE_MAX];
}PeoInfo;

typedef struct Contact
{
	PeoInfo data[100];//存放人的信息
	int sz;//当前已经存入联系人的个数
}Contact;

//初始化通讯录 -- 函数声明
void InitContact(Contact* pc);

这里涉及到结构体传参

我们要传地址,每个人的信息就很大,而且有100个人。传值的话要拷贝,浪费栈帧空间,效率低下。

Contact con ; con 的类型 Contact 。地址传给 pc ,所以 pc 的类型为Contact *

contact.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"

void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}

memset:内存设置函数,以字节为单位来设置内存中的数据。

三个参数依次是:要设置的起始地址,要设置的值,设置多少字节的值


疑问:pc->data 这不是数组名**(传过来的,比如数组传参数组接收)吗?拿 sizeof 传参算的结果是4
答:InitContact (&con) ; 传的是结构体的地址,结构体里面包含了一个数组。(传的不是数组本身
)**

数组传参的时候传过去数组名是首元素地址,那时候会降级为指针。

这里传的是结构体的地址,进来之后通过结构体的地址找到它所指向的对象里面的 data 数组。

并且把数组名单独放在 sizeof 内部,属于2个特殊情况之一。这时可以通过这样的方式求整个数组的大小,单位:字节

三、功能实现

1.增加联系人

涉及修改通讯录,依然传地址。

先判断联系人是否满了。

放进去,sz++。放到那呢?

没有联系人,增加的放到下标为0;有1个,增加的风道下标为1;放到下标为 sz 的位置


test.c

cpp 复制代码
		case 1:
			AddContact(&con);
			break;

contact.h

cpp 复制代码
//增加联系人 -- 函数声明
void AddContact(Contact* pc);

contact.h

cpp 复制代码
void AddContact(Contact* pc)
{
	assert(pc);
	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].tele);

	pc->sz++;
}

**解析:**放到 pc 所指向的结构体通讯录里面 data 数组里面,下标为 sz 的位置。
**sz 怎么找?**pc 所指向的结构体通讯录里面的 sz

**. name?**data[ ] 是data 数组里面的一个元素,是 PeoInfo 的数据。放名字的话,放到 name 里面去

**不 &?**name 本来就是数组,数组名本来就是地址,所以不用 &。
但 age 是变量,要 &



5.显示通讯录中的信息

contact.c

cpp 复制代码
void ShowContact(const Contact* pc)
{
	assert(pc);
	int i = 0;
	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].tele);
	}
}


优化:

%20s:最多打印20个字符 一个汉字占2个字节


右对齐:

cpp 复制代码
printf("%20s\t%4d\t%5s\t%20s\t%12s\n", ......

左对齐:

cpp 复制代码
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", ......

加上列名 contact.c

cpp 复制代码
void ShowContact(const Contact* pc)
{
	assert(pc);
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].addr,
			pc->data[i].tele);
	}
}


2.删除指定联系人

先判断通讯录是否为空

删除, 到谁,去删除; 查找, 到谁,去查找; 修改, 到谁,去修改

这些函数都会用到查找。把查找提取出来,分装成函数。遍例查找

怎么删除?
(1)后面的往前覆盖,sz--。 挪动的数据多,考虑效率能不能接受。(我们演示这个)
(2)最后一个覆盖,sz--。 考虑顺序变动能不能接受。


查找函数 contact.c

cpp 复制代码
int FindByName(const Contact* pc, char name[])
{
	assert(pc);

	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

删除 contact.c

cpp 复制代码
void DelContact(Contact* pc)
{
	assert(pc);

	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	//查找
	printf("请输入要删除的人的名字:>");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (-1 == ret)
	{
		printf("要删除的人不存在\n");
		return;
	}

	int i = 0;
	//删除
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

效果:

疑问:最后一个联系人还在呀!不管了吗?
答:sz-- 后,访问不到了。在不在效果一样。



3.查找指定联系人

contact.c

cpp 复制代码
void SearchContact(const Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (-1 == pos)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//打印信息
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
	printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].addr,
		pc->data[pos].tele);
}

效果:



4.修改指定联系人

contact.c

cpp 复制代码
void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要修改人的名字:");
	scanf("%s", name);
	int pos = FindByName(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].tele);

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

效果:



四.整体代码

test.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"

void menu()
{
	printf("************************************\n");
	printf("******  1. add    2. del      ******\n");
	printf("******  3. search 4. modify   ******\n");
	printf("******  5. show   6. sort     ******\n");
	printf("******  0. exit               ******\n");
	printf("************************************\n");
}

int main()
{
	int input = 0;
	//创建通讯录
	Contact con;
	//初始化通讯录
	InitContact(&con);

	do
	{
		menu();
		printf("请输入:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			break;
		case 3:
			SearchContact(&con);
			break;
		case 4:
			ModifyContact(&con);
			break;
		case 5:
			ShowContact(&con);
			break;
		case 6:
			break;
		case 0:
			printf("退出通讯录");
			break;
		default:
			printf("输入错误\n");
			break;
		}

	} while (input);

	return 0;
}

contact.h

cpp 复制代码
#pragma once
#include <stdio.h>
#include <assert.h>
#include <string.h>

#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define TELE_MAX 12

//人的信息
typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char addr[ADDR_MAX];
	char tele[TELE_MAX];
}PeoInfo;

typedef struct Contact
{
	PeoInfo data[MAX];//存放人的信息
	int sz;//当前已经存入联系人的个数
}Contact;

//初始化通讯录 -- 函数声明
void InitContact(Contact* pc);

//增加联系人 -- 函数声明
void AddContact(Contact* pc);

//显示通讯录中的信息 -- 函数声明
void ShowContact(const Contact* pc);

//删除指定联系人
void DelContact(Contact* pc);

//查找指定联系人
void SearchContact(const Contact* pc);

//修改指定联系人
void ModifyContact(Contact* pc);

contact.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"

void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}

void AddContact(Contact* pc)
{
	assert(pc);
	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].tele);

	pc->sz++;
}

void ShowContact(const Contact* pc)
{
	assert(pc);
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].addr,
			pc->data[i].tele);
	}
}

int FindByName(const Contact* pc, char name[])
{
	assert(pc);

	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

void DelContact(Contact* pc)
{
	assert(pc);

	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	//查找
	printf("请输入要删除的人的名字:>");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (-1 == ret)
	{
		printf("要删除的人不存在\n");
		return;
	}

	int i = 0;
	//删除
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

void SearchContact(const Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (-1 == pos)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//打印信息
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
	printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].addr,
		pc->data[pos].tele);
}

void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要修改人的名字:");
	scanf("%s", name);
	int pos = FindByName(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].tele);

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

通讯录排序见小编下一篇文章

这就是我们当前写的通讯录,还是比较简单,粗糙的。

信息并没有存储起来。下一次运行时,上一次存的信息全都没了。

因为程序运行时,输入的数据是放到内存当中的。

怎么办呢?后期小编再给大家讲

相关推荐
i love you china1 小时前
深入理解指针5
c语言
卷卷的小趴菜学编程2 小时前
算法篇-------------双指针法
c语言·开发语言·c++·vscode·算法·leetcode·双指针法
XWXnb62 小时前
C语言:多线程
c语言·开发语言
似水এ᭄往昔3 小时前
【C语言】文件操作(2)
c语言·开发语言
GalaxyPokemon3 小时前
C/C++ 基础 - 回调函数
c语言·开发语言·c++
annekqiu4 小时前
MPLAB X IDE 环境中配置字的注意点
c语言·单片机
·醉挽清风·5 小时前
学习笔记—数据结构—二叉树(链式)
c语言·数据结构·c++·笔记·学习·算法
szpc16215 小时前
60V单通道高精度线性恒流LED驱动器防60V反接SOD123封装
c语言·开发语言·单片机·嵌入式硬件·计算机外设
Susea&5 小时前
数据结构初阶:单链表
c语言·开发语言·数据结构
婕婕天帝7 小时前
C语言:3.31
c语言·开发语言