文章目录
前言
个人写的通讯录C语言实现,望交流
版本①
一、main函数所在源文件:test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game0122.h"
// 实现一个通讯录:(不考虑相同名字)
// 通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址
// 提供方法:
// 1-添加联系人信息
// 2-删除指定联系人信息
// 3-查找指定联系人信息
// 4-修改指定联系人信息
// 5-显示所有联系人信息
// 6-清空所有联系人
// 7-以名字排序所有联系人
void Meun()
{
printf("--------------------------------------\n");
printf("----------0-退出----------------------\n");
printf("----------1-添加联系人信息------------\n");
printf("----------2-删除指定联系人信息--------\n");
printf("----------3-查找指定联系人信息--------\n");
printf("----------4-修改指定联系人信息--------\n");
printf("----------5-显示所有联系人信息--------\n");
printf("----------6-清空所有联系人------------\n");
printf("----------7-以名字排序所有联系人------\n");
printf("--------------------------------------\n");
}
int main()
{
// 创建一个数组,实际大小为1000的数组,如果直接将其作为通讯录,
// 则通讯录中已有多少数据是未知的,后续增删查改打印都无法实现
// list data[1000] = { 0 };
// 创建通讯录
contact con = { 0 };
// 初始化通讯录(也为之后的优化做铺垫)
Init(&con);
int input = 0;
do {
Meun();
printf("请输入您的选项\n");
scanf("%d", &input);
switch (input)
{
case 0:
printf("已退出/n");
break;
case 1:
// 传入结构体地址
Add(&con);
break;
case 2:
Del(&con);
break;
case 3:
Find(&con);
break;
case 4:
Amd(&con);
break;
case 5:
Print(&con);
break;
case 6:
Emp(&con);
break;
case 7:
Sort(&con);
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
二、相关函数定义源文件:game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game0122.h"
// 初始化通讯录
void Init(contact* p)
{
assert(p);
(p->sz) = 0;
memset(p->data, 0, sizeof(p->data));
}
// 判断通讯录是否满
int Is_Full(contact* p)
{
assert(p);
if ((p->sz) < MAX) {
return 1;
}
else {
return 0;
}
}
// 查询通讯录联系人
int Search(const contact* p, char name[]) //const保护通讯录不被改变
{
int i = 0;
for (i = 0; i < (p->sz); i++) {
if (0 == strcmp(name, (p->data[i]).name)) {
// 查询成功返回下标
return i;
}
}
// 循环结束仍未返回说明查询失败,返回-1
return -1;
}
// 1-添加联系人信息
void Add(contact* p)
{
assert(p);
// 判断通讯录是否存满
if (Is_Full(p)) {
printf("请输入您要添加的联系人信息:姓名、性别、年龄、电话、住址\n");
// 注:小心在输入age为int类型时,须带&,其余类似name本身就为数组名,是地址
scanf("%s %s %d %s %s", (p->data[(p->sz)]).name, (p->data[(p->sz)]).sex, \
& (p->data[(p->sz)]).age, (p->data[(p->sz)]).call, (p->data[(p->sz)]).address);
// 有效联系人数量加一并提示成功
(p->sz)++;
printf("增加联系人成功\n");
}
else {
printf("通讯录已满,无法继续添加\n");
}
}
// 2-删除指定联系人信息
void Del(contact* p)
{
assert(p);
// 输入需要删除第几个(从0开始数)联系人(p->sz),也可以根据需求输入名字,查找联系人,然后删除
/*int num = 0;
printf("请输入您需要删除的联系人序号(从0开始)\n");
scanf("%d", &num);*/
// 根据输入的名字,调用查找函数,根据函数返回值,如果找到再删除
char name[NAMEMAX] = { 0 };
printf("请输入您要删除的用户姓名\n");
scanf("%s", name);
// 返回值,如果查询到即为下标,未查询到返回-1
int ret = Search(p, name);
if (-1 == ret) {
printf("未查询到此人\n");
}
else {
printf("删除成功\n");
// 将该位置覆盖来删除
int i = 0;
/*for (i = ret; i < ((p->sz) - 1); i++) {
strcpy((p->data[i]).name, (p->data[i + 1]).name);
strcpy((p->data[i]).sex, (p->data[i + 1]).sex);
(p->data[i]).age = (p->data[i + 1]).age;
strcpy((p->data[i]).call, (p->data[i + 1]).call);
strcpy((p->data[i]).address, (p->data[i + 1]).address);
}*/
// 结构体变量很规律,可以相互赋值:(优化版本)
for (i = 0; i < (p->sz) - 1; i++) {
(p->data[i]) = (p->data[i + 1]);
}
// 有效联系人数量减一
(p->sz)--;
}
}
// 3 - 查找指定联系人信息
void Find(contact* p)
{
assert(p);
// 输入需要查找第几个(从0开始数)联系人(p->sz),也可以根据需求输入名字,查找联系人,然后打印
/*int i = 0;
printf("请输入您需要查找的联系人序号(从0开始)\n");
scanf("%d", &i);*/
// 根据输入的名字,调用查找函数,根据函数返回值,如果找到再打印
char name[NAMEMAX] = { 0 };
printf("请输入您要查找的用户姓名\n");
scanf("%s", name);
// 返回值,如果查询到即为下标,未查询到返回-1
int i = Search(p, name);
if (-1 == i) {
printf("未查询到此人\n");
}
else {
printf("查询成功\n");
printf("%s\t%s\t%s\t%s\t%s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%s\t%s\t%d\t%s\t%s\n", (p->data[i]).name, (p->data[i]).sex, \
(p->data[i]).age, (p->data[i]).call, (p->data[i]).address);
}
}
// 4 - 修改指定联系人信息
void Amd(contact* p)
{
assert(p);
// 判断通讯录是否为空,如果为空就无法删除并直接返回
if (0 == (p->sz)) {
printf("通讯录为空,无法删除\n");
return;
}
// 输入需要修改第几个(从0开始数)联系人(p->sz),也可以根据需求输入名字,查找联系人,然后修改
/*int i = 0;
printf("请输入您需要修改的联系人序号(从0开始)\n");
scanf("%d", &i);*/
// 根据输入的名字,调用查找函数,根据函数返回值,如果找到再修改
char name[NAMEMAX] = { 0 };
printf("请输入您要修改的用户姓名\n");
scanf("%s", name);
// 返回值,如果查询到即为下标,未查询到返回-1
int i = Search(p, name);
if (-1 == i) {
printf("未查询到此人\n");
}
else {
// 输入需要修改后的内容
printf("请输入你所修改后的信息:姓名、性别、年龄、电话、住址\n");
scanf("%s\t%s\t%d\t%s\t%s\n", (p->data[i]).name, (p->data[i]).sex, \
& (p->data[i]).age, (p->data[i]).call, (p->data[i]).address);
printf("修改完毕\n");
}
}
// 5-显示所有联系人信息
void Print(const contact* p) //const保护通讯录不被改变
{
assert(p);
// 按需求,也可以分开提示并输入
printf("%s\t%s\t%s\t%s\t%s\n", "姓名", "性别", "年龄", "电话", "住址");
int i = 0;
for (i = 0; i < (p->sz); i++) {
printf("%s\t%s\t%d\t%s\t%s\n", (p->data[i]).name, (p->data[i]).sex, \
(p->data[i]).age, (p->data[i]).call, (p->data[i]).address);
}
}
// 6-清空所有联系人
void Emp(contact* p)
{
assert(p);
// 直接将有效联系人数量置为0
(p->sz) = 0;
}
// 7-以名字排序所有联系人
void Sort(contact* p)
{
assert(p);
// 冒泡排序
int i = 0;
int j = 0;
for (i = 0; i < (p->sz) - 1; i++) {
for (j = 0; j < (p->sz) - 1 - i; j++) {
if (strcmp((p->data[j]).name, (p->data[j + 1]).name) > 0) {
list tmp = p->data[j];
p->data[j] = p->data[j + 1];
p->data[j + 1] = tmp;
}
}
}
}
三、头文件、宏定义、函数等声明头文件:game.h
#pragma once
#include <stdio.h>
#include <string.h>
#include <assert.h>
// 注:需有意识将变动的常量值用会宏定义
#define MAX 1000
#define NAMEMAX 10
#define SEXMAX 5
#define CALLMAX 10
#define ADDRESSMAX 10
// 在头文件声明一个人物信息结构体类型
typedef struct List
{
char name[NAMEMAX];
char sex[SEXMAX];
int age;
char call[CALLMAX];
char address[ADDRESSMAX];
}list;
// 再声明一个真正的通讯录结构体类型
typedef struct Contact
{
// 可存1000个人的人物信息结构体数组
list data[MAX];
// 通讯录中的已存有效信息的数量
int sz;
}contact;
// 初始化通讯录
void Init(contact* p);
// 判断通讯录是否满
int Is_Full(contact* p);
// 查询通讯录联系人
int Search(contact* p, char name[]);
// 1-添加联系人信息
void Add(contact* p);
// 2-删除指定联系人信息
void Del(contact* p);
// 3 - 查找指定联系人信息
void Find(contact* p);
// 4 - 修改指定联系人信息
void Amd(contact* p);
// 5-显示所有联系人信息
void Print(const contact* p);
// 6-清空所有联系人
void Emp(contact* p);
// 7-以名字排序所有联系人
void Sort(contact* p);
版本②(附加动态内存开辟效果)
一、main函数所在源文件:test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game0122.h"
// 实现一个通讯录:(不考虑相同名字)
// 通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址
// 提供方法:
// 1-添加联系人信息
// 2-删除指定联系人信息
// 3-查找指定联系人信息
// 4-修改指定联系人信息
// 5-显示所有联系人信息
// 6-清空所有联系人
// 7-以名字排序所有联系人
// 实现一个枚举,使得switch代码的case分支更有意义,之前学过case后可以写枚举类型
enum Option
{
EXIT,//0
ADD,
DEL,
FIND,
AMD,
PRINT,
EMP,
SORT
};
void Meun()
{
printf("--------------------------------------\n");
printf("----------0-退出----------------------\n");
printf("----------1-添加联系人信息------------\n");
printf("----------2-删除指定联系人信息--------\n");
printf("----------3-查找指定联系人信息--------\n");
printf("----------4-修改指定联系人信息--------\n");
printf("----------5-显示所有联系人信息--------\n");
printf("----------6-清空所有联系人------------\n");
printf("----------7-以名字排序所有联系人------\n");
printf("--------------------------------------\n");
}
int main()
{
// 创建一个数组,实际大小为1000的数组,如果直接将其作为通讯录,
// 则通讯录中已有多少数据是未知的,后续增删查改打印都无法实现
// list data[1000] = { 0 };
// 创建通讯录
contact con = { 0 };
// 初始化通讯录(也为之后的优化做铺垫)
Init(&con);
int input = 0;
do {
Meun();
printf("请输入您的选项\n");
scanf("%d", &input);
switch (input)
{
case EXIT:
printf("已退出/n");
break;
case ADD:
// 传入结构体地址
Add(&con);
break;
case DEL:
Del(&con);
break;
case FIND:
Find(&con);
break;
case AMD:
Amd(&con);
break;
case PRINT:
Print(&con);
break;
case EMP:
Emp(&con);
break;
case SORT:
Sort(&con);
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
二、相关函数定义源文件:game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game0122.h"
// 初始化通讯录
void Init(contact* p)
{
assert(p);
(p->sz) = 0;
memset(p->data, 0, sizeof(p->data));
}
// 判断通讯录是否满
int Is_Full(contact* p)
{
assert(p);
if ((p->sz) < MAX) {
return 1;
}
else {
return 0;
}
}
// 查询通讯录联系人
int Search(const contact* p, char name[]) //const保护通讯录不被改变
{
int i = 0;
for (i = 0; i < (p->sz); i++) {
if (0 == strcmp(name, (p->data[i]).name)) {
// 查询成功返回下标
return i;
}
}
// 循环结束仍未返回说明查询失败,返回-1
return -1;
}
// 1-添加联系人信息
void Add(contact* p)
{
assert(p);
// 判断通讯录是否存满
if (Is_Full(p)) {
printf("请输入您要添加的联系人信息:姓名、性别、年龄、电话、住址\n");
// 注:小心在输入age为int类型时,须带&,其余类似name本身就为数组名,是地址
scanf("%s %s %d %s %s", (p->data[(p->sz)]).name, (p->data[(p->sz)]).sex, \
& (p->data[(p->sz)]).age, (p->data[(p->sz)]).call, (p->data[(p->sz)]).address);
// 有效联系人数量加一并提示成功
(p->sz)++;
printf("增加联系人成功\n");
}
else {
printf("通讯录已满,无法继续添加\n");
}
}
// 2-删除指定联系人信息
void Del(contact* p)
{
assert(p);
// 输入需要删除第几个(从0开始数)联系人(p->sz),也可以根据需求输入名字,查找联系人,然后删除
/*int num = 0;
printf("请输入您需要删除的联系人序号(从0开始)\n");
scanf("%d", &num);*/
// 根据输入的名字,调用查找函数,根据函数返回值,如果找到再删除
char name[NAMEMAX] = { 0 };
printf("请输入您要删除的用户姓名\n");
scanf("%s", name);
// 返回值,如果查询到即为下标,未查询到返回-1
int ret = Search(p, name);
if (-1 == ret) {
printf("未查询到此人\n");
}
else {
printf("删除成功\n");
// 将该位置覆盖来删除
int i = 0;
/*for (i = ret; i < ((p->sz) - 1); i++) {
strcpy((p->data[i]).name, (p->data[i + 1]).name);
strcpy((p->data[i]).sex, (p->data[i + 1]).sex);
(p->data[i]).age = (p->data[i + 1]).age;
strcpy((p->data[i]).call, (p->data[i + 1]).call);
strcpy((p->data[i]).address, (p->data[i + 1]).address);
}*/
// 结构体变量很规律,可以相互赋值:(优化版本)
for (i = 0; i < (p->sz) - 1; i++) {
(p->data[i]) = (p->data[i + 1]);
}
// 有效联系人数量减一
(p->sz)--;
}
}
// 3 - 查找指定联系人信息
void Find(contact* p)
{
assert(p);
// 输入需要查找第几个(从0开始数)联系人(p->sz),也可以根据需求输入名字,查找联系人,然后打印
/*int i = 0;
printf("请输入您需要查找的联系人序号(从0开始)\n");
scanf("%d", &i);*/
// 根据输入的名字,调用查找函数,根据函数返回值,如果找到再打印
char name[NAMEMAX] = { 0 };
printf("请输入您要查找的用户姓名\n");
scanf("%s", name);
// 返回值,如果查询到即为下标,未查询到返回-1
int i = Search(p, name);
if (-1 == i) {
printf("未查询到此人\n");
}
else {
printf("查询成功\n");
printf("%s\t%s\t%s\t%s\t%s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%s\t%s\t%d\t%s\t%s\n", (p->data[i]).name, (p->data[i]).sex, \
(p->data[i]).age, (p->data[i]).call, (p->data[i]).address);
}
}
// 4 - 修改指定联系人信息
void Amd(contact* p)
{
assert(p);
// 判断通讯录是否为空,如果为空就无法删除并直接返回
if (0 == (p->sz)) {
printf("通讯录为空,无法删除\n");
return;
}
// 输入需要修改第几个(从0开始数)联系人(p->sz),也可以根据需求输入名字,查找联系人,然后修改
/*int i = 0;
printf("请输入您需要修改的联系人序号(从0开始)\n");
scanf("%d", &i);*/
// 根据输入的名字,调用查找函数,根据函数返回值,如果找到再修改
char name[NAMEMAX] = { 0 };
printf("请输入您要修改的用户姓名\n");
scanf("%s", name);
// 返回值,如果查询到即为下标,未查询到返回-1
int i = Search(p, name);
if (-1 == i) {
printf("未查询到此人\n");
}
else {
// 输入需要修改后的内容
printf("请输入你所修改后的信息:姓名、性别、年龄、电话、住址\n");
scanf("%s\t%s\t%d\t%s\t%s\n", (p->data[i]).name, (p->data[i]).sex, \
& (p->data[i]).age, (p->data[i]).call, (p->data[i]).address);
printf("修改完毕\n");
}
}
// 5-显示所有联系人信息
void Print(const contact* p) //const保护通讯录不被改变
{
assert(p);
// 按需求,也可以分开提示并输入
printf("%s\t%s\t%s\t%s\t%s\n", "姓名", "性别", "年龄", "电话", "住址");
int i = 0;
for (i = 0; i < (p->sz); i++) {
printf("%s\t%s\t%d\t%s\t%s\n", (p->data[i]).name, (p->data[i]).sex, \
(p->data[i]).age, (p->data[i]).call, (p->data[i]).address);
}
}
// 6-清空所有联系人
void Emp(contact* p)
{
assert(p);
// 直接将有效联系人数量置为0
(p->sz) = 0;
}
// 7-以名字排序所有联系人
void Sort(contact* p)
{
assert(p);
// 冒泡排序
int i = 0;
int j = 0;
for (i = 0; i < (p->sz) - 1; i++) {
for (j = 0; j < (p->sz) - 1 - i; j++) {
if (strcmp((p->data[j]).name, (p->data[j + 1]).name) > 0) {
list tmp = p->data[j];
p->data[j] = p->data[j + 1];
p->data[j + 1] = tmp;
}
}
}
}
三、头文件、宏定义、函数等声明头文件:game.h
#pragma once
#include <stdio.h>
#include <string.h>
#include <assert.h>
// 注:需有意识将变动的常量值用会宏定义
#define MAX 1000
#define NAMEMAX 10
#define SEXMAX 5
#define CALLMAX 10
#define ADDRESSMAX 10
// 在头文件声明一个人物信息结构体类型
typedef struct List
{
char name[NAMEMAX];
char sex[SEXMAX];
int age;
char call[CALLMAX];
char address[ADDRESSMAX];
}list;
// 再声明一个真正的通讯录结构体类型
typedef struct Contact
{
// 可存1000个人的人物信息结构体数组
list data[MAX];
// 通讯录中的已存有效信息的数量
int sz;
}contact;
// 初始化通讯录
void Init(contact* p);
// 判断通讯录是否满
int Is_Full(contact* p);
// 查询通讯录联系人
int Search(contact* p, char name[]);
// 1-添加联系人信息
void Add(contact* p);
// 2-删除指定联系人信息
void Del(contact* p);
// 3 - 查找指定联系人信息
void Find(contact* p);
// 4 - 修改指定联系人信息
void Amd(contact* p);
// 5-显示所有联系人信息
void Print(const contact* p);
// 6-清空所有联系人
void Emp(contact* p);
// 7-以名字排序所有联系人
void Sort(contact* p);
版本③(附加文件存储效果)
一、main函数所在源文件:test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game0122_3.h"
// 实现一个通讯录:(不考虑相同名字)
// 通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址
// 提供方法:
// 1-添加联系人信息
// 2-删除指定联系人信息
// 3-查找指定联系人信息
// 4-修改指定联系人信息
// 5-显示所有联系人信息
// 6-清空所有联系人
// 7-以名字排序所有联系人
// 实现一个枚举,使得switch代码的case分支更有意义,之前学过case后可以写枚举类型
enum Option
{
EXIT,//0
ADD,
DEL,
FIND,
AMD,
PRINT,
EMP,
SORT
};
void Meun()
{
printf("--------------------------------------\n");
printf("----------0-退出----------------------\n");
printf("----------1-添加联系人信息------------\n");
printf("----------2-删除指定联系人信息--------\n");
printf("----------3-查找指定联系人信息--------\n");
printf("----------4-修改指定联系人信息--------\n");
printf("----------5-显示所有联系人信息--------\n");
printf("----------6-清空所有联系人------------\n");
printf("----------7-以名字排序所有联系人------\n");
printf("--------------------------------------\n");
}
int main()
{
// 创建一个数组,实际大小为1000的数组,如果直接将其作为通讯录,
// 则通讯录中已有多少数据是未知的,后续增删查改打印都无法实现
// list data[1000] = { 0 };
// 创建通讯录
contact con = { 0 };
// 初始化通讯录(也为之后的优化做铺垫)
Init(&con);
int input = 0;
do {
Meun();
printf("请输入您的选项\n");
scanf("%d", &input);
switch (input)
{
case EXIT:
// 先保存在文件里
Save_Con(&con);
// 先清空,释放空间再退出
Emp(&con);
printf("已退出/n");
break;
case ADD:
// 传入结构体地址
Add(&con);
break;
case DEL:
Del(&con);
break;
case FIND:
Find(&con);
break;
case AMD:
Amd(&con);
break;
case PRINT:
Print(&con);
break;
case EMP:
Emp(&con);
break;
case SORT:
Sort(&con);
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
二、相关函数定义源文件:game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game0122_3.h"
// 将上次创建的通讯录文件内容加载到新创建的con通讯录中
void Load_Con(contact* p)
{
// 打开文件
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL) {
printf("Load()::%s\n", strerror(errno));
return;
}
// 读文件(二进制输入)
// fread()函数:返回值的读取的内容数量,当返回值为0时说明读取完毕,
// 所以不用担心上次保存的内容有多少个用户信息
// 创建一个临时用户
list tmp = { 0 };
while (fread(&tmp, sizeof(list), 1, pf)) {
// 判断上次保存的用户数量是否大于capacity,如果大于就扩容
Is_Full(p);
// 加载用户信息到新通讯录
p->data[p->sz] = tmp;
(p->sz)++;
// 注意:每轮的容量判断指标也要加1
(p->capacity)++;
}
// 关闭文件
fclose(pf);
pf = NULL;
}
// 初始化通讯录
void Init(contact* p)
{
assert(p);
(p->sz) = 0;
(p->capacity) = 0;
// 第一次扩容DEFAULTAMP个人物信息结构体数量大小并利用calloc函数直接初始化为0
list* ptr = (list*)calloc(DEFAULTAMP, sizeof(list));
if (NULL != ptr) {
// 确保开辟成功再赋值
(p->data) = ptr;
}
else {
printf("Init()::%s\n", strerror(errno));
// 有错误提前结束
return;
}
// 将上次创建的通讯录文件内容加载到新创建的con通讯录中
Load_Con(p);
}
// 判断通讯录本轮开辟空间是否满(增容函数)
void Is_Full(contact* p)
{
assert(p);
if (DEFAULTAMP == (p->capacity)) {
// 扩容:每次扩容DEFAULTAMP个sizeof(list)大小
list* ptr = (list*)realloc(p->data, (DEFAULTAMP * 2) * sizeof(list));
if (NULL != ptr) {
// 确保扩容成功再赋值
(p->data) = ptr;
printf("扩容成功\n");
// 新扩容一次,扩容标记置0
(p->capacity) = 0;
}
else {
printf("Is_Full()::%s\n", strerror(errno));
// 无需return,已到函数末尾
}
}
}
// 查询通讯录联系人
int Search(const contact* p, char name[]) //const保护通讯录不被改变
{
int i = 0;
for (i = 0; i < (p->sz); i++) {
if (0 == strcmp(name, (p->data[i]).name)) {
// 查询成功返回下标
return i;
}
}
// 循环结束仍未返回说明查询失败,返回-1
return -1;
}
// 1-添加联系人信息
void Add(contact* p)
{
assert(p);
// 判断通讯录已开辟空间容量是否已满,如果满了会自动扩容,扩容成功提示
Is_Full(p);
// 添加联系人信息
printf("请输入您要添加的联系人信息:姓名、性别、年龄、电话、住址\n");
// 注:小心在输入age为int类型时,须带&,其余类似name本身就为数组名,是地址
scanf("%s %s %d %s %s", (p->data[(p->sz)]).name, (p->data[(p->sz)]).sex, \
& (p->data[(p->sz)]).age, (p->data[(p->sz)]).call, (p->data[(p->sz)]).address);
// 有效联系人数量加一并提示成功,本轮已占容量也加一
(p->sz)++;
(p->capacity)++;
printf("增加联系人成功\n");
}
// 2-删除指定联系人信息
void Del(contact* p)
{
assert(p);
// 输入需要删除第几个(从0开始数)联系人(p->sz),也可以根据需求输入名字,查找联系人,然后删除
/*int num = 0;
printf("请输入您需要删除的联系人序号(从0开始)\n");
scanf("%d", &num);*/
// 根据输入的名字,调用查找函数,根据函数返回值,如果找到再删除
char name[NAMEMAX] = { 0 };
printf("请输入您要删除的用户姓名\n");
scanf("%s", name);
// 返回值,如果查询到即为下标,未查询到返回-1
int ret = Search(p, name);
if (-1 == ret) {
printf("未查询到此人\n");
}
else {
printf("删除成功\n");
// 将该位置覆盖来删除
int i = 0;
/*for (i = ret; i < ((p->sz) - 1); i++) {
strcpy((p->data[i]).name, (p->data[i + 1]).name);
strcpy((p->data[i]).sex, (p->data[i + 1]).sex);
(p->data[i]).age = (p->data[i + 1]).age;
strcpy((p->data[i]).call, (p->data[i + 1]).call);
strcpy((p->data[i]).address, (p->data[i + 1]).address);
}*/
// 结构体变量很规律,可以相互赋值:(优化版本)
for (i = 0; i < (p->sz) - 1; i++) {
(p->data[i]) = (p->data[i + 1]);
}
// 有效联系人数量减一,本轮所剩有效容量加一
(p->sz)--;
(p->capacity)++;
}
}
// 3 - 查找指定联系人信息
void Find(contact* p)
{
assert(p);
// 输入需要查找第几个(从0开始数)联系人(p->sz),也可以根据需求输入名字,查找联系人,然后打印
/*int i = 0;
printf("请输入您需要查找的联系人序号(从0开始)\n");
scanf("%d", &i);*/
// 根据输入的名字,调用查找函数,根据函数返回值,如果找到再打印
char name[NAMEMAX] = { 0 };
printf("请输入您要查找的用户姓名\n");
scanf("%s", name);
// 返回值,如果查询到即为下标,未查询到返回-1
int i = Search(p, name);
if (-1 == i) {
printf("未查询到此人\n");
}
else {
printf("查询成功\n");
printf("%s\t%s\t%s\t%s\t%s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%s\t%s\t%d\t%s\t%s\n", (p->data[i]).name, (p->data[i]).sex, \
(p->data[i]).age, (p->data[i]).call, (p->data[i]).address);
}
}
// 4 - 修改指定联系人信息
void Amd(contact* p)
{
assert(p);
// 判断通讯录是否为空,如果为空就无法删除并直接返回
if (0 == (p->sz)) {
printf("通讯录为空,无法删除\n");
return;
}
// 输入需要修改第几个(从0开始数)联系人(p->sz),也可以根据需求输入名字,查找联系人,然后修改
/*int i = 0;
printf("请输入您需要修改的联系人序号(从0开始)\n");
scanf("%d", &i);*/
// 根据输入的名字,调用查找函数,根据函数返回值,如果找到再修改
char name[NAMEMAX] = { 0 };
printf("请输入您要修改的用户姓名\n");
scanf("%s", name);
// 返回值,如果查询到即为下标,未查询到返回-1
int i = Search(p, name);
if (-1 == i) {
printf("未查询到此人\n");
}
else {
// 输入需要修改后的内容
printf("请输入你所修改后的信息:姓名、性别、年龄、电话、住址\n");
scanf("%s\t%s\t%d\t%s\t%s\n", (p->data[i]).name, (p->data[i]).sex, \
& (p->data[i]).age, (p->data[i]).call, (p->data[i]).address);
printf("修改完毕\n");
}
}
// 5-显示所有联系人信息
void Print(const contact* p) //const保护通讯录不被改变
{
assert(p);
// 按需求,也可以分开提示并输入
printf("%s\t%s\t%s\t%s\t%s\n", "姓名", "性别", "年龄", "电话", "住址");
int i = 0;
for (i = 0; i < (p->sz); i++) {
printf("%s\t%s\t%d\t%s\t%s\n", (p->data[i]).name, (p->data[i]).sex, \
(p->data[i]).age, (p->data[i]).call, (p->data[i]).address);
}
}
// 6-清空所有联系人
void Emp(contact* p)
{
assert(p);
// 有效数据置0
(p->sz) = 0;
(p->capacity) = 0;
// 动态内存释放
free(p->data);
(p->data) = NULL;
}
// 7-以名字排序所有联系人
void Sort(contact* p)
{
assert(p);
// 冒泡排序
int i = 0;
int j = 0;
for (i = 0; i < (p->sz) - 1; i++) {
for (j = 0; j < (p->sz) - 1 - i; j++) {
if (strcmp((p->data[j]).name, (p->data[j + 1]).name) > 0) {
list tmp = p->data[j];
p->data[j] = p->data[j + 1];
p->data[j + 1] = tmp;
}
}
}
}
void Save_Con(contact* p)
{
// 讲:结构体一般用二进制来保存
// 打开文件
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL) {
printf("Save_Con()::%s\n", strerror(errno));
return;
}
// 写文件(二进制输出)
int i = 0;
// 每次写一个,写sz次
for (i = 0; i < (p->sz); i++) {
fwrite(&(p->data[i]), 1, sizeof(list), pf);
}
// 关闭文件
fclose(pf);
pf = NULL;
}
三、头文件、宏定义、函数等声明头文件:game.h
#pragma once
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
// 注:需有意识将变动的常量值用会宏定义
//#define MAX 1000
#define NAMEMAX 10
#define SEXMAX 5
#define CALLMAX 10
#define ADDRESSMAX 10
// 默认每次扩容的人物信息结构体数量大小
#define DEFAULTAMP 3
// 在头文件声明一个人物信息结构体类型
typedef struct List
{
char name[NAMEMAX];
char sex[SEXMAX];
int age;
char call[CALLMAX];
char address[ADDRESSMAX];
}list;
// 再声明一个真正的通讯录结构体类型
typedef struct Contact
{
// 可存1000个人的人物信息结构体数组
// list data[MAX]; 存在浪费优化见下
// 创建指针来负责维护通讯录后续动态开辟的内存空间
list* data;
// 通讯录每次开辟新空间后目前所占据的空间数量,达到每次开辟新空间数量DEFAULTAMP就触发扩容机制
int capacity;
// 通讯录中的已存有效信息的数量
int sz;
}contact;
// 将上次创建的通讯录文件内容加载到新创建的con通讯录中
void Load_Con(contact* p);
// 初始化通讯录
void Init(contact* p);
// 判断通讯录本轮开辟空间是否满(增容函数)
void Is_Full(contact* p);
// 查询通讯录联系人
int Search(contact* p, char name[]);
// 1-添加联系人信息
void Add(contact* p);
// 2-删除指定联系人信息
void Del(contact* p);
// 3 - 查找指定联系人信息
void Find(contact* p);
// 4 - 修改指定联系人信息
void Amd(contact* p);
// 5-显示所有联系人信息
void Print(const contact* p);
// 6-清空所有联系人
void Emp(contact* p);
// 7-以名字排序所有联系人
void Sort(contact* p);
// 保存通讯录
void Save_Con(contact *p);
总结
这里对文章进行总结:
以上就是今天总结的内容,本文包括了所有个人写的通讯录C语言代码,分享给大家。
真💙欢迎各位给予我更好的建议,欢迎访问!!!小编创作不易,觉得有用可以一键三连哦,感谢大家。peace
希望大家一起坚持学习,共同进步。梦想一旦被付诸行动,就会变得神圣。
欢迎各位大佬批评建议,分享更好的方法!!!🙊🙊🙊