【C語言進階】結構體練習:通訊錄

要求:

實現一個通訊錄。

(1)人的信息:

? ? ? ? 包括姓名、年齡、性別、電話地址。

(2)功能:

? ? ? ? ①存放一百個人的信息。

? ? ? ? ②增加聯系人。

? ? ? ? ③刪除指定聯系人。

? ? ? ? ④查找指定聯系人。

? ? ? ? ⑤修改聯系人。

? ? ? ? ⑥排序。

? ? ? ? ⑦顯示聯系人。

(3)文件:

? ? ? ? ①contact.c:通訊錄實現的文件。

? ? ? ? ②contact.h:通訊錄聲明的文件。

? ? ? ? ③test.c? ? ? :測試通訊錄的文件。

目錄

1.框架的搭建

2. 結構體的聲明以及初始化

2.1 結構體的聲明

2.2 結構體的初始化

3. 通訊錄的增加功能

4. 展示通訊錄的功能

5.刪除、查找指定聯系人

6.查找聯系人

7. 修改聯系人

8.排序聯系人

9.完整代碼

9.1 contact.h

9.2 contact.c

9.3 test.c

10.功能演示

10.1添加、展示

10.2?刪除

10.3?查找

10.4?修改

10.5?排序


1.框架的搭建

? ? ? ? ?整體采用dowhile的結構,讀取用戶的輸入根據不同的輸入選項,調用不同的方法從而實現不同的功能。

在test.c中代碼如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>void menu()
{printf("=====================================");printf("======1.add			2.del	 ========");printf("======3.search		4.modify ========");printf("======5.show		6.sort	 ========");printf("======0.exit		         ========");printf("=====================================");
}int main()
{int input = 0;do{menu();printf("請輸入一個選項:\n");scanf("%d", &input);switch (input){case 1:break;case 2:break;case 3:break;case 4:break;case 5:break;case 6:break;case 0:printf("程序已退出!\n");break;default:printf("請正確輸入選項!\n");break;}} while (input);return 0;
}

2. 結構體的聲明以及初始化

2.1 結構體的聲明

? ? ? ? 這個部分需要在頭文件中contact.h,編寫完畢之后若要使用改結構體需要在test.c中引用該頭文件。

? ? ? ? 首先聲明一個人信息的結構體,具體成員變量詳見文章開頭。

? ? ? ? 我們思考一下,如果我們在主函數中創建了一個100個人信息的結構體數組,我們還需要一個變量來記錄這100個變量中實際存放的變量的個數,那么我們可以封裝成一個通訊錄結構體,通訊錄結構體中包含一個人信息結構體數組和實際存放結構體變量的數目。

? ? ? ? 此時可以在主函數聲明一個通訊錄結構體變量,這樣就會更加的方便。

2.2 結構體的初始化

? ? ? ? 需要將通訊錄結構體變量進行初始化,我們可以在頭文件聲明一個初始化函數形參傳入指針;將成員變量count置為0,將成員變量PeoInfo 類型的數組全部置為0,可以使用memset來實現。

????????這里需要注意一個細節,既然測試函數和邏輯函數都引用頭文件,那么不妨直接把第三方庫全部放在頭文件中,這樣一來只需要引用頭文件即可。

3. 通訊錄的增加功能

①在頭文件中進行方法的聲明,形參需要傳入通訊錄變量的地址;

②具體實現在contact.c中實現。

③首先需要判斷指針是否為空。

④如果通訊錄的count == 100,說明通訊錄已經滿了,提示用戶并且直接返回。

這里需要注意的是,在代碼中出現的數字都可以使用define關鍵字進行宏定義,后面方便修改。

⑤count可以當做結構體數組下標一用,使用scanf來輸入數據,這里需要注意的是數組名本就是地址,除了age需要取地址,剩余四個成員變量不需要取地址。

