系統程式設計——電子通訊錄(自儲存)
阿新 • • 發佈:2018-12-21
1、功能要求
製作一個電子通訊錄,通過該通訊錄能存入好友 ID 號、姓名(英文)、手機號碼、家庭住址、公司電話。
I、 主介面:主要顯示軟體功能
A) 新增好友資訊。
B) 列表好友資訊。(包含排序功能)
C) 搜尋好友
D) 刪除好友
II、新增好友:
使用者輸入 “1” 命令後,讓使用者輸入好友資訊。新增成功或失敗都需要提示
使用者
III、 列表好友:
使用者輸入 “2” 命令後,好友資訊升序排列。
IV、搜尋好友:
使用者輸入 “3” 命令後,讓使用者輸入將要搜尋好友姓名查詢。如果未搜尋到
請友好提示。如果搜尋到,顯示出該好友資訊。
V、刪除好友:
使用者輸入 “4” 命令後,讓用輸入將要刪除好友姓名刪除,如果存在同名的多個好友,則列表出,所有同名的好友資訊,讓使用者通過輸入ID 號刪除。提示用
戶刪除成功。
2、程式檔案
I、
在電子通訊錄(自儲存)/src目錄下新建main.c、Contact.c檔案
// main.c #include <stdio.h> // 包含open函式 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include "Contact.h" int main() { // 建立連結串列 List *ls = CreateList(); if (NULL == ls) { printf ("建立失敗\n"); return -1; } // 開啟檔案 BYTE_4 fd = open("Contact", O_RDWR | O_CREAT | O_APPEND, 0766); if (-1 == fd) { perror("開啟Contact檔案失敗"); return -1; } // 判斷Contact檔案是否為空,並進行相應操作 Empty_File(ls, fd); // 顯示主選單,並進行相應操作 Menu(ls); // 退出前判斷連結串列是否為空,並進行相應操作 myWrite(ls, fd); Destory(ls); close(fd); return 0; }
// contact.c #include <stdio.h> // 包含malloc()、system("clear") #include <stdlib.h> // 包含strcmp() #include <string.h> // 包含read、write函式 #include <unistd.h> // 包含ftruncate函式 #include <sys/types.h> #include "Contact.h" // 建立連結串列 List *CreateList(void) { List *ls = (List*)malloc(sizeof(List)/sizeof(char)); if (NULL == ls) { return NULL; } ls->head = (Node*)malloc(sizeof(Node)/sizeof(char)); if (NULL == ls->head) { free(ls); return NULL; } ls->head->next = NULL; return ls; } // 初始執行前判斷Contact檔案是否為空,並進行相應操作 void Empty_File(List *ls, BYTE_4 fd) { // 將檔案指標定位到結尾的地方,以判斷是否為空檔案 // 當呼叫成功時則返回目前的讀寫位置,也就是距離檔案開頭多少個位元組。 off_t ret_last = lseek(fd, 0, SEEK_END); if (-1 == ret_last) { perror("檔案指標定位失敗"); return; } if (ret_last > 0) { // 將檔案中資料匯入連結串列 file_to_contact(fd, ls); } return; } // 將檔案中資料匯入連結串列 void file_to_contact(BYTE_4 fd, List *ls) { if (NULL == ls) { return; } // 指向檔案開頭 off_t ret = lseek(fd, 0, SEEK_SET); if (-1 == ret) { perror("檔案指標定位失敗"); return; } BYTE_4 ret_tmp = 0; BYTE_4 id; // 不指向檔案末尾時就將檔案中的資料匯入到連結串列中 while((ret_tmp = read(fd, &id, sizeof(BYTE_4))) != 0) { Node *node = (Node *)malloc(sizeof(Node)/sizeof(BYTE_1)); if (NULL == node) { return; } // 如果返回0,表示已到達檔案尾或無可讀取的資料。錯誤返回-1,並將根據不同的錯誤原因適當的設定錯誤碼。 // 讀檔案中ID號、姓名、手機號碼、家庭住址、公司,並將其寫入連結串列 // ssize_t ret_id = read(fd, &node->id, sizeof(BYTE_4)); node->id = id; ssize_t ret_name = read(fd, node->name, 10*sizeof(BYTE_1)); ssize_t ret_mobilephone = read(fd, &node->mobilephone, sizeof(BYTE_8)); ssize_t ret_homeaddress = read(fd, node->homeaddress, 20*sizeof(BYTE_1)); ssize_t ret_businessnumber = read(fd, &node->businessnumber, sizeof(BYTE_8)); node->next = NULL; Node *tmp = ls->head; while (tmp->next) { tmp = tmp->next; } tmp->next = node; } // 清空檔案 ftruncate(fd, 0); return; } // 主介面的顯示 BOOL Menu(List *ls) { if (NULL == ls) { return ERROR; } system ("clear"); BYTE_1 buf[10]; // search_flag = 1時,搜尋不成功! BYTE_4 search_flag = 1; // delete_flag = 1時,刪除不成功! BYTE_4 delete_flag = 1; while (1) { printf ("\n \n \n \n \n \n \n \n"); printf ("\t\t\t\t\t\t**************************************************\n"); printf ("\t\t\t\t\t\t* *\n"); printf ("\t\t\t\t\t\t*\t\t 0.退出 *\n"); printf ("\t\t\t\t\t\t*\t\t 1.新增好友 *\n"); printf ("\t\t\t\t\t\t*\t\t 2.列表好友 *\n"); printf ("\t\t\t\t\t\t*\t\t 3.搜尋好友 *\n"); printf ("\t\t\t\t\t\t*\t\t 4.刪除好友 *\n"); printf ("\t\t\t\t\t\t* *\n"); printf ("\t\t\t\t\t\t**************************************************\n"); printf ("\n\t\t\t\t\t\t請輸入指令:"); // fgets(buf, 10, stdin); ==>改用這條指令有問題,暫未解決 scanf ("%s", buf); // 退出、增、顯、查、刪 switch (buf[0]) { case ADD: Add_Contact(ls); break; case DISPLAY: Display_Contact(ls); break; case SEARCH: // search_flag = 1時,搜尋不成功! // 搜尋成功,返回0 while (1 == search_flag) { search_flag = Search_Contact(ls); } search_flag = 1; break; case DELETE: // delete_flag = 1時,不成功! // 刪除成功,返回0 while (1 == delete_flag) { delete_flag = Delete_Contact(ls); } delete_flag = 1; break; case QUIT: // 清屏 system("clear"); return; default: printf ("\t\t\t\t\t\t輸入指令有誤,請重新輸入!"); sleep(1); system("clear"); break; } } } // 新增好友資訊、尾插 BOOL Add_Contact(List *ls) { if (NULL == ls) { return ERROR; } // 清屏 system("clear"); Node *node = (Node *)malloc(sizeof(Node)/sizeof(BYTE_1)); if (NULL == node) { return ERROR; } // flag = 1 新增成功 flag = 0 新增失敗 BYTE_4 flag = 0; printf ("\n \n \n \n \n \n \n \n"); printf ("\t\t\t\t\t\t\t請輸入好友ID號:"); scanf ("%d", &node->id); printf ("\t\t\t\t\t\t\t請輸入好友姓名:"); scanf ("%s", node->name); printf ("\t\t\t\t\t\t\t請輸入好友手機號碼:"); scanf ("%lld", &node->mobilephone); printf ("\t\t\t\t\t\t\t請輸入好友家庭住址:"); scanf ("%s", node->homeaddress); printf ("\t\t\t\t\t\t\t請輸入好友公司電話:"); scanf ("%lld", &node->businessnumber); node->next = NULL; // 頭結點 Node *tmp = ls->head; // 作表示式時,取指標變數中存放的地址值 while (tmp->next) { tmp = tmp->next; } tmp->next = node; flag = 1; // 清屏 // system("clear"); if (1 == flag) { printf ("\n"); printf ("\t\t\t\t\t\t\t好友資訊新增成功!\n"); sleep(1); system("clear"); } else { printf ("\t\t\t\t\t\t好友資訊新增失敗!\n"); } return TRUE; } // 列表好友資訊 BOOL Display_Contact(List *ls) { if (NULL == ls) { return ERROR; } if (NULL == ls->head->next) { printf ("\t\t\t\t\t\t您暫未新增聯絡人!"); sleep(1); system("clear"); return TRUE; } system("clear"); // 氣泡排序:按ID從小到大 Sort(ls); printf("\n\t\t\t\t\tID號\t姓名\t手機號碼\t\t家庭住址\t\t公司電話\n"); Node *tmp = ls->head->next; while (tmp) { printf ("\t\t\t\t\t%-4d\t", tmp->id); printf ("%-4s\t", tmp->name); printf ("%-13lld\t\t", tmp->mobilephone); printf ("%-10s\t\t", tmp->homeaddress); printf ("%-13lld\n", tmp->businessnumber); tmp = tmp->next; } } // 氣泡排序 BOOL Sort(List *ls) { if((ls->head -> next == NULL) || (ls->head->next->next == NULL)) { return ERROR; } Node *pre, *cur, *next, *end, *temp; Node *tmp = ls->head; end = NULL; // 從連結串列頭開始將較大值往後沉 while(tmp->next != end) { for(pre = tmp, cur = pre->next, next = cur->next; next != end; pre = pre->next, cur = cur->next, next = next->next) { // 相鄰的節點,按id進行比較 if(cur->id > next->id) { cur->next = next->next; pre->next = next; next->next = cur; temp = next; next = cur; cur = temp; } } end = cur; } } // 搜尋好友:按姓名 BYTE_4 Search_Contact(List *ls) { if (NULL == ls) { return -1; } // 清屏 system("clear"); BYTE_1 Name[10]; printf ("\n \n \n \n \n \n \n \n"); printf ("\t\t\t\t\t\t\t請輸入您想查詢的好友的姓名:"); scanf ("%s", Name); // tmp相當於頭結點 Node *tmp = ls->head; while (tmp->next) { if (0 == strcmp(tmp->next->name, Name)) { system("clear"); printf ("\t\t\t\t\t\t您所搜尋的好友的資訊如下:\n\n"); printf ("\t\t\t\t\t\tID號:%d\n", tmp->next->id); printf ("\t\t\t\t\t\t姓名:%s\n", tmp->next->name); printf ("\t\t\t\t\t\t手機號碼:%lld\n", tmp->next->mobilephone); printf ("\t\t\t\t\t\t家庭住址:%s\n", tmp->next->homeaddress); printf ("\t\t\t\t\t\t公司電話:%lld\n", tmp->next->businessnumber); return 0; } tmp = tmp->next; } printf ("\t\t\t\t\t\t\t您所搜尋的姓名為 %s 的好友不存在!\n", Name); printf ("\t\t\t\t\t\t\t請再次輸入您想查詢的好友的姓名!"); sleep(1); system("clear"); return 1; } // 刪除好友:按姓名 // 姓名相同,再按ID刪除 BYTE_4 Delete_Contact(List *ls) { if (NULL == ls) { return -1; } // 統計姓名相同的人數 BYTE_4 count = 0; BYTE_4 Id; BYTE_1 Name[10]; system("clear"); printf ("\n \n \n \n \n \n \n \n"); printf ("\t\t\t\t\t\t請輸入您想刪除的好友的姓名:"); scanf ("%s", Name); Node *tmp = ls->head; // 初始:頭結點中存的地址值 while (tmp->next) { if (0 == strcmp(tmp->next->name, Name)) { count++; } tmp = tmp->next; } // tmp回位 tmp = ls->head; if (0 == count) { system("clear"); printf ("\t\t\t\t\t\t您所刪除的姓名為 %s 的好友不存在!\n", Name); printf ("\t\t\t\t\t\t請再次輸入您想刪除的好友的姓名!"); sleep(1); return 1; } // 姓名不重複時,直接刪除! while (1 == count) { while (tmp->next) { if (0 == strcmp(tmp->next->name, Name)) { Node *p = tmp->next; tmp->next = p->next; free(p); printf ("\t\t\t\t\t\t刪除成功!"); sleep(1); system("clear"); return 0; } tmp = tmp->next; } } // 姓名重複時,按ID刪除 while(count > 1) { printf ("\t\t\t\t\t\t姓名為 %s 的好友共有 %d 人,其資訊如下:\n\n", Name, count); printf ("\t\t\t\t\t\tID號\t姓名\t手機號碼\t\t家庭住址\t\t公司電話\n"); while (tmp->next) { if (0 == strcmp(tmp->next->name, Name)) { printf ("\t\t\t\t\t\t%-4d\t", tmp->next->id); printf ("%-4s\t", tmp->next->name); printf ("%-13lld\t\t", tmp->next->mobilephone); printf ("%-10s\t\t", tmp->next->homeaddress); printf ("%-13lld\n", tmp->next->businessnumber); } tmp = tmp->next; } // tmp回位 tmp = ls->head; printf ("\n"); printf ("\t\t\t\t\t\t請輸入您想刪除的好友的ID:"); scanf ("%d", &Id); while (tmp->next) { if (tmp->next->id == Id) { Node *p = tmp->next; tmp->next = p->next; free(p); system("clear"); printf ("\t\t\t\t\t\t刪除成功!\n"); return 0; } tmp = tmp->next; } } return FALSE; } // 退出前判斷連結串列是否為空,並進行相應操作 void myWrite(List *ls, BYTE_4 fd) { if (NULL == ls) { return; } // 判斷是否為空連結串列,為空連結串列直接退出,不用執行寫入 if (NULL == ls->head->next) { return; } // O_APPEND:每次寫之前,將標誌位移動到檔案的末端。 // fd:檔案描述符 Node *tmp = ls->head->next; while(tmp) { // 寫入ID號、姓名、手機號碼、家庭住址、公司 ssize_t ret_id = write(fd, &tmp->id, sizeof(BYTE_4)); ssize_t ret_name = write(fd, tmp->name, 10*sizeof(BYTE_1)); ssize_t ret_mobilephone = write(fd, &tmp->mobilephone, sizeof(BYTE_8)); ssize_t ret_homeaddress = write(fd, tmp->homeaddress, 20*sizeof(BYTE_1)); ssize_t ret_businessnumber = write(fd, &tmp->businessnumber, sizeof(BYTE_8)); tmp = tmp->next; } } // 銷燬 void Destory(List *ls) { if (NULL == ls) { return; } Node *tmp = ls->head; while (tmp->next) { Node *p = tmp->next; tmp->next = p->next; free(p); } free(ls->head); free(ls); }
II、
在電子通訊錄(自儲存)/include目錄下建立Contact.h檔案
// Contact.h
#ifndef _CONTACT_H_
#define _CONTACT_H_
// 退出、增、顯、查、刪
enum menu{QUIT = '0', ADD, DISPLAY, SEARCH, DELETE};
typedef enum {TRUE, FALSE, ERROR} BOOL;
typedef char BYTE_1;
typedef int BYTE_4;
typedef long long BYTE_8;
// 每一個結點中應包含一個指標變數,用它來存放下一結點的地址
typedef struct _node
{
// 資料域
BYTE_4 id;// ID號
BYTE_1 name[10];// 姓名
BYTE_8 mobilephone;// 手機號碼
BYTE_1 homeaddress[20];// 家庭住址
BYTE_8 businessnumber;// 公司電話
// 指標域
struct _node *next;
}Node;
typedef struct _list
{
// 頭節點
Node *head;
}List;
// 建立連結串列
List *CreateList(void);
// 初始執行前判斷Contact檔案是否為空,並進行相應操作
void Empty_File(List *ls, BYTE_4 fd);
// 將檔案中資料匯入連結串列
void file_to_contact(BYTE_4 fd, List *ls);
// 主介面的顯示
BOOL Menu(List *ls);
// 新增好友資訊、尾插
BOOL Add_Contact(List *ls);
// 列表好友資訊
BOOL Display_Contact(List *ls);
// 氣泡排序
BOOL Sort(List *ls);
// 搜尋好友:按姓名
BYTE_4 Search_Contact(List *ls);
// 刪除好友:按姓名
BYTE_4 Delete_Contact(List *ls);
// 退出前判斷連結串列是否為空,並進行相應操作
void myWrite(List *ls, BYTE_4 fd);
// 銷燬
void Destory(List *ls);
#endif // _CONTACT_H
III、在電子通訊錄(自儲存)目錄下新建Makefile檔案
src1 = $(wildcard ./src/*.c)
obj1 = $(patsubst ./src/%.c, ./obj/%.o, $(src1))
target = ./bin/a.out
all:$(target)
$(target):$(obj1)
gcc $(^) -o $(@)
$(obj1):./obj/%.o:./src/%.c
gcc -c $(^) -I ./include -o $(@) -g
.PHONY:clean all
clean:
-rm -rf $(target) $(obj1)
3、測試結果
略