通讯录的内容
contect.h
#pragma once
// 包含头文件
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
// 使用枚举常量定义功能
enum Function
{
quit, // 注意这是逗号,不是分号
save,
addition,
delete,
search,
revise,
sort,
show // 最后一个没有逗号
};
// 人的信息
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
typedef struct People_Information
{
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char tele[TELE_MAX];
char addr[ADDR_MAX];
}People; // 通过typedef将struct People_Informtion定义为了People
// 通讯录
#define DATA_MAX 1000
typedef struct Contact
{
People data[DATA_MAX]; // data数组里面存放的是每个人的信息
int sz; // 用于记录通讯录中有几个人的信息
}Contact; // 通过typedef将struct Contact定义为了Contact
// 函数声明
// 初始化通讯录
void InitContact(Contact* contact);
// 增加个人信息
void AddContact(Contact* contact);
// 显示通讯录
void ShowContact(const Contact* contact);
// 删除指定信息
void DelContact(Contact* contact);
// 查找指定信息
void SeaContact(const Contact* contact);
// 修改指定联系人
void RevContact(Contact* contact);
// 排序通讯录
void SorContact(Contact* contact);
contact.c
#define _CRT_SECURE_NO_WARNINGS
#include "contact.h"
void menu()
{
printf("..............................\n");
printf("....0:quit........1:save......\n");
printf("....2:addition....3:delete....\n");
printf("....4:search......5:revise....\n");
printf("....6:sort........7:show......\n");
printf("..............................\n");
}
int main()
{
// 利用do{}while();循环和switch语句进行多次选择
int input;
// 进入main函数就要创建通讯录
Contact contact; // contact就是一个通讯录
// 初始化通讯录
InitContact(&contact); // 将通讯录的地址传过去,不仅节省地址,而且可以通过形参改变实参
do
{
// 有哪些功能
// 通过菜单将功能展现出来
menu();
printf("请输入功能序号:");
scanf("%d", &input);
switch (input)
{
// 通过枚举常量定义会更直观
case quit:
printf("退出通讯录!\n");
break;
case save:
break;
case addition:
AddContact(&contact);
break;
case delete:
DelContact(&contact);
break;
case search:
SeaContact(&contact);
break;
case revise:
RevContact(&contact);
break;
case sort:
SorContact(&contact);
break;
case show:
ShowContact(&contact);
break;
default:
printf("无此序号,请重新输入。\n");
}
} while (input);
return 0;
}
test.c
#define _CRT_SECURE_NO_WARNINGS
#include "contact.h"
// 初始化通讯录
void InitContact(Contact* contact)
{
assert(contact);
// contact->data = 0; // contact->data表示的是首元素地址
// 初始化一块连续的内存空间可以使用memset
memset(contact->data, 0, sizeof(contact->data));
contact->sz = 0;
}
// 增加个人信息
void AddContact(Contact* contact)
{
assert(contact);
// 进入函数进行判断
if (contact->sz == DATA_MAX)
{
printf("通讯录已满,无法增加个人信息!\n");
return;
}
// 没有满则进行增加个人信息
printf("请输入姓名:");
scanf("%s", &(contact->data[contact->sz].name));
printf("请输入年龄:");
scanf("%d", &(contact->data[contact->sz].age));
printf("请输入性别:");
scanf("%s", &(contact->data[contact->sz].sex));
printf("请输入电话:");
scanf("%s", &(contact->data[contact->sz].tele));
printf("请输入地址:");
scanf("%s", &(contact->data[contact->sz].addr));
// 增加完一条信息后sz要加1
contact->sz++;
printf("增加成功!\n");
}
// 显示通讯录
void ShowContact(const Contact* contact)
{
assert(contact);
// 进入函数进行判断
if (contact->sz == 0)
{
printf("通讯录为空!\n");
return;
}
// 显示信息
// 标题
printf("%-10s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "住址");
for (int i = 0; i < contact->sz; i++)
{
printf("%-10s %-5d %-5s %-12s %-30s\n",
contact->data[i].name,
contact->data[i].age,
contact->data[i].sex,
contact->data[i].tele,
contact->data[i].addr
);
}
}
// 通过名字查找联系人下标
int FindByName(const Contact* contact, char* name)
{
assert(contact);
for (int i = 0; i < contact->sz; i++)
{
if (strcmp(contact->data[i].name, name) == 0)
{
// 找到返回数组下标
return i;
}
}
return -1;
}
// 删除指定信息
void DelContact(Contact* contact)
{
assert(contact);
char name[NAME_MAX];
if (contact->sz == 0)
{
printf("通讯录为空!\n");
return;
}
// 通过名字查找
printf("请输入要删除人的姓名:");
scanf("%s", name);
int ret = FindByName(contact, name);
// 没找到
if (ret == -1)
{
printf("要删除的人不存在!\n");
}
// 找到了
// 删除这个人(其实是覆盖)
for (int i = ret; i < contact->sz - 2; i++) // 减2这里不是很懂
{
contact->data[i] = contact->data[i + 1];
}
contact->sz--;
printf("删除成功!\n");
// 最后一个直接覆盖当前这个
// 结构体类型相同可以直接赋值
/*contact->data[ret] = contact->data[contact->sz];
contact->sz--;*/
}
// 查找指定信息
void SeaContact(const Contact* contact)
{
assert(contact);
char name[NAME_MAX];
if (contact->sz == 0)
{
printf("通讯录为空!\n");
return;
}
// 通过名字查找
printf("请输入要修改人的姓名:");
scanf("%s", name);
int ret = FindByName(contact, name);
// 没找到
if (ret == -1)
{
printf("要查找的人不存在!\n");
}
// 找到了
// 显示出来
printf("%-10s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "住址");
printf("%-10s %-5d %-5s %-12s %-30s\n",
contact->data[ret].name,
contact->data[ret].age,
contact->data[ret].sex,
contact->data[ret].tele,
contact->data[ret].addr
);
}
// 修改指定联系人
void RevContact(Contact* contact)
{
assert(contact);
char name[NAME_MAX];
if (contact->sz == 0)
{
printf("通讯录为空!\n");
return;
}
// 通过名字修改
printf("请输入要修改人的姓名:");
scanf("%s", name);
int ret = FindByName(contact, name);
// 没找到
if (ret == -1)
{
printf("要修改的人不存在!\n");
}
// 找到了
// 修改
printf("请输入姓名:");
scanf("%s", &(contact->data[contact->sz].name));
printf("请输入年龄:");
scanf("%d", &(contact->data[contact->sz].age));
printf("请输入性别:");
scanf("%s", &(contact->data[contact->sz].sex));
printf("请输入电话:");
scanf("%s", &(contact->data[contact->sz].tele));
printf("请输入地址:");
scanf("%s", &(contact->data[contact->sz].addr));
printf("修改成功!\n");
}
int compare_name(const void* x, const void* y)
{
return strcmp((char*)x, (char*)y);
}
// 排序通讯录
void SorContact(Contact* contact)
{
assert(contact);
if (contact->sz == 0)
{
printf("通讯录为空!\n");
return;
}
// 排序通讯录
qsort(contact, contact->sz, sizeof(contact->data[0]), compare_name);
// 显示信息
// 标题
printf("%-10s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "住址");
for (int i = 0; i < contact->sz; i++)
{
printf("%-10s %-5d %-5s %-12s %-30s\n",
contact->data[i].name,
contact->data[i].age,
contact->data[i].sex,
contact->data[i].tele,
contact->data[i].addr
);
}
}
注意:
传址还是传值
通讯录初始化涉及到传递参数,那我们到底是传址还是传值呢?
InitContact(&contact); // 传递的是地址
// 传址:因为更节省内存空间(地址只占4/8个字节),而且可以通过形参来改变实参;
// 传值:所需的内存空间更大,并且改变形参并不会影响实参;
memset初始化连续空间
// 这里使用的是memset初始化数组,也可以通过循环将数组一个一个制成0;
memset的用法