[Advanced C Language] Address Book (Full Version)

1. Basic framework and functions

Insert image description here

Preparation work:
1. Sub-module development
 1.test.c, implement the test link of the module
 2.contact.c, implement the function of the function
 3.contact.h, implement the naming of the function and the use of the structure.
The following focuses on the implementation of the function. function, a header file is provided at the beginning to improve the readability of this article.

2. Details of the header file

#include<stdio.h>//printf,scanf,perror
#include<stdlib.h>//system,malloc,realloc
#include<string.h>//strcmp
//对开辟的大小,方便之后的统一修改。
enum SIZE
{
    
    
	NAME_SIZE=10,
	SEX_SIZE=5,
	TELE_SIZE=15,
	ADDRE_SIZE=20,
	DEFAULT_SIZE=2,
	ADD_SIZE=2
};
//功能的选项数字赋予一定的意义
enum function
{
    
    
	ADD=1,
	DEL,
	FIND,
	MODIFY,
	PRINT,
	SORT,
	EXIT
};
//联系人信息
typedef struct people
{
    
    
	char name[NAME_SIZE];
	int age;
	char sex[SEX_SIZE];
	char tele[TELE_SIZE];
	char addre[ADD_SIZE];
}peo;
//通讯录信息
typedef struct Contact
{
    
    
	int count;//联系人个数
	int capacity;//当前最大容量
	peo CON[];//柔性数组利用内存池的概念,使内存管理更加高效,并且free只要一次,更方便。
}contact;

//菜单
void menu();
//初始化通讯录
void Init_contact(contact** p);//要修改一级指针所以要传一级指针的地址用二级指针来接收
//添加联系人信息
void Add_Contact(contact** p);//同理
//打印通讯录
void Print_Contact(contact* p);
//删除联系人信息
void Del_Contact(contact* p);
//查找联系人信息
void Find_Contact(contact* p);
//修改联系人信息
void Modify_Contact(contact* p);
//释放已开辟的内存空间
void Distory_Contact(contact** p);//同理
//按照名字进行排序通讯录
void Sort_Contact(contact* p);

3. Implementation of functions

1.Print menu

void menu()
{
    
    
	printf("******************************************\n");
	printf("******** 1.增加联系人 2.删除联系人 *******\n");
	printf("******** 3.查找联系人 4.修改联系人 *******\n");
	printf("******** 5.打印联系人 6.排序联系人 *******\n");
	printf("******** 7.退出通讯录              *******\n");
	printf("******************************************\n");

}

No parameters, no return type (you can write return;)

2.Initialize address book

void Init_contact(contact** p)
{
    
    
	*p = (contact*)malloc(4*2 + sizeof(peo) * DEFAULT_SIZE);
	if (*p != NULL)
	{
    
    
		(*p)->count = 0;
		(*p)->capacity = DEFAULT_SIZE;
	}
	else
	{
    
    
		perror("Init_contact");
		return;
	}
}

1. The space allocated here defaults to two integers + the number of contacts that can be initially stored (2)
2. The structure pointer can only access the first-level pointer. To change the first-level pointer, you must pass the second-level pointer to the function. Pointer
3. Calloc can also be used here, but it is more troublesome and slightly less efficient than malloc.
4. Pay attention to checking the address returned by opening up the space.

3. Add contact information

