C language - address book

introduction

Address book is a very simple and practical small project in C language. It involves a lot of basic knowledge in C language. Being able to independently write this small project of address book proves that you have a certain mastery of C language knowledge. Today we will discuss the implementation of three versions of the address book

1. Static version of address book

contact.h

pragma once is to prevent the header file from being called repeatedly in memory while the program is running.

The string.h header file is to call the string function

There is no need to say more about stdio.h

The assert.h header file refers to the assert function to prevent some pointers from being NULL and affecting program operation.

 enum is used to enumerate the eight main functions of the address book to increase code readability and standardization.

Directly define a large number of variables that appear in contact.c in contact.h. When encountering these variables later, you do not need to define them again, which improves code efficiency.

 Create a structure to store contact information

Create another structure

data [MAX] is an array that can store 1000 Ploinfo (that is, the previous structure) information

sz is used to record the number of contacts

#pragma once 
#include<string.h>
#include<stdio.h>
#include<assert.h>
//类型的声明


enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	PRINT,
	CLEAR,
	SORT
};


#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define TELE_MAX 12


typedef struct Ploinfo
{
	char name[NAME_MAX];  //姓名
	char sex[SEX_MAX];    //性别
	int age;              //年龄
	char addr[ADDR_MAX];  //地址
	char tele[TELE_MAX];  //电话号码
}Ploinfo;


typedef struct Contact
{
	struct Ploinfo data[MAX]; //存放联系人的数组
	int sz;                   //统计联系人的个数
}Contact;






//函数的声明


//contact 初始化
void InitContact(Contact* pc);


//Contact 增加联系人的信息
void AddContact(Contact* pc);


//Contact 打印联系人的信息
void PrintContact(const Contact* pc);//只是打印,不会改变Contact里面的数据,所以可以const来修饰


//Contact 删除指定联系人
void DelContact(Contact* pc);


//Contact 查找指定联系人
void SearchContact(Contact* pc);


//Contact 修改指定联系人信息
void ModifyContact(Contact* pc);


//Contact 通讯录信息排序
void sortContact(Contact* pc);


//Contact 通讯录信息清空
void ClearContact(Contact* pc);

contact.h

contact.h is a header file we created independently, which contains all the header files and variables we need to run contact.c

At the beginning of contact.c, you only need to quote this contact.h header file.

The InitContact function is used to initialize the address book. Before adding contact information, both data and sz need to be initialized to 0.

assert prevents pc from being NULL

memset is a string function. Its function here is to set all the spaces in data [MAX] to 0.

The AddContact function is used to add contact information

Before adding, you need to confirm whether the address book has enough space. If it is not enough, you cannot add it.

If you can add it, just continue to execute the following statement. I won’t elaborate too much here. Take a look at the source code below.

 The only thing you need to pay attention to here is that in the printf statement, "-" is to the left, so without adding a sign, it is to the right.

Modifying and deleting specified contact information are inseparable from the FindByName function, because to implement modification and deletion, you must first find the element to be deleted and modified. If you cannot find it, there is no need to delete or modify it.

How the FindByName function is implemented:

The principle is to use a for loop to traverse the names in the data. Each data has a unique subscript i. Compare the name to be found with the name in the data through strcmp. If they are the same, strcmp returns 0, and then in the for loop Nest an if statement. If 0 == the value returned by strcmp, then at this time, the subscript of data will be returned to the Del and Modify functions to delete and modify the specified contact information. If it is traversed, it is best not to find it. This person jumps out of the for loop directly, returns - 1 and returns the Del and Modify functions.

This statement is included in the Del Modify Search function

If you read the source code carefully, you will find that some parts of the Del Modify Search function are the same.

1. Need to determine whether the address book is empty

2. Need to determine whether the contact you are looking for exists

3. All need to call FindByName

The Sort function implements sorting of contact information. There are 5 types of contact information. Their types may be the same or different. We cannot sort them separately. Although it can definitely be achieved if we force it, it is not necessary. In our mobile phones The address book is basically sorted by name, so it would be more realistic if we also sort by name.

Names are of type char. We can directly use strcmp to compare them and then sort them.

Here, a double for loop is used to nest an if statement, and a Ploinfo type tmp is created as an intermediate variable to exchange data to achieve sorting.

#include"contact.h"




//contact初始化
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}


//Contact函数的使用 —— 添加联系人
void AddContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == MAX)
	{
		printf("通讯录容量已满!无法添加!\n");


		return;
	}


	printf("请输入姓名 =>\n");
	scanf("%s", pc->data[pc->sz].name);


	printf("请输入性别 =>\n");
	scanf("%s", pc->data[pc->sz].sex);


	printf("请输入年龄 =>\n");
	scanf("%d", &pc->data[pc->sz].age);


	printf("请输入电话号码 =>\n");
	scanf("%s", pc->data[pc->sz].tele);


	printf("请输入地址 =>\n");
	scanf("%s", pc->data[pc->sz].addr);


	pc->sz++;


	printf("添加联系人成功!\n");
}