// 通訊錄的增加方法
void addContact(Contact* p)
{assert(p); // 斷言空指針if (p->count == N){printf("通訊錄已滿!存不下了!\n");return;}printf("請輸入姓名:\n");scanf("%s",(p->list)[p->count].name);printf("請輸入年齡:\n");scanf("%d", &((p->list)[p->count].age));printf("請輸入性別:\n");scanf("%s", (p->list)[p->count].gender);printf("請輸入電話號碼:\n");scanf("%s", (p->list)[p->count].tele);printf("請輸入地址:\n");scanf("%s", (p->list)[p->count].addr);(p->count)++;printf("通訊錄增加成功!");
}

4. 展示通訊錄的功能

①首先在頭文件定義方法,這個方法的形參是一個const Contact的指針,因為只需要展示無需修改。

②遍歷打印p指針指向的結構體即可。

③唯一需要注意的是:輸出的格式要對齊,使用左對齊,在%后加上一個-號。

// 通訊錄的顯示
void showContact(const Contact* p)
{assert(p);int i = 0;printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n","姓名","年齡","性別","電話","地址");for(i = 0;i < p->count; i++){printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",(p->list)[i].name,(p->list)[i].age,(p->list)[i].gender,(p->list)[i].tele,(p->list)[i].addr);}
}

左對齊的樣式:

5.刪除、查找指定聯系人

①首先需要判斷Contact數組有效元素是否為空,如果為空直接返回;

②刪除之前需要讀取聯系人姓名,根據姓名來查找,找到了就返回下標,沒找到就返回-1;

③查找這個動作在修改、查找等功能都會用到,所以可以先封裝成一個函數,具有兩個參數,第一個參數是結構體的指針,第二個是查找的名字。

? ? ? ? (1)查找的邏輯:

? ? ? ? ? ? ? ? a.遍歷通訊錄中的PeoInfo數組;

? ? ? ? ? ? ? ? b.判斷數組中的姓名是否和傳入姓名一致;

? ? ? ? ? ? ? ? c.一致就返回下標,沒找到就返回-1;

static int findByname(const Contact* p,char name[])
{assert(p);int i = 0;for ( i = 0; i < p->count; i++){if (strcmp(p->list[i].name,name ) == 0){return i;}}return -1;
}

查找函數不在外界暴露,所以不需要聲明,最好加上關鍵字static修飾,只有本文件能夠訪問。?

④查找到了之后需要根據下標進行刪除,其實就是將數組的此下標的后面元素向前覆蓋即可;需要將有效數據count再-1;

// 通訊錄的刪除
void deleContact(Contact* p)
{char name[NAME_LONG] = { 0 };assert(p);// 判斷通訊錄聯系人數量為0if (p->count == 0){printf("通訊錄為空,無法刪除\n");}printf("請輸入要刪除的聯系人姓名\n");scanf("%s", name);int ret = findByname(p, name);if (ret == -1){printf("刪除的聯系人不存在!\n");return;}else{// 刪除for (int i = ret; i < p->count - 1; i++){p->list[i] = p->list[i + 1];}p->count--; // 有效的數據-1printf("刪除成功!!\n");}
}

6.查找聯系人

? ? ? ? 我們之前已經寫過函數了,所以這里只需要封裝一層。

// 通訊錄的查找
void SearchContact(Contact* p) 
{char name[NAME_LONG];printf("請輸入查找的姓名:\n");scanf("%s",name);int ret = findByname(p, name);if (ret == -1) {printf("該姓名不存在!\n");return;}else {printf("查找成功!以下是該聯系人的信息:\n");printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "年齡", "性別", "電話", "地址");printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",(p->list)[ret].name,(p->list)[ret].age,(p->list)[ret].gender,(p->list)[ret].tele,(p->list)[ret].addr);}
}

7. 修改聯系人

①先根據姓名查找。

②找到了就根據下標來進行修改(和添加聯系人雷同);

③找不到就提示并返回。

