1. 程式人生 > >系統程式設計——電子通訊錄(自儲存)

系統程式設計——電子通訊錄(自儲存)

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、測試結果