在本篇之前的順序表專題我們已經學習的順序表的實現,了解了如何實現順序表的插入和刪除等功能,那么在本篇當中就要學習基于順序表來實現通訊錄,在通訊錄當中能實現聯系人的增、刪、查改等功能,接下來就讓我們一起來實現通訊錄吧!
?
?1.實現通訊錄前的分析
在實現通訊錄的代碼前我們要先思考在通訊錄項目中能實現什么樣的功能
(1)至少能夠存儲100個人的通訊信息
(2)能夠保存用戶信息:名字、性別、年齡、電話、地址等
(3)增加聯系人信息
(4)刪除指定聯系人
(5)查找制定聯系人
(6)修改指定聯系人
(7)顯示聯系人信息
同時由于在之前的順序表中使用的是動態順序表,所以在實現通訊錄項目中也基于的是動態順序表
以下是該通訊錄項目的程序文件設置以及各文件中所實現的內容
?
2.通訊錄的實現?
2.1 聯系人信息的設置以及順序表內要做出的更改
?由于順序表的底層就是數組,所以我們就是要利用數組來實現如以下所示的結構
在通訊錄中由于我們要存儲的是多個聯系人的信息,因此要定義一個結構體來存儲聯系人的信息
以下定義結構體struct PersonIfon來存儲聯系人的信息,并且使用typedef將該結構體重命名為Persondef
并且在PersonIfon中的每個數組的大小用#define來定義
#define MAX_NAME 20
#define MAX_GENDER 10
#define MAX_TELE 20
#define MAX_ADRESS 50typedef struct PersonIfon//聯系人信息
{char name[MAX_NAME];//姓名char Gender[MAX_GENDER];//性別int age;//年齡char Tele[MAX_TELE];//電話char Adress[MAX_ADRESS];//地址}PersonIfon;
同時由于要通訊錄所以之前順序表的Sqelist.h的數組類型也要更改,由用來的整型改變為PersonIfon,要實現該改變就需要在Seqlist.h內代碼的頭加上#define“contact.h”
這時Seqlist.h就變為以下形式
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>typedef struct PersonIfon SLDataType;
typedef struct Seqlist
{SLDataType* arr;int size;//有效的數據個數int capacity;//空間大小}SL;//將struct Seqlist重命名為SL
在之前的順序表的結構體struct Seqlist被重命名為SL,但現在我們要實現的是通訊錄這時這個名字就不太合適與直觀,那該如何來在contact.h文件內對struct Seqlist進行重命名呢?
這時你可能想到是在contact.h內加上預處理指令#define“Seqlist.h”,但這樣就存在問題了,在之前的操作中我們已經在Seqlaist.h文件內包含了contact.h,如果在這再在contact.h內包含Seqlist.h就會存在頭文件相互包含的問題,這時程序就會崩潰
所以正確的解決方法是什么呢?
其實這時只需要在contact.h中先聲明以下struct Seqlist就可以對該結構體進行重命名了
struct Seqlist;
typedef struct Seqlist contact;
2.2? 通訊錄的初始化以及銷毀
在以上完成聯系人結構體的定義以及對順序表內數組類型的更改,接下來就可以來實現通訊錄初始化和銷毀的函數了
在此先在contact.h內聲明初始化函數以及銷毀函數,由于在此要對通訊錄內容進行更改,所以要進行傳址調用,兩個函數的參數都是結構體指針
void ContactInit(contact* con);//初始化通訊錄 void ContactDestory(contact* con);//銷毀通訊錄
聲明完之后就是在contact.c內實現以上兩個函數,在此通訊錄的初始化以及銷毀內就可以直接調用之前順序表的初始化以及銷毀函數了
void ContactInit(contact* con)//通訊錄初始化
{SLInit(con);
}
void ContactDestory(contact* con)//銷毀通訊錄
{SLDestory(con);
}
2.3通訊錄的展示?
通訊錄的展示就是將通訊錄的信息都打印出來,實質就是要遍歷一般數組
在此在printf中在占位符中的%后加入的最小寬度限制來讓打印出的通訊錄更有順序
void ContactShow(contact* con)//展示通訊錄
{printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性別", "年齡", "電話", "地址");for (int i = 0; i < con->size; i++){printf("%-10s %-4s %-4d %15s %-20s\n",con->arr[i].name,con->arr[i].Gender,con->arr[i].age,con->arr[i].Tele,con->arr[i].Adress);}
}
2.4通訊錄各功能實現
在以上完成了通訊錄的初始化和銷毀接下來我們就來實現通訊錄增、刪、查、改的功能了
2.4.1 通訊錄內添加聯系人?
在此要實現通訊錄中聯系人的增加先在contact.h內對增加聯系人函數進行聲明,由于在此要對通訊錄內容進行更改,所以要進行傳址調用,函數的參數是結構體指針
void ContactAdd(contact* con);//通訊錄內添加聯系人
接下來就是在contact.c內完成添加聯系人的函數
在此先創建一個結構體PersonIfon ifon,并且使用scanf來讀取用戶輸入的此聯系人的各信息存儲在結構體ifon內,再調用順序表中的插入函數將該結構體ifon插入到數組內,在此使用的是尾插函數,也可以使用其他插入方法
void ContactAdd(contact* con)//在通訊錄內添加聯系人
{PersonIfon ifon;printf("請輸入聯系人姓名:\n");scanf("%s", &ifon.name);printf("請輸入聯系人性別:\n");scanf("%s", &ifon.Gender);printf("請輸入聯系人年齡:\n");scanf("%d", &ifon.age);printf("請輸入聯系人電話:\n");scanf("%s", &ifon.Tele);printf("請輸入聯系人地址:\n");scanf("%s", &ifon.Adress);SLPushBack(con, ifon);
}
2.4.2 通訊錄內刪除聯系人
在此要實現通訊錄中聯系人的刪除先在contact.h內對刪除聯系人函數進行聲明,由于在此要對通訊錄內容進行更改,所以要進行傳址調用,函數的參數是結構體指針
void ContactDel(contact* con);//通訊錄內刪除聯系人
在聲明完函數之后就是對該函數的實現,但在刪除通訊錄內的聯系人要通訊錄中存在要刪除的聯系人才能刪除,所以在函數內還要先判斷,但之后通訊錄的其他功能可能還要用到查找聯系人是否存在
所以可以直接在創建一個判斷相關聯系人是否存在的函數,在此根據的是名字來查找聯系人
存在該聯系人就返回相應的數組下標,不存在就返回-1
int FindbyName(contact* con, char* name) {for (int i = 0; i < con->size; i++){if (strcmp(con->arr[i].name, name)==0){return i;}}return -1; }
接下來就是在contact.c內完成刪除聯系人的函數
在此函數內先定義一個char類型的數組name,大小為MAX_NAME。用scanf將用戶輸入的聯系人姓名存放在該數組內,之后再將指針con與name作為FindbyName的參數,通過FindbyName函數的返回值來得到要刪除的聯系人是否存在。若返回值小于0則說明該聯系人不存在,之后就直接退出函數ContactDel,否則就調用順序表中的任意位置的刪除函數SLErase,這時tmp就是要刪除的數組下標
void ContactDel(contact* con)//通訊錄內刪除聯系人
{char name[MAX_NAME];printf("請輸入要刪除的聯系人的姓名\n");scanf("%s", name);int tmp = FindbyName(con, name);if (tmp < 0){printf("該聯系人不存在,刪除失敗\n");return;}SLErase(con, tmp);printf("刪除成功\n");}
?2.4.3 通訊錄內修改聯系人
在此要實現通訊錄中聯系人的修改先在contact.h內對修改聯系人函數進行聲明,由于在此要對通訊錄內容進行更改,所以要進行傳址調用,函數的參數是結構體指針
void ContactModify(contact* con);//通訊錄內修改聯系人
?接下來就是在contact.c內完成修改聯系人的函數
在該函數內和刪除聯系人函數一樣也是先在此函數內先定義一個char類型的數組name,大小為MAX_NAME。用scanf將用戶輸入的聯系人姓名存放在該數組內,之后再將指針con與name作為FindbyName的參數,通過FindbyName函數的返回值來得到要修改的聯系人是否存在。若返回值小于0則說明該聯系人不存在,之后就直接退出函數ContactDel。否則就使用scanf將用戶輸入的信息存放到原來聯系人的數組位置
void ContactModify(contact* con)//修改聯系人信息
{char name[MAX_NAME];printf("請輸入要修改的聯系人的姓名\n");scanf("%s", name);int tmp = FindbyName(con, name);if (tmp < 0){printf("該聯系人不存在,修改失敗\n");return;}//直接修改printf("請輸入新的聯系人姓名:\n");scanf("%s", con->arr[tmp].name);printf("請輸入新的聯系人性別:\n");scanf("%s", con->arr[tmp].Gender);printf("請輸入新的聯系人年齡:\n");scanf("%d", &con->arr[tmp].age);printf("請輸入新的聯系人電話:\n");scanf("%s", con->arr[tmp].Tele);printf("請輸入新的聯系人地址:\n");scanf("%s", con->arr[tmp].Adress);printf("修改成功!\n");}
?2.4.4 通訊錄內查找聯系人
?在此要實現通訊錄中聯系人的修改先在contact.h內對修改聯系人函數進行聲明,在此雖然查找聯系人未對通訊錄內數據進行修改,但在此還是將結構體作為函數的參數,原因通訊錄其他函數都是傳地址在此也保持一致性
void ContactFind(contact* con);//在通訊錄內查找聯系人
??接下來就是在contact.c內完成查找聯系人的函數
在該函數內也是先定義一個char類型的數組name,再通過scanf函數將用戶輸入的字符串存儲到數組內,在此并定義一個變量flag=-1。再通過for循環遍歷數組中的各個元素中的name是否和數組name相同,相同就將flag賦值為1,相同就打印該元素的聯系人信息,當遍歷完時flag如果等于-1就打印查找不到聯系人
void ContactFind(contact* con)//查找聯系人
{char name[MAX_NAME];printf("請輸入要查找的聯系人的姓名\n");scanf("%s", name);int flag = -1;for (int i = 0; i < con->size; i++){if (strcmp(con->arr[i].name, name) == 0){flag = 1;printf("查找成功!\n");printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性別", "年齡", "電話", "地址");printf("%-10s %-4s %-4d %15s %-20s\n",con->arr[i].name,con->arr[i].Gender,con->arr[i].age,con->arr[i].Tele,con->arr[i].Adress);}}if (flag == -1){printf("你所要查找的聯系人不存在!\n");}}
?
3.通訊錄test.c文件
在以上我們已經實現了通訊錄各種功能,現在就需要在test.c內將這些設計好的功能給拼裝起來,讓程序能在運行窗口通過輸入不同的數就可以實現通訊錄的各功能
?
注:在test.c的開頭要加上#include"SeqList.h"和#include"contact.h"
先在test.c內先創建main函數,同時要實現對通訊錄的多次操作就需要用到循環,在此用的是do...while循環,在循環內在創建一個switch語句來實現用戶輸入不同的信息就進入不同的函功能。在switch語句內的case后的常量都使用枚舉所定義的,這樣會使得代碼的可讀性更高、同時shitch語句的case語句排序也可以是不按順序來的。在不同的case語句內就調用不同的通訊錄功能函數
?
在進入循環先初始化順序表,退出循環就銷毀順序表?
#include"SeqList.h"
#include"contact.h"void menu()
{printf("**************************************\n");printf("******1.添加聯系人 2.刪除聯系人******\n");printf("******3.查找聯系人 4.修改聯系人******\n");printf("******5.展示通訊錄 0.退出程序 ******\n");printf("**************************************\n");}enum option
{ADD=1,DEL=2,FIND=3,MODIFY=4,SHOW=5};int main()
{int input = 0;contact con;ContactInit(&con);do{menu();printf("請選擇操作\n");scanf("%d", &input);switch (input){case ADD:ContactAdd(&con);break;case DEL:ContactDel(&con);break;case FIND:ContactFind(&con);break;case MODIFY:ContactModify(&con);break;case SHOW:ContactShow(&con);break;default:printf("選擇操作錯誤,請輸入1~5內的數\n");break;}} while(input);//當輸入的值為0時,input值也就也0,在此判斷部分input就為假就會退出循環ContactDestory(&con);return 0;
}
?
4.?通訊錄讀取歷史數據和保存數據
在之前已經實現了通訊錄的各功能的數據只能在程序運行窗口打開的時候進行通訊錄的增、刪、查、改等功能。在關閉窗口后對通訊錄進行的各項操作都不會保存,那么要怎么樣才能讓我們設計的通訊錄在每次開始之前都讀取之前的信息,在結束后都保存通訊錄的信息呢?
在之前文件操作章節中講解了如何將程序數據輸出到文件中,將文件數據輸入到程序當中,所以在通訊錄中我們就可以用到文件操作的相關函數來實現通訊錄數據的保存與讀取。
?
4.1讀取歷史數據
要讀取歷史數據就要在通訊錄每次初始化之后就輸入文件的信息到所創建的通訊錄中,也就是將輸入到數組當中。
在此先在我們創建的程序的文件夾中創建一個con.txt文本,再使用fopen以讀的方式打開文件,再創建一個PersonIfon ifon的變量,之后在使用到fread以二進制的形式輸入文件的信息到創建的ifon中,再將ifon尾插到數組當中。
void ContactRead(contact* con)//從文件中讀取歷史數據
{FILE* pf = fopen("con.txt", "rb");if (pf == NULL){perror("fopen");return;}PersonIfon ifon;while (fread(&ifon, sizeof(PersonIfon), 1, pf)){SLPushBack(con, ifon);}printf("成功讀取歷史數據到通訊錄中\n");
}
?
在通訊錄初始化函數中調用SLInit函數后調用COntactRead就可以實現歷史數據的讀取
void ContactInit(contact* con)//通訊錄初始化 {SLInit(con);ContactRead(con); }
?
4.2 保存數據
要實現通訊錄每次在退出程序后都能將數據保留,這就需要在每次銷毀通訊錄前將通訊錄內的數據,也就是數組的所有元素都輸出到con.txt文件內。
要把數組的所有元素都輸出到con.txt文件內就需要先以寫的方式打開文件,后在循環的使用fwrite將數組的數據以二進制的形式輸出到文件當中
void ContactWrite(contact* con)//將通訊錄數據讀入文件中
{FILE* pf = fopen("con.txt", "wb");if (pf == NULL){perror("fopen\n");return;}for (int i = 0; i < con->size; i++){fwrite(con->arr+i, sizeof(PersonIfon), 1, pf);}printf("通訊錄數據保存成功\n");
}
?
在通訊錄銷毀函數中調用SLDestory函數前調用COntactWrite就可以實現數據輸出到文件當中,也就將數據保留了下來
void ContactDestory(contact* con)//銷毀通訊錄 {ContactWrite(con);SLDestory(con); }
?
通訊錄完整代碼?
?
注:在Seqlist.h和Seqlist.c內的查找和打印順序表與以上代碼不兼容,運行時會使得程序崩潰,所以將這些部分注釋掉?
contact.h?
#pragma once
#define MAX_NAME 20
#define MAX_GENDER 10
#define MAX_TELE 20
#define MAX_ADRESS 50typedef struct PersonIfon//聯系人信息
{char name[MAX_NAME];//姓名char Gender[MAX_GENDER];//性別int age;//年齡char Tele[MAX_TELE];//電話char Adress[MAX_ADRESS];//地址}PersonIfon;struct Seqlist;
typedef struct Seqlist contact;void ContactInit(contact* con);//初始化通訊錄
void ContactDestory(contact* con);//銷毀通訊錄
void ContactAdd(contact* con);//通訊錄內添加聯系人
void ContactDel(contact* con);//通訊錄內刪除聯系人
void ContactModify(contact* con);//通訊錄內修改聯系人
void ContactFind(contact* con);//在通訊錄內查找聯系人
void ContactShow(contact* con);//展示通訊錄void ContactRead(contact* con);//從文件中讀取歷史數據
void ContactWrite(contact* con);//將通訊錄數據讀入文件中
?
Seqlist.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>typedef struct PersonIfon SLDataType;
typedef struct Seqlist
{SLDataType* arr;int size;//有效的數據個數int capacity;//空間大小}SL;//將struct Seqlist重命名為SLvoid SLInit(SL* ps);//初始化
void SLDestory(SL* ps);//銷毀void SLCheckCapacity(SL* ps);//檢查空間是否足夠
//void SLPrint(SL ps);//打印順序表void SLPushBack(SL* ps, SLDataType x);//尾插
void SLPushPront(SL* ps, SLDataType x);//頭插void SLPopBack(SL* ps);//尾刪
void SLPopPront(SL* ps);//頭刪void SLInsert(SL* ps, int pos, SLDataType x);//任意位置插入
void SLErase(SL* ps, int pos);//任意位置刪除//int SLFind(SL* ps, SLDataType x);//查找
?
?
Seqlist.c?
#include"SeqList.h"void SLInit(SL* ps)//順序表初始化
{ps->arr = NULL;ps->size = ps->capacity = 0;
}void SLDestory(SL* ps)//順序表銷毀
{if (ps->arr){free(ps->arr);}ps->arr = NULL;ps->size = ps->capacity = 0;
}void SLCheckCapacity(SL* ps)//檢查空間是否足夠,不足時增大空間大小
{if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));if (tmp == NULL){perror("realloc");exit(1);}ps->arr = tmp;ps->capacity = newcapacity;}
}//void SLPrint(SL ps)//打印
//{
// int i = 0;
// for (i; i < ps.size; i++)
// {
// printf("%d ", ps.arr[i]);
// }
// printf("\n");
//}void SLPushBack(SL* ps, SLDataType x)//尾插
{assert(ps);SLCheckCapacity(ps);ps->arr[ps->size++] = x;
}void SLPushPront(SL* ps, SLDataType x)//頭插
{assert(ps);SLCheckCapacity(ps);for (int i = ps->size; i > 0; i--){ps->arr[i] = ps->arr[i - 1]; //pa->arr[1]=pa->arr[0]}ps->arr[0] = x;ps->size++;
}void SLPopBack(SL* ps)//尾刪
{assert(ps);assert(ps->size);ps->size--;
}void SLPopPront(SL* ps)//頭刪
{assert(ps);assert(ps->size);for (int i = 0; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}void SLInsert(SL* ps, int pos, SLDataType x)//任意位置插入
{assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheckCapacity(ps);for (int i = ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1];//結束條件ps->arr[pos+1] = ps->arr[pos]}ps->arr[pos] = x;ps->size++;}void SLErase(SL* ps, int pos)//任意位置刪除
{assert(ps);assert(pos >= 0 && pos < ps->size);for (int i = pos; i <= ps->size - 2; i++){ps->arr[i] = ps->arr[i + 1];//結束條件ps->arr[ps->size-2] = ps->arr[ps->size-1]}--ps->size;
}//int SLFind(SL* ps, SLDataType x)//查找
//{
// assert(ps);
// for (int i = 0; i < ps->size; i++)
// {
// if (ps->arr[i] == x)
// {
// return i;
// }
// }
// return -1;
//
//}
?
contact.c?
#pragma once
#include "contact.h"
#include"SeqList.h"void ContactRead(contact* con)//從文件中讀取歷史數據
{FILE* pf = fopen("con.txt", "rb");if (pf == NULL){perror("fopen");return;}PersonIfon ifon;while (fread(&ifon, sizeof(PersonIfon), 1, pf)){SLPushBack(con, ifon);}printf("成功讀取歷史數據到通訊錄中\n");
}void ContactInit(contact* con)//通訊錄初始化
{SLInit(con);ContactRead(con);}void ContactWrite(contact* con)//將通訊錄數據讀入文件中
{FILE* pf = fopen("con.txt", "wb");if (pf == NULL){perror("fopen\n");return;}for (int i = 0; i < con->size; i++){fwrite(con->arr+i, sizeof(PersonIfon), 1, pf);}printf("通訊錄數據保存成功\n");
}void ContactDestory(contact* con)//銷毀通訊錄
{ContactWrite(con);SLDestory(con);}void ContactAdd(contact* con)//在通訊錄內添加聯系人
{PersonIfon ifon;printf("請輸入聯系人姓名:\n");scanf("%s", &ifon.name);printf("請輸入聯系人性別:\n");scanf("%s", &ifon.Gender);printf("請輸入聯系人年齡:\n");scanf("%d", &ifon.age);printf("請輸入聯系人電話:\n");scanf("%s", &ifon.Tele);printf("請輸入聯系人地址:\n");scanf("%s", &ifon.Adress);SLPushBack(con, ifon);}int FindbyName(contact* con, char* name)
{for (int i = 0; i < con->size; i++){if (strcmp(con->arr[i].name, name)==0){return i;}}return -1;
}void ContactDel(contact* con)//通訊錄內刪除聯系人
{char name[MAX_NAME];printf("請輸入要刪除的聯系人的姓名\n");scanf("%s", name);int tmp = FindbyName(con, name);if (tmp < 0){printf("該聯系人不存在,刪除失敗\n");return;}SLErase(con, tmp);printf("刪除成功\n");}void ContactModify(contact* con)//修改聯系人信息
{char name[MAX_NAME];printf("請輸入要修改的聯系人的姓名\n");scanf("%s", name);int tmp = FindbyName(con, name);if (tmp < 0){printf("該聯系人不存在,修改失敗\n");return;}printf("請輸入新的聯系人姓名:\n");scanf("%s", con->arr[tmp].name);printf("請輸入新的聯系人性別:\n");scanf("%s", con->arr[tmp].Gender);printf("請輸入新的聯系人年齡:\n");scanf("%d", &con->arr[tmp].age);printf("請輸入新的聯系人電話:\n");scanf("%s", con->arr[tmp].Tele);printf("請輸入新的聯系人地址:\n");scanf("%s", con->arr[tmp].Adress);printf("修改成功!\n");}void ContactFind(contact* con)//查找聯系人
{char name[MAX_NAME];printf("請輸入要查找的聯系人的姓名\n");scanf("%s", name);int flag = -1;for (int i = 0; i < con->size; i++){if (strcmp(con->arr[i].name, name) == 0){flag = 1;printf("查找成功!\n");printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性別", "年齡", "電話", "地址");printf("%-10s %-4s %-4d %15s %-20s\n",con->arr[i].name,con->arr[i].Gender,con->arr[i].age,con->arr[i].Tele,con->arr[i].Adress);}}if (flag == -1){printf("你所要查找的聯系人不存在!\n");}}void ContactShow(contact* con)//展示通訊錄
{printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性別", "年齡", "電話", "地址");for (int i = 0; i < con->size; i++){printf("%-10s %-4s %-4d %15s %-20s\n",con->arr[i].name,con->arr[i].Gender,con->arr[i].age,con->arr[i].Tele,con->arr[i].Adress);}
}
?
?test.c
#include"SeqList.h"
#include"contact.h"void menu()
{printf("**************************************\n");printf("******1.添加聯系人 2.刪除聯系人******\n");printf("******3.查找聯系人 4.修改聯系人******\n");printf("******5.展示通訊錄 0.退出程序 ******\n");printf("**************************************\n");}enum option
{ADD=1,DEL=2,FIND=3,MODIFY=4,SHOW=5};int main()
{int input = 0;contact con;ContactInit(&con);do{menu();printf("請選擇操作\n");scanf("%d", &input);switch (input){case ADD:ContactAdd(&con);break;case DEL:ContactDel(&con);break;case FIND:ContactFind(&con);break;case MODIFY:ContactModify(&con);break;case SHOW:ContactShow(&con);break;default:printf("選擇操作錯誤,請輸入1~5內的數\n");break;}} while(input);ContactDestory(&con);return 0;
}
通訊錄實現效果?
?
基于順序表實現通訊錄
?
以上就是本篇的所有內容了,希望能得到你的點贊與收藏,感謝支持!!!