// 通訊錄的修改
void ModifyContact(Contact* p) 
{char name[NAME_LONG];printf("請輸入要修改的聯系人姓名:\n");scanf("%s", name);int ret = findByname(p, name);if (ret == -1){printf("該姓名不存在!\n");return;}else{printf("請輸入修改姓名:\n");scanf("%s", (p->list)[ret].name);printf("請輸入修改年齡:\n");scanf("%d", &((p->list)[ret].age));printf("請輸入修改性別:\n");scanf("%s", (p->list)[ret].gender);printf("請輸入修改電話號碼:\n");scanf("%s", (p->list)[ret].tele);printf("請輸入修改地址:\n");scanf("%s", (p->list)[ret].addr);printf("通訊錄修改成功!\n");}
}

8.排序聯系人

①直接使用qsort函數即可,唯一需要注意的是明確按照什么來排序,這里按照姓名來排序

②首先保證傳入的指針有效。

③qsort的第一個參數是排序的起始地址,第二個參數是排序元素的個數,第三個參數是每一個元素的字節數,第四個是一個比較函數,這個比較函數的形參有兩個void*指針,需要強轉成排序的兩個元素的指針類型。

size_t contact_cmp(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}// 通訊錄的排序
void SortContact(Contact* p)
{assert(p);qsort(p->list, p->count, sizeof(p->list[0]), contact_cmp);printf("排序成功!\n");
}

9.完整代碼

9.1 contact.h

#define _CRT_SECURE_NO_WARNINGS
#define N 100
#define NAME_LONG 20
#define GENDER_LONG 10
#define TELE_LONG 12
#define ADDRESS_LONG 30
#include<string.h>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
// 人信息的結構體聲明
typedef struct PeoInfo
{char name[NAME_LONG]; // 姓名int age; // 年齡char gender[GENDER_LONG]; // 性別char tele[TELE_LONG]; // 電話號碼char addr[ADDRESS_LONG]; // 地址
}PeoInfo;// 通訊錄結構體的聲明
typedef struct Contact 
{// 通訊錄假如可以存放一百條信息PeoInfo list[N];// 真實存放的信息的條數int count;
}Contact;// 初始化通訊錄結構體變量
void InitContact(Contact* p);// 通訊錄的增加方法
void addContact(Contact* p);// 通訊錄的顯示
void showContact(const Contact* p);// 通訊錄的刪除
void deleContact(Contact* p);// 通訊錄的查找
void SearchContact(Contact* p);// 通訊錄的修改
void ModifyContact(Contact* p);// 通訊錄的排序
void SortContact(Contact* p);

9.2 contact.c