//Contact 打印联系人的信息
void PrintContact(const Contact* pc)
{
	assert(pc);


	int i = 0;
	printf("%-10s %-5s %-5s %-15s %-20s\n","姓名","性别","年龄","电话","地址");


	for (i = 0;i < pc->sz;i++)
	{
		printf("%-10s %-5s %-5d %-15s %-20s\n", pc->data[i].name, pc->data[i].sex,
			pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
	}
}


//Contact 删除指定联系人


int FindByName(const Contact* pc, char name[])
{
	int i = 0;
	//遍历查找
	//找到返回下标
	//没找到返回 -1
	for (i = 0;i < pc->sz;i++)
	{
		if (0 == strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	return -1;
}
void DelContact(Contact* pc)
{
	assert(pc);


	if (0 == pc->sz)
	{
		printf("通讯录为空!无法删除!\n");


	    return;
	}


	printf("请输入你要查找的联系人的姓名 =>\n");


	char name[NAME_MAX] = { 0 };//初始化


	scanf("%s", name);//输入要查找的联系人的姓名


	//1、查找
	int pos = FindByName(pc, name);


	if (-1 == pos)
	{
		printf("联系人不存在!\n");


		return;
	}


	//2、删除
	int j = 0;


	for (j = pos;j < pc->sz - 1;j++)
	{
		pc->data[j] = pc->data[j + 1];
	}


	pc->sz--;


	printf("删除成功!\n");
}


//Contact 查找指定联系人
void SearchContact(Contact* pc)
{
	assert(pc);


	if (0 == pc->sz)
	{
		printf("通讯录为空!无法查找!\n");


		return;
	}


	char name[NAME_MAX] = { 0 };


	printf("输入你要查找的联系人的姓名=>\n");


	scanf("%s", &name);


	int pos = FindByName(pc, name);


	if (-1 == pos)
	{
		printf("联系人不存在!\n");


		return;
	}


	printf("%-10s %-5s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");


	printf("%-10s %-5s %-5d %-15s %-20s\n", pc->data[pos].name, pc->data[pos].sex,
		pc->data[pos].age, pc->data[pos].tele, pc->data[pos].addr);


	printf("搜索联系人信息成功!\n");
}


//Contact 修改指定联系人信息
void ModifyContact(Contact* pc)
{
	assert(pc);


	if (0 == pc->sz)
	{
		printf("通讯录为空!无法修改!\n");


		return;
	}
	//查找
	char name[NAME_MAX] = { 0 };


	printf("输入你要查找的联系人的姓名=>\n");


	scanf("%s", &name);


	int pos = FindByName(pc, name);


	if (-1 == pos)
	{
		printf("联系人不存在!\n");


		return;
	}


	//修改


	printf("请输入你想修改该联系人的信息 =>\n");


	printf("请输入姓名 =>\n");
	scanf("%s", pc->data[pos].name);


	printf("请输入性别 =>\n");
	scanf("%s", pc->data[pos].sex);


	printf("请输入年龄 =>\n");
	scanf("%d", &pc->data[pos].age);


	printf("请输入电话号码 =>\n");
	scanf("%s", pc->data[pos].tele);


	printf("请输入地址 =>\n");
	scanf("%s", pc->data[pos].addr);


	printf("修改联系人信息成功!\n");
}


//Contact 通讯录信息排序
void SortContact(Contact* pc)
{
	assert(pc);


	if (0 == pc->sz)
	{
		printf("通讯录为空!无法排序!\n");


		return;
	}


	//以名字排序
	int i, j;
	Ploinfo tmp;
	for (i = 0; i < pc->sz - 1; i++)
	{
		for (j = 0; j < pc->sz - 1 - i; j++)
		{
			if (0 < strcmp(pc->data[j].name, pc->data[j + 1].name))
			{
				tmp = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = tmp;
			}
		}
	}


	printf("排序成功!\n");
}


//Contact 通讯录信息清空
void ClearContact(Contact* pc)
{
	InitContact(pc);
}

address book.c

Here is a menu interface to select functions. It is very simple and I won’t elaborate too much.

#include "contact.h"


void menu()
{
	printf("**********************************************\n");
	printf("***     1.添加(add)      2.删除(del)       ***\n");
	printf("***     3.搜索(search)   4.修改(modify)    ***\n");
	printf("***     5.排序(sort)     6.打印(print)     ***\n");
	printf("***     7.清空(clear)    0.退出(exit)      ***\n");
	printf("**********************************************\n");
}


void test()
{
	int input = 0;
	//创建通讯录
	Contact cot;
	//初始化通讯录
	InitContact(&cot);
	do
	{
		menu();


		printf("请选择功能 =>\n");


		scanf("%d", &input);


		switch (input)
		{
		case EXIT:
			printf("退出通讯录\n");
			break;
		case ADD:
			//添加联系人
			AddContact(&cot);
			break;
		case DEL:
			DelContact(&cot);
			break;
		case SEARCH:
			SearchContact(&cot);
			break;
		case MODIFY:
			ModifyContact(&cot);
			break;
		case SORT:
			SortContact(&cot);
			break;
		case PRINT:
			PrintContact(&cot);
			break;
		case CLEAR:
			ClearContact(&cot);
		default:
			printf("输入错误!请重新输入\n");
			break;
		}
	} while (input);
}


int main()
{
	test();


	return 0;
}

2. Dynamic version of address book

    The dynamic version of the address book is an upgrade based on the above address book. The so-called dynamic version can dynamically change the address book space. The advantage of this version is that it can greatly reduce the waste of space and avoid insufficient storage space. .

    I won’t move all the code here, but just separate the modified parts of the static version of the address book for explanation.

    It will involve the knowledge of dynamic memory management. If you are new to C language and need to understand this knowledge, you can learn more about it. It doesn’t matter if you don’t understand it. I will also briefly explain the principle.

contact.h

#define DEFAULT_SZ 3//初始状态的容量大小

//动态的版本
typedef struct Contact
{
	Ploinfo* data; //data不再是数组,而是指定为一个指针,在contact.c中直接向内存申请空间
	int sz;   //统计联系人的个数
	int capacity;//容量
}Contact;

//contact 销毁
void DestroyContact(Contact* pc);

contact.c

Add DestroyContact and Check_capacity functions

Modify the InitContact function

 The instructions are all in the code

//contact初始化
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;//sz指的是联系人个数,初始化为0
	pc->capacity = DEFAULT_SZ;
	pc->data = (Ploinfo*)malloc(pc->capacity * sizeof(Ploinfo));//malloc开辟一个动态的空间,含有capacity个联系人信息的空间
	if (pc->data == NULL)
	{
		perror("InitContact::malloc");//如果pc->data是NULL perror会在屏幕上打印出错误信息 InitContact::malloc 这个格式是给计算机减负,能快速定位错误的语句具体在哪个位置
		                              //同时也是一个保险 当你代码运行时发现错误时,能快速锁定错误位置进行修正
		return 1;
	}

	memset(pc->data, 0, pc->capacity * sizeof(Ploinfo));//初始化 前三个信息的位置 都为0

}

//contact销毁
void DestroyContact(Contact* pc)
{
	assert(pc);
	free(pc->data);//动态开辟了空间,在不需要用通讯录时,需要把空间释放
	pc->data = NULL;
	pc->capacity = 0;//归零
	pc->sz = 0;//归零
}

//检查capacity是否等于sz,也就是在检查空间是否已满,需不需要增加空间
Check_capacity(Contact* pc)
{
	assert(pc);

	if (pc->capacity == pc->sz)
	{
		Ploinfo* tmp = (Ploinfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(Ploinfo));//realloc 的目的就是动态增加开始malloc开辟的空间
		if (tmp != NULL)
		{
			pc->data = tmp;
		}
		pc->capacity += 2;//不要一次只添加一个联系人所占的空间,一次加多点,也不加太多,加两个联系人的空间
	}
}

//Contact函数的使用 —— 添加联系人
void AddContact(Contact* pc)
{
	//静态版本
	/*assert(pc);
	if (pc->sz == MAX)
	{
		printf("通讯录容量已满!无法添加!\n");

		return;
	}*/

	Check_capacity(pc);//添加联系人之前,需要先调用这个函数检查一下空间是否足够,不够就扩容

	printf("请输入姓名 =>\n");
	scanf("%s", pc->data[pc->sz].name);

	printf("请输入性别 =>\n");
	scanf("%s", pc->data[pc->sz].sex);

	printf("请输入年龄 =>\n");
	scanf("%d", &pc->data[pc->sz].age);

	printf("请输入电话号码 =>\n");
	scanf("%s", pc->data[pc->sz].tele);

	printf("请输入地址 =>\n");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;//添加联系人成功 sz++ 联系人数量增加

	printf("添加联系人成功!\n");
}

address book.c

The DestroyContact function is only added to the exit option in the menu.


3. File version of address book

The file version is an upgrade of the dynamic version. The information stored in the above two versions will be destroyed after exiting the address book and cannot be saved. The address book will still be empty next time you run it. The file version allows you to enter the address book for the first time. The information is saved to a specified file. The next time you open the address book, the information is read from the specified file into the address book and saved. This is the file version of the address book.

Knowledge involving file operations in C language.

contact.h

//Contact 通讯录信息在销毁之前以文件形式保存
void SaveContact(Contact* pc);

contact.c

Check_capacity(Contact* pc)
{
	assert(pc);

	if (pc->capacity == pc->sz)
	{
		Ploinfo* tmp = (Ploinfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(Ploinfo));
		if (tmp != NULL)
		{
			pc->data = tmp;
		}
		pc->capacity += 2;
	}
}

//读取文件
LoadContact(Contact* pc)
{
	//1.打开文件
	FILE* pf = fopen("C.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact::fopen");

		return;
	}
	//2.读取文件
	Ploinfo tmp = { 0 };//创建一个存放读取信息的变量

	while (fread(&tmp, sizeof(Ploinfo), 1, pf))
	{
		Check_capacity(pc);//第二次打开通讯录时,sz(联系人个数)和capacity(容量)都为0,从C.txt读取到的信息需要放到data里面去,就必须先开辟空间
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}

	//3.关闭文件
}

//contact初始化
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	pc->data = (Ploinfo*)malloc(pc->capacity * sizeof(Ploinfo));
	if (pc->data == NULL)
	{
		perror("InitContact::malloc");
		return 1;
	}

	memset(pc->data, 0, pc->capacity * sizeof(Ploinfo));

	//关闭通讯录,再次打开,我们需要读取C.txt里面的联系人信息
	//再创建一个函数
	LoadContact(pc);

}

