通訊錄
老規矩筆記和代碼歡迎自取~
鏈接:
- 通訊錄筆記
- 通訊錄工程檔案+源代碼
文章目錄
- 通訊錄
- 一、通訊錄的組成
- 二、通訊錄檔案構成
- 1. test.c
- 2. correspondence.c
- 3. correspondence.h
- 三、實作的代碼步驟分析
- 1. 列印選單
- 2. 聯系人資訊初始化
- 3. 添加聯系人
- 4. 列印聯系人
- 5. 洗掉聯系人
- 6. 查找指定聯系人
- 7. 修改聯系人
- 8. 排序聯系人
一、通訊錄的組成
利用最近所學的知識,試著實作一個通訊錄
手機里面的通訊錄資訊

最后我決定給通訊錄增加以下資訊
-
存放100個聯系人的資訊
資訊包括:姓名 + 性別 + 年齡 + 電話 + 公司地址
(PS:節目效果,真不是跟蹤狂)
-
增加/洗掉/修改/查找/列印/排序聯系人
(功能是不是很強大?看完這篇你也可以實作!)
二、通訊錄檔案構成
為什么每一篇小專案都強調一遍檔案構成?
- 檔案的構成是每一個專案的思路
- 沒有思路,直接上手容易手忙腳亂
- 分析好每個檔案所包含的內容,有利于我們代碼的書寫
1. test.c
按照之前的設計小游戲一樣,test.c檔案是必要的,用來測驗各種功能使用是否可以正常使用或者運行
還包括整個通訊錄的框架,比如提供給使用者得選擇選單
2. correspondence.c
用來設計實作通訊錄功能的檔案,檔案包含的基本上都是函式
函式包括實作增加/洗掉/修改/查找/列印/排序聯系人
3. correspondence.h
包含 test.c 和 correspondence.c 中需要用到的庫函式的頭檔案,以及全程序需要使用的變數
三、實作的代碼步驟分析
1. 列印選單
使用者上手即操作,我們需要提供給他們操作的選單,也是我們功能的目錄
選單明細上面也分析了,主要包含:
void menu()//選單
{
printf("==============通訊錄=============\n");
printf(" 1.添加聯系人(add) \n");
printf(" 2.查找聯系人(seek) \n");
printf(" 3.洗掉聯系人(delete) \n");
printf(" 4.修改聯系人(modify) \n");
printf(" 5.排序聯系人(sort) \n");
printf(" 6.列印聯系人(print) \n");
printf(" 0.退出通訊錄(EXIT) \n");
}
利用最近所學的列舉型別,我們試著這次的回圈內的switch陳述句,判斷不選擇數字,而選擇判斷功能的內容
所以我們定義一個列舉型別,用單詞代表各個功能
此程序在 test.c 檔案中
enum menu
{
EXIT,//0
add,//1
seek,//2
delete,//3
modify,//4
sort,//5
print//6
};
把exit放前面正好代表0,每個列舉常量代表的數字都是對應的功能
到此為止,整個回圈的大概模型是這樣,代碼如下
此程序在 test.c 檔案中
int main()
{
int input = 0;
do
{
menu();//列印選單提供使用者選擇
printf("請選擇您要使用的功能(輸入選項括號內內容):");
scanf("%d", &input);//使用者輸入選擇
switch (input)
{
case add:break;
case seek:break;
case delete:break;
case modify:break;
case sort:break;
case print:break;
case exit:
printf("您選擇了退出通訊錄\n");
break;
default:
printf("輸入錯誤資訊,請重新輸入:\n");
break;
}
} while (input != 0);
return 0;
}
運行的結果
分別測驗了 正確資訊 錯誤資訊 退出功能