#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"// 初始化通訊錄結構體變量
void InitContact(Contact* p)
{assert(p);p->count = 0;memset(p, 0, sizeof(p->list)); // list是PeoInfo的結構體數組
}// 通訊錄的增加方法
void addContact(Contact* p)
{assert(p);if (p->count == N){printf("通訊錄已滿!存不下了!\n");return;}printf("請輸入姓名:\n");scanf("%s", (p->list)[p->count].name);printf("請輸入年齡:\n");scanf("%d", &((p->list)[p->count].age));printf("請輸入性別:\n");scanf("%s", (p->list)[p->count].gender);printf("請輸入電話號碼:\n");scanf("%s", (p->list)[p->count].tele);printf("請輸入地址:\n");scanf("%s", (p->list)[p->count].addr);(p->count)++;printf("通訊錄增加成功!\n");
}// 通訊錄的顯示
void showContact(const Contact* p)
{assert(p);int i = 0;printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "年齡", "性別", "電話", "地址");for (i = 0; i < p->count; i++){printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",(p->list)[i].name,(p->list)[i].age,(p->list)[i].gender,(p->list)[i].tele,(p->list)[i].addr);}
}static int findByname(const Contact* p, char name[])
{assert(p);int i = 0;for (i = 0; i < p->count; i++){if (strcmp(p->list[i].name, name) == 0){return i;}}return -1;
}// 通訊錄的刪除
void deleContact(Contact* p)
{char name[NAME_LONG] = { 0 };assert(p);// 判斷通訊錄聯系人數量為0if (p->count == 0){printf("通訊錄為空,無法刪除\n");}printf("請輸入要刪除的聯系人姓名\n");scanf("%s", name);int ret = findByname(p, name);if (ret == -1){printf("刪除的聯系人不存在!\n");return;}else{// 刪除for (int i = ret; i < p->count - 1; i++){p->list[i] = p->list[i + 1];}p->count--; // 有效的數據-1printf("刪除成功!!\n");}
}// 通訊錄的查找
void SearchContact(Contact* p)
{char name[NAME_LONG];printf("請輸入查找的姓名:\n");scanf("%s", name);int ret = findByname(p, name);if (ret == -1){printf("該姓名不存在!\n");return;}else{printf("查找成功!以下是該聯系人的信息:\n");printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "年齡", "性別", "電話", "地址");printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",(p->list)[ret].name,(p->list)[ret].age,(p->list)[ret].gender,(p->list)[ret].tele,(p->list)[ret].addr);}
}// 通訊錄的修改
void ModifyContact(Contact* p)
{char name[NAME_LONG];printf("請輸入要修改的聯系人姓名:\n");scanf("%s", name);int ret = findByname(p, name);if (ret == -1){printf("該姓名不存在!\n");return;}else{printf("請輸入修改姓名:\n");scanf("%s", (p->list)[ret].name);printf("請輸入修改年齡:\n");scanf("%d", &((p->list)[ret].age));printf("請輸入修改性別:\n");scanf("%s", (p->list)[ret].gender);printf("請輸入修改電話號碼:\n");scanf("%s", (p->list)[ret].tele);printf("請輸入修改地址:\n");scanf("%s", (p->list)[ret].addr);printf("通訊錄修改成功!\n");}
}size_t contact_cmp(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}// 通訊錄的排序
void SortContact(Contact* p)
{assert(p);qsort(p->list, p->count, sizeof(p->list[0]), contact_cmp);printf("排序成功!\n");
}

9.3 test.c

#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"
void menu()
{printf("========================================\n");printf("======1.add          2.del      ========\n");printf("======3.search       4.modify   ========\n");printf("======5.show         6.sort     ========\n");printf("======0.exit                    ========\n");printf("========================================\n");
}int main()
{// 聲明通訊錄結構體變量Contact con;// 初始化通訊錄結構體變量InitContact(&con);int input = 0;do{menu();printf("請輸入一個選項:\n");scanf("%d", &input);switch (input){case 1:addContact(&con);break;case 2:deleContact(&con);break;case 3:SearchContact(&con);break;case 4:ModifyContact(&con);break;case 5:showContact(&con);break;case 6:SortContact(&con);break;case 0:printf("程序已退出!\n");break;default:printf("請正確輸入選項!\n");break;}} while (input);return 0;
}

10.功能演示

10.1添加、展示

10.2?刪除

10.3?查找

10.4?修改

10.5?排序

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/90035.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/90035.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/90035.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

緩存三劍客解決方案

緩存三劍客解決方案 1.緩存雪崩 定義&#xff1a; 大量緩存數據在同一時間點集體失效&#xff0c;導致所有請求直接穿透到數據庫&#xff0c;引發數據庫瞬時高負載甚至崩潰。 解決方案&#xff1a; 設置過期隨機值&#xff0c;避免大量緩存同時失效。 // 緩存雪崩防護&#xff…

HTML 頁面禁止縮放功能

頁面禁止縮放 代碼如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"utf-8"><meta name"viewport" content"widthdevice-width, initial-scale1, shrink-to-fitno, maximum-scale1.0, us…

在github上搭建自己主頁

主要是這篇博客進行一些補充。 第一步照做就行 首先是第二步 克隆倉庫到本地 先下載一個git&#xff0c;電腦創建一個新文件夾&#xff0c;然后 git clone xxxxx 注意即使你使用了代理&#xff0c;這里大概率也會報錯&#xff0c;Failed to connect to github.com port 443 …

