赞
踩
本篇章笔者将会带领学者写一个 顺序表 的实践项目 - 通讯录 。 相信通过本篇章学者将会对顺序表有更深的理解。
提到通讯录大家肯定会非常熟悉了 , 但要说实现可能还是有一定的难度的。这里我们弄清楚一个问题
● 为什么用顺序表实现通讯录 ?
首先,顺序表的底层其实就是数组 , 然而通讯录就是要做到 “ ‘增’ ‘删’ ‘查’ ‘改’ ” , 也要很快随意的访问联系人 , 这样来看 : 顺序表就占有很大优势了。
● 实现怎样的通讯录 ?
我们实现的是简易的通讯录项目 ,主要是练习顺序表部分的知识 , 想要实现可视化的通讯录列表还需更多知识的支撑,这里笔者就不介绍了 . 其简易通讯录包括 : 通讯录查找联系人信息 , 通讯录添加联系人信息 , 通讯录删除联系人信息 , 通讯录修改联系人信息 。
● 项目要求
◐ 至少能够存储100个人的通讯信息
◐ 能够保存用户信息:名字、性别、年龄、电话、地址等
◐ 增加联系人信息
◐ 删除指定联系人
◐ 查找制定联系人
◐ 修改指定联系人
◐ 显示联系人信息人
实现的是项目 , 所以项目中还是分为三个文件 : 实现文件(.c) 、 声明文件(.h) 、 测试文件(.c) 。
因为顺序表要实现增删查改的操作 , 要做到 " 按需申请 "动态顺序表就显得更合适了.
● 初始化通讯录
● 添加通讯录联系人信息
● 删除通讯录联系人信息
● 查找通讯录联系人信息
● 修改通讯录联系人信息
● 展示通讯录联系人信息
● 销毁通讯录联系人信息
首先, 通讯录是集结了好多好友的很多信息 , 一个信息就会与相应的一个人有关, 我们通过查找联系人的姓名,电话等就可以查到该联系人. 那要实现该怎么实现呢?
顺序表底层是数组 ,数组中每个元素就可以充当一个联系人 ,之前笔者讲到过顺序表中元素可以是自定义元素,所以联系人的信息我们可以定义在结构体中让其组成顺序表,这样就形成了通讯录.
▶ 图例:
以上图是我们考虑的重点 , 顺序表中每个元素的类型是我们自定义的 " 联系人信息 " 类型 ,然而每一个联系人的信息都具有相同的结构 , 这样我们可以考虑定义结构体来封装联系人信息 .
▶ 联系人信息
联系人信息笔者给出以下几个:
◐ 姓名
◐ 电话
◐ 年龄
◐ 家庭住址
◐ 性别
学者可自行添加 !
因为我们底层使用顺序表实现通讯录 , 所以要先实现顺序表 , 然后调用接口即可.
※关于前置声明
◐ 什么是前置声明?
前置声明就是在一个文件中声明另一个文件中的内容 ,声明一个类或结构体而不定义它。这种方式是让编译器知道该类型或结构体的存在。
◐ 顺序表实现用到的前置声明
▶ 顺序表的声明
#include "Contacts.h"
//顺序表的声明
typedef PersonInfo SqDataType;
typedef struct SeqList
{
SqDataType* arr;
int size; // 有效元素个数
int capacity;// 空间大小
}STList;
以上是顺序表实现的声明部分,其中 PersonInfo 是顺序表中数据的类型 , 但在 Contacts 的声明文件中编译器是找不到 PersonInfo 的 , 所以要包含对应头文件才可以让编译器找到该声明并使用。 故:本声明文件中需要包含 — > Contacts.h
▶ 通讯录的声明(错位演示)
#include "SeqList.h" #define NAME_MAX 100 #define PHONE_MAX 30 #define HOME_ADDRRSS_MAX 200 #define SEX_MAX 4 //通讯录的声明 typedef struct PersonInfo { char name[NAME_MAX]; char phone[PHONE_MAX]; int age; char Home_Address[HOME_ADDRRSS_MAX]; char sex[SEX_MAX]; }PersonInfo; //初始化通讯录 void InitContact(SeqList* con);
以上为通讯录的声明 , 虽然我们实现的通讯录底层是顺序表,但当我们实现 初始化通讯录时编译器是不认识 SeqList 的, 这时需要包含头文件才可以让编译器知道。 但是在顺序表的声明文件中(SeqList.h)中已经包含了 " Contacts.h " 这样的头文件,若我们在通讯录的声明文件中再次包含 " SeqList.h "这样的头文件 ,就会存在头文件包重的问题 , 这是 C 语言不支持的!
◐ 头文件互包错误结果
▶ 通讯录的声明(正确代码)
//通讯录的声明 //定义联系人数据类型 #define NAME_MAX 100 #define PHONE_MAX 30 #define HOME_ADDRRSS_MAX 200 #define SEX_MAX 4 typedef struct PersonInfo { char name[NAME_MAX]; char phone[PHONE_MAX]; int age; char Home_Address[HOME_ADDRRSS_MAX]; char sex[SEX_MAX]; }PersonInfo; //**************前置声明 ***************** typedef struct SqList Contacts;
※正确实现代码
● 顺序表的声明文件 ( SeqList.h )
#pragma once #include "Contacts.h" //顺序表的声明 typedef PersonInfo SqDataType; typedef struct SeqList { SqDataType* arr; int size; // 有效元素个数 int capacity;// 空间大小 }STList; //初始化 void SeqListInit(STList * psl); //销毁 void SeqListDesTroy(STList* psl); //尾插 void SeqListPushBack(STList* psl, SqDataType x); //指定位置删除 void SeqListPop(STList* psl , int pos);
● 顺序表的实现文件 ( SeqList.c )
#define _CRT_SECURE_NO_WARNINGS #include "SeqList.h" //初始化 void SeqListInit(STList* psl) { psl->arr = NULL; psl->size = psl->capacity = 0; } //销毁 void SeqListDesTroy(STList* psl) { if (psl->arr) { free(psl->arr); } psl->arr = NULL; psl->size = psl->capacity = 0; } void Chick_capacity(STList* chick) { if (chick->capacity == chick->size) { //申请空间 - 动态增容 int Newcapacity = chick->capacity == 0 ? 4 : 2*chick->capacity; SqDataType* tmp = (SqDataType*)realloc(chick->arr, Newcapacity * sizeof(SqDataType)); if (tmp == NULL) { perror("realloc fail!"); exit(1); } //申请成功 chick->arr = tmp; chick->capacity = Newcapacity; } } //尾插 void SeqListPushBack(STList* psl, SqDataType x) { assert(psl); //检查空间容量 Chick_capacity(psl); psl->arr[psl->size++] = x; } //指定位置删除 void SeqListPop(STList* psl , int pos) { //pos 之后的数据 , 后面移动到前面 for (int i = pos+1; i < psl->size ; i++) { //后面数据移动到前面 psl->arr[i-1] = psl->arr[i]; } --psl->size; }
● 通讯录的声明文件 ( Contacts.h )
#pragma once #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <windows.h> //通讯录的声明 //定义联系人数据类型 #define NAME_MAX 100 #define PHONE_MAX 30 #define HOME_ADDRRSS_MAX 200 #define SEX_MAX 4 typedef struct PersonInfo { char name[NAME_MAX]; char phone[PHONE_MAX]; int age; char Home_Address[HOME_ADDRRSS_MAX]; char sex[SEX_MAX]; }PersonInfo; //前置声明 typedef struct SeqList Contacts; //通讯录接口 //初始化通讯录 void InitContact(Contacts* con); //添加通讯录数据 void AddContact(Contacts* con); //删除通讯录数据 void DelContact(Contacts* con); //展示通讯录数据 void ShowContact(Contacts* con); //查找通讯录数据 void FindContact(Contacts* con); //修改通讯录数据 void ModifyContact(Contacts* con); //销毁通讯录数据 void DestroyContact(Contacts* con);
● 通讯录的实现文件( Contacts.c )
#define _CRT_SECURE_NO_WARNINGS #include "Contacts.h" #include "SeqList.h" //初始化通讯录 void InitContact(Contacts* con) { SeqListInit(con); } //添加通讯录数据 void AddContact(Contacts* con) { //创建联系人 PersonInfo Info; //用户选择 printf("请输入您要添加的联系人姓名:\n"); scanf("%s",Info.name); printf("请输入您要添加的联系人电话:\n"); scanf("%s", Info.phone); printf("请输入您要添加的联系人年龄:\n"); scanf("%d", &Info.age); printf("请输入您要添加的联系人家庭住址:\n"); scanf("%s", Info.Home_Address); printf("请输入您要添加的联系人性别:\n"); scanf("%s", Info.sex); //写入联系人信息表中 -- 尾插到顺序表 SeqListPushBack(con , Info); } //查找联系人姓名 int Find_Name(Contacts* con , char* name) { for (int i = 0; i < con->size; i++) { if (0 == strcmp(con->arr[i].name, name)) { //找到了 return i; } } //没有找到 return -1; } //删除通讯录数据 void DelContact(Contacts* con) { char name[NAME_MAX]; printf("请输入您要删除的联系人姓名:"); scanf("%s", name); printf("\n"); printf("正在删除,请稍后......\n"); Sleep(1000); int find = Find_Name(con, name); if (find >= 0) { SeqListPop(con , find); printf("删除成功!\n"); ShowContact(con); } else { printf("******您删除的联系人不存在, 请您先添加该联系人!******\n"); printf("\n"); } } //展示通讯录数据 void ShowContact(Contacts* con) { printf("以下是联系人簿信息:\n"); printf("\n"); //遍历通讯录,打印每个联系人信息 for (int i = 0; i < con->size; i++) { printf("姓名: %2s\n电话: %2s\n年龄:%6d\n家庭住址:%2s\n性别: %2s\n", con->arr[i].name, con->arr[i].phone, con->arr[i].age, con->arr[i].Home_Address, con->arr[i].sex); printf("\n"); } printf("\n"); } //查找通讯录数据 void FindContact(Contacts* con) { char name[NAME_MAX]; printf("请输入您要查找的联系人姓名:"); scanf("%s", name); printf("\n"); printf("正在查找中,请稍后.....\n"); Sleep(1000); int flag = 0; // 1 代表找到 for (int i = 0; i < con->size; i++) { if ( 0 == strcmp(con->arr[i].name, name)) { printf("该联系人已找到\n"); ShowContact(con); flag = 1; } } if (flag == 0) { printf("******您查找的联系人不存在,请您先添加该联系人******\n"); printf("\n"); } } //修改姓名 void Modify_name(Contacts* con , int find) { printf("请输入新的姓名: \n"); scanf("%s", con->arr[find].name); } //修改电话 void Modify_phone(Contacts* con, int find) { printf("请输入新的电话: \n"); scanf("%s", con->arr[find].phone); } //修改年龄 void Modify_age(Contacts* con, int find) { printf("请输入新的年龄: \n"); scanf("%d", &con->arr[find].age); } //修改家庭住址 void Modify_home_address(Contacts* con, int find) { printf("请输入新的家庭住址: \n"); scanf("%s", con->arr[find].Home_Address); } //修改性别 void Modify_sex(Contacts* con, int find) { printf("请输入新的性别: \n"); scanf("%s", con->arr[find].sex); } //修改通讯录数据 void ModifyContact(Contacts* con) { char name[NAME_MAX]; printf("请您先输入修改的联系人姓名:\n"); scanf("%s", name); printf("\n"); printf("正在查找中,请稍后.....\n"); Sleep(1000); printf("\n"); printf("\n"); int find = Find_Name(con, name); if (find < 0) { printf("******您修改的联系人不存在, 请您先添加该联系人!******\n"); printf("\n"); } else { printf("您修改的联系人存在!\n"); printf("\n"); printf("以下是修改信息:\n"); printf("*** 0.结束选择 1. 姓名 2.电话 3.年龄 4.家庭住址 5.性别 ***\n"); int chance = 0; do { printf("请您对该联系人的信息修改做出选择:\n"); scanf("%d", &chance); switch (chance) { case 0: printf("结束选择...\n"); break; case 1: Modify_name(con, find); break; case 2: Modify_phone(con, find); break; case 3: Modify_age(con, find); break; case 4: Modify_home_address(con, find); break; case 5: Modify_sex(con, find); break; default: printf("您输入有误,请重新选择!\n"); printf("\n"); } }while(chance); } } //销毁通讯录数据 void DestroyContact(Contacts* con) { SeqListDesTroy(con); }
● 测试文件 ( Test.c )
#define _CRT_SECURE_NO_WARNINGS #include "Contacts.h" #include "SeqList.h" void menu() { printf("******************通讯录******************\n"); printf("*******1.添加联系人 2.删除联系人********\n"); printf("*******3.修改联系人 4.查找联系人********\n"); printf("*******5.展示联系人 0. 退出 *********\n"); printf("******************************************\n"); } int main() { int op = -1; Contacts con; InitContact(&con); do { menu(); printf("请选择您的操作:\n"); scanf("%d", &op); //要根据对应的op执行不同的操作 switch (op) { case 1: AddContact(&con); break; case 2: DelContact(&con); break; case 3: ModifyContact(&con); break; case 4: FindContact(&con); break; case 5: ShowContact(&con); break; case 0: printf("退出通讯录....\n"); break; default: printf("输入错误,请重新选择您的操作!\n"); break; } } while (op != 0); DestroyContact(&con); }
※效果展示
以上我们可以实现一个简易的通讯录项目 , 以上是笔者对于之前知识的回顾, 同时希望学者能够学完并独立的写出 , 这样相信顺序表部分就会熟悉的掌握了!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。