void Add_Contact(contact** p)
{
    
    
	int judge = 0;
	//判断内存是否够
	if ((*p)->count== (*p)->capacity)
	{
    
    
		printf("通讯录已满,请确定是否要增容(1是0否):");
		scanf("%d", &judge);
		if (judge)
		{
    
    
			contact* ptr = (contact*)realloc(*p, 4 * 2 + sizeof(peo) *   ((*p)->capacity+ ADD_SIZE));
			if (ptr != NULL)
			{
    
    
				(*p) = ptr;
				(*p)->capacity += ADD_SIZE;
				printf("增容成功\n");
			}
			else
			{
    
    
				perror("Add_Contact");
				printf("增容失败\n");
				return;
			}
		}
		else
		{
    
    
			return;
		}

	}
    //输入信息部分
	printf("请输入姓名:");
	scanf("%s", (*p)->CON[(*p)->count].name);

	printf("请输入年龄:");
	scanf("%d", &(*p)->CON[(*p)->count].age);

	printf("请输入性别:");
	scanf("%s", (*p)->CON[(*p)->count].sex);

	printf("请输入电话:");
	scanf("%s", (*p)->CON[(*p)->count].tele);

	printf("请输入住址:");
	scanf("%s", (*p)->CON[(*p)->count].addre);
	printf("增加成功!\n");
	(*p)->count++;
}

1. Check the return value of realloc. If it is empty, report an error promptly.
2. After entering the information, add 1 to the number of contacts.
3. When entering the information, determine the type of member being accessed to determine whether to add the address
. : When inputting the address array name and the array name, the effect is the same, because their values ​​are the same, but their meanings are different.

4.Print contact information

void Print_Contact(contact* p)
{
    
    
	if (p->count == 0)
	{
    
    
		printf("通讯录为空!\n");
		return;
	}
	printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", 
												"年龄", 
												"性别", 
												"电话", 
												"住址");
	int i = 0;
	for (i = 0; i < p->count; i++)
	{
    
    
		printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[i].name, 
													p->CON[i].age, 
													p->CON[i].sex, 
													p->CON[i].tele, 
													p->CON[i].addre);
	}
}

1. When there is no information in the address book, you should be reminded in time.
2. Pay attention to the relationship between the subscript and the number of contact information.
3. If the printed content is too long, it is recommended to wrap the line to improve the readability of the code.
4. When printing, you need to align and set the format for printing, so that the printed content will be simpler and more beautiful.

5. Find a name

const int Find_By_name(contact* p,char*arr)
{
    
    
	int i = 0;
	for (i = 0; i < p->count; i++)
	{
    
    
		if (strcmp(p->CON[i].name, arr) == 0)
		{
    
    
			return i;
		}
	}
	return -1;
}

1. Since this function only serves the module that implements the function, const is added.
2. strcmp compares two strings and returns 0 if they are equal.
3. If there is no string, it returns -1. If found, it returns its subscript
4. This The function is used to find contacts, modify contacts, and delete contacts.

6. Delete contact information

void Del_Contact(contact* p)
{
    
    
	char name[20] = {
    
     0 };
	printf("请输入要删除的联系人:");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret!=-1)
	{
    
    
		int i = 0;
		for (i = ret; i < p->count-1; i++)
		{
    
    
			p->CON[ret] = p->CON[ret + 1];
		}
		p->count--;
		printf("已删除\n");
	}
	else
	{
    
    
		printf("查无此人\n");
	}
}

1. The idea of ​​deleting here is to overwrite. As for the last element, adding it after the number of contacts is reduced will overwrite it.
2. Pay attention to the range of i here. Combining the following code, we can see that the array out-of-bounds problem may occur, so subtract 1. 3. The
members of the structure array can directly overwrite the previous member, which is the same as the characteristics of the array.

7. Find contacts

void Find_Contact(contact* p)
{
    
    
	char name[20] = {
    
     0 };
	printf("请输入要查找的联系人:");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret != -1)
	{
    
    
		printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", 
													"年龄", 
													"性别", 
													"电话", 
													"住址");
		printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[ret].name,
													p->CON[ret].age, 
			                                        p->CON[ret].sex,
			                                        p->CON[ret].tele, 
													p->CON[ret].addre);
	}
	else
	{
    
    
		printf("查无此人\n");
	}
}

8. Modify contact information