Laravel 框架NOAUTH Authentication required 錯誤解決方案-優雅草卓伊凡

Laravel 框架NOAUTH Authentication required 錯誤解決方案-優雅草卓伊凡NOAUTH Authentication required 錯誤這個錯誤通常出現在以下幾種情況&#xff1a;Redis 認證問題&#xff1a;如果你的應用使用了 Redis 且配置了密碼API 認證問題&#xff1a;請求需要認證的 API 端點但…

kafka生產端和消費端的僵尸實例以及解決辦法

目錄 一 生產端僵尸 1.1 原因 1.2 問題 1.3解決辦法 1.4 案例 1.4.1 案例1&#xff1a;生產者崩潰后重啟 (同一 transactional.id) 1.4.2 案例2&#xff1a;短暫網絡分區導致的腦裂 1.4.3 案例3&#xff1a;正確 - 解決僵尸 1.4.4 案例4&#xff1a;錯誤 - 無法解決僵…

國產電科金倉數據庫金倉KES V9 2025:AI時代的數據庫融合標桿

國產電科金倉數據庫金倉KES V9 2025&#xff1a;AI時代的數據庫融合標桿 在AI技術迅猛發展的今天&#xff0c;企業數據管理面臨著前所未有的挑戰&#xff1a;異構數據庫兼容難題、多數據模型融合需求、高并發場景性能瓶頸、跨中心容災壓力……這些痛點如同數據流轉的大問題&am…

【STM32】關于STM32F407寫Flash失敗問題的解決辦法

問題描述 在使用正點原子的STM32F407寫flash例程時&#xff0c;發現STMFLASH_Write函數沒辦法寫入數據到flash&#xff0c;原始代碼輸入下&#xff1a; 隨后對每一行代碼的結果進行分析&#xff0c;發現87行的“FLASH_ProgramWord(WriteAddr,*pBuffer)”返回值是7&#xff0c;一…

CUDA與RISC-V的融合:打破架構霸權,重塑AI計算未來

當x86和Arm統治數據中心十余年后,一家GPU巨頭正悄悄將十億顆RISC-V核心嵌入其系統。如今,它決定拆除CPU架構的圍墻。 2025年7月,上海張江科學會堂。英偉達硬件工程副總裁Frans Sijstermanns在第五屆RISC-V中國峰會上宣布:英偉達正式啟動CUDA向RISC-V架構的移植工作。 這個…

微信二維碼掃描登錄流程詳解

二維碼掃描登錄流程細節&#xff08;項目經驗&#xff09; 1&#xff1a; 獲取二維碼信息 PC會優先存放服務器生成的唯一密鑰&#xff1a; 比如 source、secret 以密文形式存儲大致發送字段&#xff1a; sourcesecretmac(mac 地址) 服務器生成 二維碼信息&#xff1a;二維碼字符…

日本上市IT企業|8月125日將在大連舉辦赴日it招聘會

株式會社GSD的核心戰略伙伴貝斯株式會社&#xff0c;將于2025年8月25日在大連香格里拉大酒店商務會議室隆重舉辦赴日技術人才專場招聘會。本次招聘會面向全國范圍內的優秀IT人才&#xff0c;旨在為貝斯株式會社東京本社長期發展招募優質的系統開發與管理人才。招聘計劃&#xf…

Python 數據分析與可視化:從基礎到進階的技術實現與優化策略

數據分析與可視化是數據科學領域的核心技能,Python 憑借其豐富的庫生態和靈活的編程范式,成為該領域的首選工具。本文將系統講解 Python 數據分析與可視化的技術棧實現,從基礎操作到性能優化,結合實戰場景提供可復用的解決方案。 數據分析核心庫技術解析 Pandas 數據處理…

Rust Web 全棧開發(十):編寫服務器端 Web 應用

