副本Boss:
写一个通讯录,可以录入100个人的信息
每个人的信息包括:
姓名,性别,年龄,电话,住址通讯录的功能包括:
增加,删除,修改,查找,排序,显示。
以下是原码:
contact.h —— 通讯录的声明
contact.c —— 通讯录的实现
test.c —— 测试通讯录
使用方法:
1.头文件:contact.h
#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#define MAX 100
//表示一个人的信息
struct PeoInfo
{
char name[20];
char sex[10];
char tele[15];
int age;
char addr[30];
};
//表示该通讯录能存多少人的数据
struct Contact
{
struct PeoInfo data[MAX];
int sz;
};
//初始化通讯录的声明
void InitContact(struct Contact* pc);
//增加信息的声明
void AddContact(struct Contact* pc);
//删除信息的声明
void DelContact(struct Contact* pc);
//查找信息的声明
void SearchContact(struct Contact* pc);
//修改信息的声明
void ModifyContact(struct Contact* pc);
//显示信息的声明
void ShowContact(const struct Contact* pc);
//排序信息的声明
void SortContact(struct Contact* pc);
2.函数实现文件:contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"
//初始化通讯录
void InitContact(struct Contact* pc)
{
pc->sz = 0;
memset(pc->data, 0, MAX * sizeof(struct PeoInfo));
}
//增加信息
void AddContact(struct Contact* pc)
{
if (pc->sz == MAX)
{
printf("通讯录已满,无法添加信息!");
}
else
{
//增加人的信息
printf("请输入名字:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入年龄:");
scanf("%d", &pc->data[pc->sz].age);
printf("请输入电话:");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入住址:");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
}
}
//按姓名查找函数
int FindByName(const struct Contact* pc, char name[])
{
int i = 0;
for (i = 0;i < pc->sz;i++)
{
if (0 == strcmp(pc->data[i].name, name))
{
return i;
}
}
return -1;
}
//删除指定联系人信息
void DelContact(struct Contact* pc)
{
char name[20];
printf("请输入要删除人的姓名:");
scanf("%s", name);
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("删除的人不存在");
}
else
{
//删除
int j = 0;
for (j = ret;j < pc->sz - 1;j++)
{
pc->data[j] = pc->data[j + 1];
}
pc->sz--;
printf("成功删除该联系人");
}
}
//查找指定联系人的信息
void SearchContact(struct Contact* pc)
{
char name[20];
printf("请输入要查找人的姓名:");
scanf("%s", name);
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("要查找的人不存在");
}
else
{
printf("%-20s\t%-10s\t%-5s\t%-15s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-20s\t%-10s\t%-5d\t%-15s\t%-30s\n", pc->data[ret].name,
pc->data[ret].sex, pc->data[ret].age,
pc->data[ret].tele, pc->data[ret].addr);
}
}
//修改指定联系人的信息
void ModifyContact(struct Contact* pc)
{
printf("请输入要删除人的名字:");
char name[20];
scanf("%s", name);
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("删除的人不存在");
}
else
{
printf("请输入名字:");
scanf("%s", pc->data[ret].name);
printf("请输入性别:");
scanf("%s", pc->data[ret].sex);
printf("请输入年龄:");
scanf("%d", &pc->data[ret].age);
printf("请输入电话:");
scanf("%s", pc->data[ret].tele);
printf("请输入住址:");
scanf("%s", pc->data[ret].addr);
printf("修改成功");
}
}
//qsort参数函数
int cmp_age(const void* e1, const void* e2)
{
return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//按年龄排序信息(用qsort)
void SortContact(struct Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(struct PeoInfo), cmp_age);
}
//显示信息
void ShowContact(const struct Contact* pc)
{
int i = 0;
printf("%-20s\t%-10s\t%-5s\t%-15s\t%-30s\n","姓名","性别","年龄","电话","地址");
for (i = 0;i < pc->sz;i++)
{
printf("%-20s\t%-10s\t%-5d\t%-15s\t%-30s\n", pc->data[i].name,
pc->data[i].sex, pc->data[i].age,
pc->data[i].tele, pc->data[i].addr);
}
}
3.运行文件: test.c
#define _CRT_SECURE_NO_WARNINGS
#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()
{
//创建通讯录
struct Contact con;
//初始化通讯录
InitContact(&con);
int input = 0;
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:
SortContact(&con);
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("请重新输入\n");
break;
}
} while (input);
return 0;
}
通讯录的讲解:
先看text.c和contact.c中的前两行代码的作业:
#define _CRT_SECURE_NO_WARNINGS
这是在vs编译器中解决无法识别scanf函数的声明
#include“contact.h”
包括自己写的头文件的时候要用 “ ” 而不是< >;
头文件 contact.h 主要写包含的库函数,声明一些变量,结构体内容,函数声明
#define MAX 100:
这里用MAX来表示通讯录最大能录入的人的数量,
通#define声明是为了以后像改为200人的时候,直接改这里就行
每个人的信息包括:
姓名,性别,年龄,电话,住址struct PeoInfo { char name[20]; char sex[10]; char tele[15]; int age; char addr[30]; };
可以录入100个人的信息:
struct Contact { struct PeoInfo data[MAX]; int sz; };
这里 data 是创建另一个结构体,里面放着每个人的各种信息;
然后sz里面存放每个结构体的地址(就是一个顺序,表示第几个人的信息)
剩下的一些都是通讯录函数实现的声明:
//初始化通讯录的声明 void InitContact(struct Contact* pc); //增加信息的声明 void AddContact(struct Contact* pc); //删除信息的声明 void DelContact(struct Contact* pc); //查找信息的声明 void SearchContact(struct Contact* pc); //修改信息的声明 void ModifyContact(struct Contact* pc); //显示信息的声明 void ShowContact(const struct Contact* pc); //排序信息的声明 void SortContact(struct Contact* pc);
显示函数中加入const的原因是因为:显示函数不会改变结构体的内容,
加上const能防止写代码时对结构体数据的改变
然后再看text.c中的主函数:
//创建通讯录
struct Contact con;
//初始化通讯录
InitContact(&con);
首先是创建一个通讯录的结构体con
1.初始化通讯录:
void InitContact(struct Contact* pc) { pc->sz = 0; memset(pc->data, 0, MAX * sizeof(struct PeoInfo)); }
因为要改变结构体的内容,所以需要传入地址
然后用到memset将函数初始化为0;
这里简单介绍一下memset函数:
void * memset ( void * ptr, int value, size_t num );该函数会将从 ptr 地址开始,向后的 num 个字节大小的数据初始化为 value
想具体了解memset函数可看:字符函数和字符串函数
https://blog.youkuaiyun.com/weixin_60630270/article/details/126976359?spm=1001.2014.3001.5501
2.增加信息函数
void AddContact(struct Contact* pc) { if (pc->sz == MAX) { printf("通讯录已满,无法添加信息!"); } else { //增加人的信息 printf("请输入名字:"); scanf("%s", pc->data[pc->sz].name); printf("请输入性别:"); scanf("%s", pc->data[pc->sz].sex); printf("请输入年龄:"); scanf("%d", &pc->data[pc->sz].age); printf("请输入电话:"); scanf("%s", pc->data[pc->sz].tele); printf("请输入住址:"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; } }
用struct Contact* pc接受结构体con的地址
增加信息的时候先要考虑通讯录是否已录满
没有录满在进行输入
pc->data[ ],找到录入为主,pc->sz,找到第几个人,.name是找到哪个信息
->和.的区别:
结构体指针->结构体成员名(这里pc是结构体指针)
结构体变量 . 结构体成员名(这里data是结构体变量)
注意:在输入的时候只有输入年龄的时候 用了 &,
其他都没有用,这是因为其他信息都是数组,而数组名表示首元素的地址。
最后将sz++,让sz指向下一个带录入的人的地址
3.删除指定联系人:
这里我们以姓名为查找对象:
//删除指定联系人信息 void DelContact(struct Contact* pc) { char name[20]; printf("请输入要删除人的姓名:"); scanf("%s", name); int ret = FindByName(pc, name); if (ret == -1) { printf("删除的人不存在"); } else { //删除 int j = 0; for (j = ret;j < pc->sz - 1;j++) { pc->data[j] = pc->data[j + 1]; } pc->sz--; printf("成功删除该联系人"); } }
输入要删除人的姓名
用ret接收查找函数的返回值,再进行判断。
删除的话,我们可以将需要删除的数据,用后面的数据往前移的方式给覆盖掉。
(当然这里不用考虑顺序的话,也可以让要删除人的数据 = 最后一个人的数据
然后sz--,将最后一个人的数据删除)
最后删除成功 并将pc->sz--
因为删除一个人的时候先要找到这个人,所以需要再写一个查找函数
//按姓名查找函数 int FindByName(const struct Contact* pc, char name[]) { int i = 0; for (i = 0;i < pc->sz;i++) { if (0 == strcmp(pc->data[i].name, name)) { return i; } } return -1; }
利用strcmp函数将name和pc->data[i].name进行逐个对比
对于strcmp函数:
int strcmp ( const char * str1, const char * str2 )如果str1>str2返回大于0的数,str1<str2,返回小于0的数
如果相等返回0
4.查找指定联系人的信息
void SearchContact(struct Contact* pc) { char name[20]; printf("请输入要查找人的姓名:"); scanf("%s", name); int ret = FindByName(pc, name); if (ret == -1) { printf("要查找的人不存在"); } else { printf("%-20s\t%-10s\t%-5s\t%-15s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址"); printf("%-20s\t%-10s\t%-5d\t%-15s\t%-30s\n", pc->data[ret].name, pc->data[ret].sex, pc->data[ret].age, pc->data[ret].tele, pc->data[ret].addr); } }
用姓名查找,和删除一样,现需要用FindByName进行查找比对,然后判断是否存在
之后进行打印,打印的时候为了好看用了 \t 和 %-20s之类的对齐操作
这里简单说明一下:
int main() { // % 与 d 之间加数字说明需要打印多少个空格,如: char arr[10] = "abcde"; printf("%20s\n", arr); //说明再打印arr数组后,向前面补空格知道补齐到20个字符为止,一般用于右对齐 printf("%-20s%c\n", arr,arr[0]); //说明再打印arr数组后,向后面补空格知道补齐到20个字符为止,一般用于左对齐 printf("%s\t%c\n", arr,arr[0]); //'\t'表示再后面隔开一个注册表的距离,也就是4个空格的距离 return 0; }
5.修改指定联系人的信息
void ModifyContact(struct Contact* pc) { printf("请输入要删除人的名字:"); char name[20]; scanf("%s", name); int ret = FindByName(pc, name); if (ret == -1) { printf("删除的人不存在"); } else { printf("请输入名字:"); scanf("%s", pc->data[ret].name); printf("请输入性别:"); scanf("%s", pc->data[ret].sex); printf("请输入年龄:"); scanf("%d", &pc->data[ret].age); printf("请输入电话:"); scanf("%s", pc->data[ret].tele); printf("请输入住址:"); scanf("%s", pc->data[ret].addr); printf("修改成功"); } }
和上面的同一个道理^_^
6.显示所有人的信息
void ShowContact(const struct Contact* pc) { int i = 0; printf("%-20s\t%-10s\t%-5s\t%-15s\t%-30s\n", "姓名","性别","年龄","电话","地址"); for (i = 0;i < pc->sz;i++) { printf("%-20s\t%-10s\t%-5d\t%-15s\t%-30s\n", pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].tele, pc->data[i].addr); } }
也和上面差不多一样滴
7.排序函数
//qsort参数函数 int cmp_age(const void* e1, const void* e2) { return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age; } //按年龄排序信息(用qsort) void SortContact(struct Contact* pc) { qsort(pc->data, pc->sz, sizeof(struct PeoInfo), cmp_age); }
这个函数用到了qsort排序函数相对比较复杂,
感兴趣的可以看我之前的博客:
之后还会有关于动态通讯录的管理 和 利用文件操做的通讯录管理
希望大家多多关注up!!!