//contact销毁
void DestroyContact(Contact* pc)
{
	assert(pc);
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

//Contact 通讯录信息在销毁之前以文件形式保存
void SaveContact(const Contact* pc)
{
	//1.打开文件
	//打开一个文件 可以在Contact 的文件路径下创建一个文件 也可以直接fopen一个文件
	FILE* ptr = fopen("C.txt", "wb");//我这里是命名的文件是txt的文件后缀名,当然这个后缀名可以随便写 wb是以二进制打开文件

	//考虑到ptr可能为NULL,防止这个函数无法正常运行,需要加个保险措施
	if (ptr == NULL)
	{
		perror("SaveContact::fopen");//方便定位错误位置
		return;
	}

	//2.写文件
	int i = 0;
	for (i = 0;i < pc->sz;i++)
	{
		fwrite(pc->data + i, sizeof(Ploinfo), 1, ptr);//在销毁通讯录之前,把联系人信息已经保存到 C.txt 里面了
	}

	//3.关闭文件
	fclose(ptr);
	ptr = NULL;
}

address book.c

#include "contact.h"

void menu()
{
	printf("**********************************************\n");
	printf("***     1.添加(add)      2.删除(del)       ***\n");
	printf("***     3.搜索(search)   4.修改(modify)    ***\n");
	printf("***     5.打印(print)    6.清空(clear)     ***\n");
	printf("***     7.排序(sort)     0.退出(exit)      ***\n");
	printf("**********************************************\n");
}

void test()
{
	int input = 0;
	//创建通讯录
	Contact cot;
	//初始化通讯录
	InitContact(&cot);
	do
	{
		menu();

		printf("请选择功能 =>\n");

		scanf("%d", &input);

		switch (input)
		{
		case EXIT:
			printf("退出通讯录\n");
			SaveContact(&cot);//销毁通讯录之前先保存联系人信息
			DestroyContact(&cot);
			break;
		case ADD:
			//添加联系人
			AddContact(&cot);
			break;
		case DEL:
			DelContact(&cot);
			break;
		case SEARCH:
			SearchContact(&cot);
			break;
		case MODIFY:
			ModifyContact(&cot);
			break;
		case PRINT:
			PrintContact(&cot);
			break;
		case CLEAR:
			ClearContact(&cot);
		case 7:
			SortContact(&cot);
			break;
		default:
			printf("输入错误!请重新输入\n");
			break;
		}
	} while (input);
}

int main()
{
	test();

	return 0;
}

4. Summary

Address book static involves C language knowledge version: branch and loop statement structure string function operator pointer function array

Address book updates involve C language knowledge version: branch and loop statement structure string function operator pointer function array

                                                  Dynamic memory management

Address book updates involve C language knowledge version: branch and loop statement structure string function operator pointer function array

                                                  Dynamic memory management file operations

Although address books are very inconspicuous nowadays, for C language beginners, being able to implement these three types of address books proficiently and independently is enough to show that the C language skills are basically qualified, and they can try to implement more C language in the future. Small projects to consolidate your programming abilities and exercise your programming thinking.


work hard!!!

Guess you like

Origin blog.csdn.net/cdtu_mid/article/details/131763803