通讯录的内容
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表示的是首元素地址// 初始化一块连续的内存空间可以使用memsetmemset(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要加1contact->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的用法