void Modify_Contact(contact* p)
{
    
    
	char name[20] = {
    
     0 };
	printf("请输入要修改的联系人:");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret != -1)
	{
    
    
		printf("请输入姓名:");
		scanf("%s", p->CON[ret].name);

		printf("请输入年龄:");
		scanf("%d", &p->CON[ret].age);

		printf("请输入性别:");
		scanf("%s", p->CON[ret].sex);

		printf("请输入电话:");
		scanf("%s", p->CON[ret].tele);

		printf("请输入住址:");
		scanf("%s", p->CON[ret].addre);
		printf("修改成功!\n");
	}
	else
	{
    
    
		printf("查无此人\n");
	}
}

9. Sort contacts (by name)

int my_cmp(const void* e1, const void* e2)
{
    
    
	return strcmp(((peo*)e1)->name, ((peo*)e2)->name);
}
void Sort_Contact(contact* p)
{
    
    
	qsort(p->CON, p->count, sizeof(peo), my_cmp);
	printf("排序成功!\n");
}

1. You need to write a comparison function for quick sort. Because it is a string comparison, you need to use the string comparison function.
2. Pay attention to the parameters of quick sort - the sorted array, the number of sorting, the size of the elements, and the comparison function.

4. Summary

1.test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
int main()
{
    
    
	contact *con =NULL;
	Init_contact(&con);
	int input = 0;
	do
	{
    
    
		menu();
		printf("请输入:");
		scanf("%d", &input);
		switch (input)
		{
    
    
		case ADD:
			system("cls");
			Add_Contact(&con);
			break;
		case DEL:
			system("cls");
			Del_Contact(con);
			break;
		case FIND:
			system("cls");
			Find_Contact(con);
			break;
		case MODIFY:
			system("cls");
			Modify_Contact(con);
			break;
		case PRINT:
			system("cls");
			Print_Contact(con);
			break;
		case SORT:
			system("cls");
			Sort_Contact(con);
			break;
		case EXIT:
			system("cls");
			Distory_Contact(&con);
			printf("退出成功\n");
			break;
		default:
			printf("输入错误\n");
			break;
		}

	} while (input!=EXIT);

	return 0;
}

2.contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
    
    
	printf("******************************************\n");
	printf("******** 1.增加联系人 2.删除联系人 *******\n");
	printf("******** 3.查找联系人 4.修改联系人 *******\n");
	printf("******** 5.打印联系人 6.排序联系人 *******\n");
	printf("******** 7.退出通讯录              *******\n");
	printf("******************************************\n");

}
void Init_contact(contact** p)
{
    
    
	*p = malloc(4*2 + sizeof(peo) * DEFAULT_SIZE);
	if (*p != NULL)
	{
    
    
		(*p)->count = 0;
		(*p)->capacity = DEFAULT_SIZE;
	}
	else
	{
    
    
		perror("Init_contact");
		return;
	}
}

//const void Think_Capacity(contact** p)
//{
    
    
//
//	if ((*p)->count == (*p)->capacity)
//	{
    
    
//		contact* ptr = (contact*)realloc(*p, 8 + sizeof(peo) * ((*p)->capacity + ADD_SIZE));
//		if (ptr != NULL)
//		{
    
    
//			(*p) = ptr;
//			(*p)->capacity += ADD_SIZE;
//			printf("增容成功\n");
//		}
//		else
//		{
    
    
//			perror("Add_Contact");
//			printf("增容失败\n");
//			return;
//		}
//	}
//
//}

//void Load_Contact(contact** p)
//{
    
    
//	FILE* pf = fopen("contact.txt", "rb");
//	if (NULL == pf)
//	{
    
    
//		perror("Load_Contact");
//	}
//	else
//	{
    
    
//		peo tmp = { 0 };
//		while (fread(&tmp, sizeof(peo), 1, pf))
//		{
    
    
//			Think_Capacity(p);
//			(*p)->CON[(*p)->count] = tmp;
//			(*p)->count++;
//		}
//	}
//	fclose(pf);
//	pf = NULL;
//}