2. 聯系人資訊初始化
剛拿到新手機的大家,通訊錄里面是沒有聯系人的資訊
但可以通過自己填寫聯系人資訊存盤到手機中
我們需要提供給使用者,接收/存盤資訊的一個資料庫
但因為人的資訊是復雜的,是多種元素構成
資訊包括:姓名 + 性別 + 年齡 + 電話 + 公司地址
使用型別:char char int int char
此程序在 correspondence.h 檔案中
#define NAME_MAX 11
#define GENDER_MAX 5
#define TELE_MAX 12
#define EMAIL_MAX 20
//通訊錄初始化個人資訊
struct perinfmt //personal information
{
char name[NAME_MAX];//支持5個漢字(2個位元組一個漢字)
char gender[GENDER_MAX];//男性 or 女性
int age;
char tele[TELE_MAX];//11位電話號碼
char email[EMAIL_MAX];//19位郵箱
};
為了不用每次挨個修改個人資訊的大小,我們用define定義每個資訊的最大值
還沒有結束,我們創建好的是每個人的資訊填寫位置,但還沒有創建一個通訊錄,有100個人,每個人還需要標記序號(這里序號不放在個人資訊里是因為,創建聯系人的時候不會去填每個人的資訊),這是需要我們系統內部自己去偷偷記錄的
此時100個人 + 序號 通訊錄仍然是復雜資訊 我們再次創建結構體變數
此程序在 correspondence.h 檔案中
struct address_book //通訊錄內容
{
struct perinfmt p[BOOK_MAX];//每個人資訊,陣列一共100個人
int ID;//統計每個人編號
};
創建通訊錄的結構體變數時,我們仍然還沒有初始化
新建一個函式,專門初始化它
此程序在 correspondence.c 檔案中
void Initialize(struct address_book* ap)
{
ap->ID = 0;//序號初始值0
memset(ap->p, 0, sizeof(ap->p));//初始化整個結構體陣列大小為0
}
記得在 correspondence.h 中宣告
我們才能在 test.c 上使用 (記得在進入回圈前就初始化好)
struct address_book alinfmt;//all information
Initialize(&alinfmt);//初始化通訊錄
PS:但其實也可以不創建這個 函式初始化
(我們是為了方便,這樣每次都可以,直接用函式初始化)
可以在創建變數的時候直接初始化
struct address_book alinfmt = { { 0 }, 0 };//all information此程序在 test.c 中完成
3. 添加聯系人
功能的鋪墊已經寫好了
我們開始寫主要的功能
添加聯系人函式
- 判斷通訊錄是否滿了,如果滿了,退出
- 如果沒滿,讓使用者輸入資訊
//增加聯系人
void add_contact(struct address_book* ap)
{
if (ap->ID == BOOK_MAX)
{
printf("通訊錄滿了,請洗掉一些聯系人再添加!\n");
}
else
{
printf("請輸入聯系人姓名:");
scanf("%s", ap->p[ap->ID].name);
printf("請輸入聯系人性別:");
scanf("%s", ap->p[ap->ID].gender);
printf("請輸入聯系人年齡:");
scanf("%d", &(ap->p[ap->ID].age));
//這里是因為age是int型別變數需要傳地址,其他陣列型別變數名就是地址
printf("請輸入聯系人電話:");
scanf("%s", ap->p[ap->ID].tele);
printf("請輸入聯系人郵箱地址:");
scanf("%s", ap->p[ap->ID].email);
printf("-----添加完成-----\n");
ap->ID++;
}
}
scanf里面一大串都是什么?
圖解

還有寫這段代碼時候必須包含等號,不能只寫大于號
if (ap->ID == BOOK_MAX)
{
printf("通訊錄滿了,請洗掉一些聯系人再添加!\n");
}
不然會警告

最后別忘了填寫完一個人的資訊的時候,記錄的ID需要增加
4. 列印聯系人
既然已經完成了添加聯系人,那么我們就不按順序,看看如何列印我們所有聯系人的成員吧
列印聯系人函式
直接用一個for回圈搞定~
//顯示所有聯系人
void print_book(struct address_book* ap)
{
int i = 0;
for (i = 0; i < ap->ID; i++)
{
printf("聯系人姓名:%s\n性別:%s\n年齡:%d\n電話:%s\n郵箱地址:%s\n",
ap->p[i].name,
ap->p[i].gender,
ap->p[i].age,
ap->p[i].tele,
ap->p[i].email);
}
}
搭配添加聯系人食用~,結果如下圖:

