Linux C 编程实现通讯录

在写代码前,构建其代码层次, 使代码具有模块化。
我会将代码分为四层:

  1. 数据层
  2. 接口层
  3. 业务逻辑层
  4. 用户界面层

这样的分层有助于模块化和代码的可维护性。每一层都有其明确的职责,使得代码更易于理解和修改。当需要对某一层进行修改或优化时,可以专注于该层,而不必担心影响到其他层的代码。

  • 我们首先来看数据层
    这里数据层LIST_INSERT()LIST_REMOVE()作用是链表操作的宏。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


#define NAME_LENGTH			16
#define PHONE_LENGTH		32
#define BUFFER_LENGTH		128
#define MIN_TOKEN_LENGTH	5

#define INFO			printf


#define LIST_INSERT(item, list) do {	\
	item->prev = NULL;					\
	item->next = list;					\
	if ((list) != NULL) (list)->prev = item; \
	(list) = item;						\
} while(0)


#define LIST_REMOVE(item, list) do {	\
	if (item->prev != NULL) item->prev->next = item->next; \
	if (item->next != NULL) item->next->prev = item->prev; \
	if (list == item) list = item->next; 					\
	item->prev = item->next = NULL;							\
} while(0)

至于为什么使用宏可以看这篇文章 为什么使用宏

  • 数据层的struct personstruct contacts:定义了联系人和联系人列表的数据结构。
struct person {
	char name[NAME_LENGTH];
	char phone[PHONE_LENGTH];

	struct person *next;
	struct person *prev;
};


struct contacts {
	struct person *people;
	int count;
};