void Add_Contact(contact** p)
{
    
    
	int judge = 0;
	if ((*p)->count== (*p)->capacity)
	{
    
    
		printf("通讯录已满,请确定是否要增容(1是0否):");
		scanf("%d", &judge);
		if (judge)
		{
    
    
			contact* ptr = (contact*)realloc(*p, 4 * 2 + sizeof(peo) * ((*p)->capacity + ADD_SIZE));
			if (ptr != NULL)
			{
    
    
				(*p) = ptr;
				(*p)->capacity += ADD_SIZE;
				printf("增容成功\n");
			}
			else
			{
    
    
				perror("Add_Contact");
				printf("增容失败\n");
				return;
			}
		}
		else
		{
    
    
			return;
		}

	}

	printf("请输入姓名:");
	scanf("%s", (*p)->CON[(*p)->count].name);

	printf("请输入年龄:");
	scanf("%d", &(*p)->CON[(*p)->count].age);

	printf("请输入性别:");
	scanf("%s", (*p)->CON[(*p)->count].sex);

	printf("请输入电话:");
	scanf("%s", (*p)->CON[(*p)->count].tele);

	printf("请输入住址:");
	scanf("%s", (*p)->CON[(*p)->count].addre);
	printf("增加成功!\n");
	(*p)->count++;
}

void Print_Contact(contact* p)
{
    
    
	if (p->count == 0)
	{
    
    
		printf("通讯录为空!\n");
		return;
	}
	printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", "年龄", "性别", "电话", "住址");
	int i = 0;
	for (i = 0; i < p->count; i++)
	{
    
    
		printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[i].name, 
													p->CON[i].age, 
													p->CON[i].sex, 
													p->CON[i].tele, 
													p->CON[i].addre);
	}
}
const int Find_By_name(contact* p,char*arr)
{
    
    
	int i = 0;
	for (i = 0; i < p->count; i++)
	{
    
    
		if (strcmp(p->CON[i].name, arr) == 0)
		{
    
    
			return i;
		}
	}
	return -1;
}
void Del_Contact(contact* p)
{
    
    
	char name[20] = {
    
     0 };
	printf("请输入要删除的联系人:");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret!=-1)
	{
    
    
		int i = 0;
		for (i = ret; i < p->count-1; i++)
		{
    
    
			p->CON[ret] = p->CON[ret + 1];
		}
		p->count--;
		printf("已删除\n");
	}
	else
	{
    
    
		printf("查无此人\n");
	}
}
void Find_Contact(contact* p)
{
    
    
	char name[20] = {
    
     0 };
	printf("请输入要查找的联系人:");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret != -1)
	{
    
    
		printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", "年龄", "性别", "电话", "住址");
		printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[ret].name, p->CON[ret].age, 
			                                        p->CON[ret].sex, p->CON[ret].tele, 
													p->CON[ret].addre);
	}
	else
	{
    
    
		printf("查无此人\n");
	}
}
void Modify_Contact(contact* p)
{
    
    
	char name[20] = {
    
     0 };
	printf("请输入要修改的联系人:");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret != -1)
	{
    
    
		printf("请输入姓名:");
		scanf("%s", p->CON[ret].name);

		printf("请输入年龄:");
		scanf("%d", &p->CON[ret].age);

		printf("请输入性别:");
		scanf("%s", p->CON[ret].sex);

		printf("请输入电话:");
		scanf("%s", p->CON[ret].tele);

		printf("请输入住址:");
		scanf("%s", p->CON[ret].addre);
		printf("修改成功!\n");
	}
	else
	{
    
    
		printf("查无此人\n");
	}


}
//void Save_Contact(contact* p)
//{
    
    
//	FILE* pf = fopen("contact.txt", "wb");
//	if (NULL == pf)
//	{
    
    
//		perror("Save_Contact:pf");
//	}
//	else
//	{
    
    
//		int i = 0;
//		for (i = 0; i < p->count; i++)
//		{
    
    
//			fwrite(p->CON + i, sizeof(peo), 1, pf);
//		}
//	}
//	printf("保存成功!\n");
//	fclose(pf);
//	pf = NULL;
//
//}