5. 洗掉聯系人
我們發現,洗掉/查找/修改 聯系人功能中,都會包含有 查找聯系人這個動作
用for回圈遍歷一遍,查找是否有這個聯系人
//查找聯系人
int find_contact(const struct address_book* ap, const char* name)
{
int i = 0;
for (i = 0; i < ap->ID; i++)
{
if (strcmp(ap->p[i].name, name) == 0)
{
return 1;
}
}
return -1;
}
找到了之后圖解:

//洗掉聯系人
void del_contact(struct address_book* ap)
{
if (ap->ID == 0)//判斷通訊錄是否為空
{
printf("無可洗掉聯系人");
return;
}
char name[NAME_MAX] = { 0 };//存放查找的姓名
printf("請輸入洗掉的聯系人姓名:");
scanf("%s", name);
int ret = find_contact(ap, name);
if (ret == -1)
{
printf("該聯系人不存在");
}
else
{
//洗掉聯系人
int j = 0;
for (j = ret; j < ap->ID - 1; j++)
{
ap->p[j] = ap->p[j + 1];
}
ap->ID--;//少了一個數字
printf("洗掉成功!\n");
}
}
代碼運行效果:


我的舍友就這樣成功被我洗掉了哈哈哈哈
6. 查找指定聯系人
這個代碼有了上面幾個代碼的鋪墊,直接復制粘貼修改一些變數就可以!
看看代碼是不是有點熟悉,copy就完事了
//查找指定聯系人
void seek_contact(const struct address_book* ap)//我們只是查找不作修改
{
char name[NAME_MAX];
printf("請輸入需要查找的聯系人姓名:");
scanf("%s", &name);
int ret = find_contact(ap, name);
if (ret == -1)
{
printf("該聯系人不存在");
}
else
{
printf("找到了!\n聯系人姓名:%s\n性別:%s\n年齡:%d\n電話:%s\n郵箱地址:%s\n\n",
ap->p[ret].name,
ap->p[ret].gender,
ap->p[ret].age,
ap->p[ret].tele,
ap->p[ret].email);
}
}
運行效果:

7. 修改聯系人
同理,也是copy + 稍微修改一下就完事了
//修改聯系人
void modify_contact(struct address_book* ap)
{
char name[NAME_MAX];
printf("請輸入需要查找的聯系人姓名:");
scanf("%s", &name);
int ret = find_contact(ap, name);
if (ret == -1)
{
printf("該聯系人不存在");
}
else
{
printf("開始修改聯系人資訊!\n");
printf("請重新輸入聯系人姓名:");
scanf("%s", ap->p[ret].name);
printf("請重新輸入聯系人性別:");
scanf("%s", ap->p[ret].gender);
printf("請重新輸入聯系人年齡:");
scanf("%d", &(ap->p[ret].age));
printf("請重新輸入聯系人電話:");
scanf("%s", ap->p[ret].tele);
printf("請重新輸入聯系人郵箱地址:");
scanf("%s", ap->p[ret].email);
printf("-----修改完成-----\n");
}
}
運行效果:


8. 排序聯系人
我們用qsort快排進行聯系人的姓名排序
int compare(const void* e1, const void* e2)
{
return (strcmp((const char*)e1, (const char*)e2));
}
//排序聯系人
void sort_contact(struct address_book* ap)
{
qsort(ap->p->name, ap->ID, sizeof(ap->p[0]), compare);
printf("排序完成,請選擇顯示所有聯系人進行查看!\n");
}
然后,我將前面的exit改成了大寫
因為出現了問題!!!
在stdlib.h檔案的存在情況下,exit是已經被使用的
而我再使用,與庫函式沖突,會報錯!!
在發現了原因的情況下,修改之后
效果如下:

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/305743.html
標籤:其他