Rust Web 全棧開發&#xff08;十&#xff09;&#xff1a;編寫服務器端 Web 應用Rust Web 全棧開發&#xff08;十&#xff09;&#xff1a;編寫服務器端 Web 應用創建成員庫&#xff1a;webappmodelshandlersrouterserrorsmodsvrstaticteachers.htmlregister.htmlbootstrap.m…

每日面試題11:JVM

深入理解JVM&#xff1a;Java的“心臟”如何驅動程序運行&#xff1f;為什么需要JVM&#xff1f;你是否想過&#xff0c;為什么用Java寫的程序&#xff0c;能在Windows、Linux、macOS上“無縫運行”&#xff1f;為什么開發者無需為不同操作系統重寫代碼&#xff1f;這背后的核心…

Linux網絡信息(含ssh服務和rsync)

73.telnet&#xff1a;測試端口連通性用法&#xff1a;telnet 主機名或IP 端口號測試目標主機的指定端口是否開放&#xff0c;檢查網絡服務連通性。eg&#xff1a;telnet www.baidu.com 80# 說明&#xff1a;# - 如果連接成功&#xff0c;顯示 "Connected to ..."。…

【PTA數據結構 | C語言版】我愛背單詞

本專欄持續輸出數據結構題目集&#xff0c;歡迎訂閱。 文章目錄題目代碼題目 作為一個勤奮的學生&#xff0c;你在閱讀一段英文文章時&#xff0c;是否希望有個程序能自動幫你把沒有背過的生詞列出來&#xff1f;本題就請你實現這個程序。 輸入格式&#xff1a; 輸入第 1 行給…

如何使用電腦連接小米耳機(紅米 redmi耳機)

如何使用電腦連接小米&#xff08;紅米 redmi&#xff09;耳機Redmi耳機連接電腦的具體步驟如下注意事項和常見問題解決方法&#xff1a;Redmi耳機連接電腦的具體步驟如下 打開耳機倉蓋&#xff1a; 首先&#xff0c;打開Redmi耳機的充電倉蓋&#xff0c;但不需要取出耳機。進…

排序算法—交換排序(冒泡、快速)(動圖演示)

目錄 十大排序算法分類?編輯 冒泡排序 算法步驟&#xff1a; 動圖演示&#xff1a; 性能分析&#xff1a; 代碼實現&#xff08;Java&#xff09;&#xff1a; 快速排序&#xff08;挖坑法&#xff09; 算法步驟&#xff1a; 動圖演示&#xff1a; 性能分析&#xff1…

2023 年 5 月青少年軟編等考 C 語言八級真題解析

目錄 T1. 道路 思路分析 T2. Rainbow 的商店 思路分析 T3. 冰闊落 I 思路分析 T4. 青蛙的約會 思路分析 T1. 道路 題目鏈接:SOJ D1216 N N N 個以 1 ~ N 1 \sim N 1~N 標號的城市通過單向的道路相連,每條道路包含兩個參數:道路的長度和需要為該路付的通行費(以金幣的數…

【vue-4】深入理解 Vue 3 中的 v-for 指令

Vue.js 作為現代前端框架的代表之一&#xff0c;其模板指令系統提供了強大的數據綁定和渲染能力。其中&#xff0c;v-for 指令是 Vue 中最常用且最重要的指令之一&#xff0c;它允許我們基于數據源循環渲染元素或組件。在 Vue 3 中&#xff0c;v-for 保留了一貫的簡潔語法&…

《R for Data Science (2e)》免費中文翻譯 (第1章) --- Data visualization(1)

寫在前面 本系列推文為《R for Data Science (2)》的中文翻譯版本。所有內容都通過開源免費的方式上傳至Github&#xff0c;歡迎大家參與貢獻&#xff0c;詳細信息見&#xff1a; Books-zh-cn 項目介紹&#xff1a; Books-zh-cn&#xff1a;開源免費的中文書籍社區 r4ds-zh-cn …