数据层中的save_file()load_file()`:负责将联系人信息保存到文件和从文件中加载联系人信息。

int save_file(struct person *people, const char *filename) {

	FILE *fp = fopen(filename, "w");
	if (fp == NULL) return -1;

	struct person *item = NULL;
	for (item = people; item != NULL;item = item->next) {
		fprintf(fp, "name: %s, phone: %s\n", item->name, item->phone);
		fflush(fp);
	}

	fclose(fp);
}
int load_file(struct person **ppeople, int *count, const char *filename) {

	FILE *fp = fopen(filename, "r");
	if (fp == NULL) return -1;

	while (!feof(fp)) {

		char buffer[BUFFER_LENGTH] = {0};
		fgets(buffer, BUFFER_LENGTH, fp);
		int length = strlen(buffer);
		INFO("length : %d\n", length);

		// name: qiuxiang,telephone: 98765678123
		char name[NAME_LENGTH] = {0};
		char phone[PHONE_LENGTH] = {0};

		if (0 != parser_token(buffer, length, name, phone)) {
			continue;
		}

		struct person *p = (struct person*)malloc(sizeof(struct person));
		if (p == NULL) return -2;

		memcpy(p->name, name, NAME_LENGTH);
		memcpy(p->phone, phone, PHONE_LENGTH);

		person_insert(ppeople, p);
		
		(*count) ++;
	}

	fclose(fp);

	return 0;
}

数据层中的parser_token():解析文件中的字符串,提取联系人的姓名和电话。

int parser_token(char *buffer, int length, char *name, char *phone) {

	if (buffer == NULL) return -1;
	if (length < MIN_TOKEN_LENGTH) return -2;

	int i = 0, j = 0, status = 0;
	for (i = 0;buffer[i] != ',';i ++) {
		if (buffer[i] == ' ') {
			status = 1;
		} else if (status == 1) {
			name[j ++] = buffer[i];
		}
	}

	status = 0;
	j = 0;
	for (;i < length;i ++) {
		if (buffer[i] == ' ') {
			status = 1;
		} else if (status == 1) {
			phone[j ++] = buffer[i];
		}
	}

	INFO("file token : %s --> %s\n", name, phone);

	return 0;
	
}

  • 接下来是接口层:这一层提供了一组接口,用于操作数据层的结构。这些函数提供了对联系人链表的基本操作。
// define interface 
char name[NAME_LENGTH] = {0};
char phone[PHONE_LENGTH] = {0};
int person_insert(struct person **ppeople, struct person *ps) {
	if (ps == NULL) return -1;

	LIST_INSERT(ps, *ppeople);

	return 0;
}

int person_delete(struct person **ppeople, struct person *ps) {

	if (ps == NULL) return -1;
	if (ppeople == NULL) return -2;

	LIST_REMOVE(ps, *ppeople);

	return 0;
	
}

struct person* person_search(struct person *people, const char *name) {

	struct person *item = NULL;
	for (item = people;item != NULL;item = item->next) {
		if (!strcmp(name, item->name)) 
			break;
	}

	return item;
}

int person_traversal(struct person *people) {

	struct person *item = NULL;
	for (item = people;item != NULL;item = item->next) {
		INFO("name: %s,phone: %s\n", item->name, item->phone);
	}

	return 0;
}
  • 业务逻辑层:这一层包含了程序的主要业务逻辑,处理用户的输入和程序的流程控制。
    这些函数根据用户的操作(添加、打印、删除、搜索、保存和加载)来处理联系人信息。
int insert_entry(struct contacts *cts) {

	if (cts == NULL) return -1;

	struct person *p = (struct person*)malloc(sizeof(struct person));
	if (p == NULL) return -2;
	memset(p, 0, sizeof(struct person));
	
	// name
	INFO("Please Input Name: \n");
	scanf("%s", p->name); //
	
	// phone
	INFO("Please Input Phone: \n");
	scanf("%s", p->phone);

	// add people
	if (0 != person_insert(&cts->people, p)) {
		free(p);
		return -3;
	}
	cts->count ++;
	INFO("Insert Success\n");

	return 0;
	
}


int print_entry(struct contacts *cts) {

	if (cts == NULL) return -1;

	// cts->people

	person_traversal(cts->people);
}

int delete_entry(struct contacts *cts) {
	
	if (cts == NULL) return -1;

	INFO("Please Input Name : \n");
	char name[NAME_LENGTH] = {0};
	scanf("%s", name);

	// person
	struct person *ps = person_search(cts->people, name);
	if (ps == NULL) {
		INFO("Person don't Exit\n");
		return -2;
	}
	INFO("name: %s, phone: %s\n", ps->name, ps->phone);

	// delete
	person_delete(&cts->people, ps);
	free(ps);

	return 0;
}


int search_entry(struct contacts *cts) {

	if (cts == NULL) return -1;

	INFO("Please Input Name : \n");
	char name[NAME_LENGTH] = {0};
	scanf("%s", name);

	// person
	struct person *ps = person_search(cts->people, name);
	if (ps == NULL) {
		INFO("Person don't Exit\n");
		return -2;
	}

	INFO("name: %s,phone: %s\n", ps->name, ps->phone);

	return 0;
}

int save_entry(struct contacts *cts) {

	if (cts == NULL) return -1;

	INFO("Please Input Save Filename :\n");
	char filename[NAME_LENGTH] = {0};
	scanf("%s", filename);

	save_file(cts->people, filename);
	
}

int load_entry(struct contacts *cts) {
	if (cts == NULL) return -1;

	INFO("Please Input Load Filename :\n");
	char filename[NAME_LENGTH] = {0};
	scanf("%s", filename);

	load_file(&cts->people, &cts->count, filename);
}

    1. 用户界面层:这一层处理与用户的交互。
    • menu_info():显示程序菜单。
void menu_info(void) {

	INFO("\n\n********************************************************\n");
	INFO("***** 1. Add Person\t\t2. Print People ********\n");
	INFO("***** 3. Del Person\t\t4. Search Person *******\n");
	INFO("***** 5. Save People\t\t6. Load People *********\n");
	INFO("***** Other Key for Exiting Program ********************\n");
	INFO("********************************************************\n\n");

}
  • main函数入口
int main() {

	struct contacts *cts = (struct contacts *)malloc(sizeof(struct contacts));
	if (cts == NULL) return -1;//malloc返回的是void*类型的指针 所以要转换类型
 
	memset(cts, 0, sizeof(struct contacts));

	while (1) {

		menu_info();

		int select = 0;
		scanf("%d", &select);

		switch (select) {

			case OPER_INSERT:
				insert_entry(cts);
				break;

			case OPER_PRINT:
				print_entry(cts);
				break;

			case OPER_DELETE:
				delete_entry(cts);
				break;

			case OPER_SEARCH:
				search_entry(cts);
				break;

			case OPER_SAVE:
				save_entry(cts);
				break;

			case OPER_LOAD:
				load_entry(cts);
				break;

			default:
				goto exit;
				
		}

	}

exit:

	free(cts);
	
	return 0;

}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值