void Distory_Contact(contact** p)
{
    
    
	free(*p);
	*p = NULL;
}



int my_cmp(const void* e1, const void* e2)
{
    
    
	return strcmp(((peo*)e1)->name, ((peo*)e2)->name);
}
void Sort_Contact(contact* p)
{
    
    
	qsort(p->CON, p->count, sizeof(peo), my_cmp);
	printf("排序成功!\n");
}

3.contact.h

#include<stdio.h>//printf,scanf,perror
#include<stdlib.h>//system,malloc,realloc
#include<string.h>//strcmp
//对开辟的大小,方便之后的统一修改。
enum SIZE
{
    
    
	NAME_SIZE=10,
	SEX_SIZE=5,
	TELE_SIZE=15,
	ADDRE_SIZE=20,
	DEFAULT_SIZE=2,
	ADD_SIZE=2
};
//功能的选项数字赋予一定的意义
enum function
{
    
    
	ADD=1,
	DEL,
	FIND,
	MODIFY,
	PRINT,
	SORT,
	EXIT
};
//联系人信息
typedef struct people
{
    
    
	char name[NAME_SIZE];
	int age;
	char sex[SEX_SIZE];
	char tele[TELE_SIZE];
	char addre[ADD_SIZE];
}peo;
//通讯录信息
typedef struct Contact
{
    
    
	int count;//联系人个数
	int capacity;//当前最大容量
	peo CON[];//柔性数组利用内存池的概念,使内存管理更加高效,并且free只要一次,更方便。
}contact;

//菜单
void menu();
//初始化通讯录
void Init_contact(contact** p);//要修改一级指针所以要传一级指针的地址用二级指针来接收
//添加联系人信息
void Add_Contact(contact** p);//同理
//打印通讯录
void Print_Contact(contact* p);
//删除联系人信息
void Del_Contact(contact* p);
//查找联系人信息
void Find_Contact(contact* p);
//修改联系人信息
void Modify_Contact(contact* p);
//释放已开辟的内存空间
void Distory_Contact(contact** p);//同理
//按照名字进行排序通讯录
void Sort_Contact(contact* p);
//保存通讯录信息
//void Save_Contact(contact* p);
//加载通讯录信息
//void Load_Contact(contact* p);

5. Functions required for file operations

1. Check capacity

const void Think_Capacity(contact** p)
{
    
    

	if ((*p)->count == (*p)->capacity)
	{
    
    
		contact* ptr = (contact*)realloc(*p, 8 + sizeof(peo) * ((*p)->capacity + ADD_SIZE));
		if (ptr != NULL)
		{
    
    
			(*p) = ptr;
			(*p)->capacity += ADD_SIZE;
			printf("增容成功\n");
		}
		else
		{
    
    
			perror("Add_Contact");
			printf("增容失败\n");
			return;
		}
	}

}

2. Add contact information

void Load_Contact(contact** p)
{
    
    
	FILE* pf = fopen("contact.txt", "rb");
	if (NULL == pf)
	{
    
    
		perror("Load_Contact");
	}
	else
	{
    
    
		peo tmp = {
    
     0 };
		while (fread(&tmp, sizeof(peo), 1, pf))
		{
    
    
			Think_Capacity(p);
			(*p)->CON[(*p)->count] = tmp;
			(*p)->count++;
		}
	}
	fclose(pf);
	pf = NULL;
}

3. Save contact information

void Save_Contact(contact* p)
{
    
    
	FILE* pf = fopen("contact.txt", "wb");
	if (NULL == pf)
	{
    
    
		perror("Save_Contact:pf");
	}
	else
	{
    
    
		int i = 0;
		for (i = 0; i < p->count; i++)
		{
    
    
			fwrite(p->CON + i, sizeof(peo), 1, pf);
		}
	}
	printf("保存成功!\n");
	fclose(pf);
	pf = NULL;

}

To create one in the current project (same path as the source file): contact.txt

Guess you like

Origin blog.csdn.net/Shun_Hua/article/details/128677214