C language data structure-implementation of address book based on dynamic sequence table


1 Basic requirements

Basic requirements of C language: structures, dynamic memory management, sequence tables, file operations

Idea: Use the completed sequence table to simply modify the sequence table and apply it to the address book.

2 Address book function

The address book can only store 100 people
. User information: name, gender, age, phone number, address.
Address book display, add, delete, modify, search, search.

2.1 Files introducing sequence tables

We have completed the sequence table, I backed it up and renamed it SeqList_copy.hand SeqList_copy.c
created Contact.hand Contact.cand tested the functionality of the code test.c
test.cand Contact.cthe referenced header files are all Contact.handSeqList_copy.h

Insert image description here

2.2 Define contact data structure

In Contact.hthe header file,
define the maximum length of the name, the maximum length of the gender, the maximum length of the phone number, and the maximum length of the address.

#define NAME_MAX 120
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 50
//定义结构体
typedef struct ContactInfo
{
    
     
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}CInfo;

//通讯录的底层是顺序表来实现
//给 SeqList 取名叫 contact ,更改名称
typedef struct SeqList contact;    

2.3 Initialization and destruction of address book

The sequence table has been initialized and destroyed. Here we apply it directly.

void ContactInit(contact* pcon)
{
    
    
	SLInit(pcon);    //直接调用我们已经实现的顺序表的方法
}

void ContactDestory(contact* pcon)
{
    
    
	SLInit(pcon);
}

2.4 Add contacts

I wanted to add contacts step by step, so I added them in stages, which seemed bloated.

What we get are all the data required by the CInfo structure.
Name, sex, tel, and addr are all string arrays. The entire array represents the address of the first element of the array. Using scanf, there is no need to & get the address.
But age is an int type array, so use scanf, still needs & to get the address

void ContactAdd(contact* pcon)
{
    
    
	CInfo info;
	printf("输入联系人姓名:\n");
	scanf("%s", info.name);    
	printf("输入联系人性别:\n");
	scanf("%s", info.sex);
	printf("输入联系人年龄:\n");
	scanf("%d", &info.age);   //这里注意,定义age是int类型数组,使用scanf,仍需要&取地址
	printf("输入联系人电话:\n");
	scanf("%s", info.tel);
	printf("输入联系人住址:\n");
	scanf("%s", info.addr);
	printf("输入完成\n\n");

	//往通讯录插入数据
	SLPushBack(pcon, info);
}

2.5 Delete contacts

Here I delete contacts by name, which is relatively simple.
Point 1: Create FindByNamea function and check whether it can be found by name.
Point 2: Use the function in the sequence table SLErase, observe its parameters, and make clever use of subscripts.

Create FindByNamefunction

int FindByName(contact* pcon,char name[])
{
    
    
	for (int i = 0; i < pcon->size; i++)
	{
    
    
		if (strcmp(pcon->a[i].name, name) == 0)  //比较字符串姓名
		{
    
    
			return i;   //找到了就返回索引i
		}
	}
	return -1;  //没有找到就用-1代替
}
//删除联系人
void ContactDel(contact* pcon)
{
    
    
	printf("需要删除联系人的名字:\n");
	char name[NAME_MAX];
	scanf("%s", name);

	//找到人的下标记录一下
	int findindex = FindByName(pcon, name);
	//没找到联系人就是不存在
	if (findindex < 0) {
    
    
		printf("不存在!\n");
		return;
	}
	//这里找到联系人,删除findindex位置的数据 
	//参考函数void SLErase(SL* ps, int pos)  根据索引删除
	SLErase(pcon, findindex);
}

2.6 Modify contacts

Use the function again FindByName. Modify the contact by name

void ContactModify(contact* pcon)
{
    
    
	char name[NAME_MAX];
	printf("请输入您要修改的联系人:\n");
	scanf("%s", name);  //同样的道理,name本身是字符串数据,不用&

	//获取到的通讯录下标的位置find,利用数组修改
	int find = FindByName(pcon, name);
	if (find < 0)
	{
    
    
		printf("要修改的用户不存在\n");
		return;
	}
	printf("请输入新的用户名:\n");
	scanf("%s", pcon->a[find].name);
	printf("请输入新的用户性别\n");
	scanf("%s", pcon->a[find].sex);
	printf("请输入新的用户年龄:\n");
	scanf("%d", &pcon->a[find].age);   //age 是整型,我们要把地址传递过去
	printf("请输入新的用户电话:\n");
	scanf("%s", pcon->a[find].tel);
	printf("请输入新的用户地址:\n");
	scanf("%s", pcon->a[find].addr);

	printf("修改完成\n");
}

2.7 Find contacts

void ContactFind(contact* pcon)
{
    
    
	char name[NAME_MAX];
	printf("请输入要查找的用户名:\n");
	scanf("%s", name);
	int find = FindByName(pcon, name);
	if (find < 0)
	{
    
    
		printf("该联系人不存在\n");
		return;
	}
	//提前打印表头,便于查看
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
	printf(
		"%s %s %d %s %s\n",
		pcon->a[find].name, 
		pcon->a[find].sex,
		pcon->a[find].age, 
		pcon->a[find].tel, 
		pcon->a[find].addr
	);
}

2.8 View address book

This logic is a bit different from the sequence table, so I re-wrote it.

void ContactShow(contact* pcon)
{
    
    
	//打印第一列header
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
	for (int i = 0; i < pcon->size; i++)
	{
    
    
		printf("%s %s %d %s %s\n", pcon->a[i].name, pcon->a[i].sex,
			pcon->a[i].age, pcon->a[i].tel, pcon->a[i].addr);
	}

}

3 Complete code display

3.1 SeqList_copy.h

SeqList_copy.hPart of the code, the function of searching the sequence table, does not apply to the address book, so please comment
this step. Be sure to change the dynamic sequence table data type to the address book data type.

#pragma once
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#include<stdbool.h>
#include"Contact.h"    //添加头文件

//动态顺序表
//typedef int SLDataType;
//1. 更改动态顺序表数据类型为通讯录数据类型
typedef struct ContactInfo SLDataType;   //这里不能直接使用ContactInfo的别名 CInfo

//或者在这里再次命名,但是这样很多余
/*
//typedef struct ContactInfo CInfo;
//typedef CInfo SLDataType;
*/

typedef struct SeqList
{
    
    
	SLDataType* a;
	int size;	// 顺序表中有效的个数
	int capacity;	//顺序表当前的空间大小
}SL;	//简化结构体名称

//对顺序表进行初始化
void SLInit(SL* ps);
void SLDestory(SL* ps);


//头部,尾部  插入,删除
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

//打印SL
SLprint(SL* ps);

//判断SL是否为空
bool SLIsEmpty(SL* ps);

//在指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x);

//删除指定位置的数据
void SLErase(SL* ps, int pos);

//查找数据
//bool SLFind(SL* ps, SLDataType x);

3.2 SeqList_copy.c

SLFind()The function is not applicable. Our FindByName()function is to check whether the name exists in the address book by name.
SLPrint()The function is also not applicable, so there is ContactShow()a function.

#include"SeqList_copy.h"

void SLInit(SL* ps) {
    
    
	ps->a = NULL;
	ps->size = ps->capacity = 0;
}

void SLDestroy(SL* ps) {
    
    
	if (ps->a)
		free(ps->a);
	ps->a = NULL;
	ps->size = ps->capacity = 0;
} 

void SLCheckCapacity(SL* ps) {
    
    
	if (ps->size == ps->capacity) {
    
    
		//空间不足以再额外插入一个数据
		//扩容
		int newCapcity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapcity * sizeof(SLDataType));
		if (tmp == NULL) {
    
    
			perror("realloc fail!\n");
			return 1;
		}
		ps->a = tmp;
		ps->capacity = newCapcity;
	}
}

//尾插
void SLPushBack(SL* ps, SLDataType x) {
    
    
	//assert(ps != NULL);
	//暴力的方式
	assert(ps);
	//柔和方式
	//if (ps == NULL) {
    
    
	//	return;
	//}

	SLCheckCapacity(ps);
	//直接插入数据
	ps->a[ps->size++] = x;
}
//头插
void SLPushFront(SL* ps, SLDataType x) {
    
    
	assert(ps);
	//判断空间是否足够,不够则扩容
	SLCheckCapacity(ps);
	//空间足够,历史数据后移一位
	for (size_t i = ps->size; i > 0; i--)
	{
    
    
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[0] = x;
	ps->size++;
}

//尾插
void SLPopBack(SL* ps) {
    
    
	//判断顺序表是否为空
	assert(ps);
	assert(!SLIsEmpty(ps));
	//ps->a[ps->size - 1] = 0;
	ps->size--;
}
void SLPopFront(SL* ps) {
    
    
	assert(ps);
	assert(!SLIsEmpty(ps));
	//让后面的数据往前挪动一位
	for (size_t i = 0; i < ps->size - 1; i++)
	{
    
    
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

//void SLPrint(SL* ps) {
    
    
//	for (size_t i = 0; i < ps->size; i++)
//	{
    
    
//		printf("%d ", ps->a[i]);
//	}
//	printf("\n");
//}

bool SLIsEmpty(SL* ps) {
    
    
	assert(ps);
	//这样子是不对的,这里只能判断空间是否足够
	//return ps->size == ps->capacity;
	return ps->size == 0;
}

//在指定的位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x) {
    
    
	assert(ps);
	//不要忘了对pos加以限制
	assert(pos >= 0 && pos <= ps->size);
	//扩容
	SLCheckCapacity(ps);
	//把pos位置及以后的数据往后挪动一位
	//循环条件里i的初始值是size还是size-1都是可以的,但不同的初始值对应不同的结束条件
	//for (int i = ps->size; i > pos; i--)
	//{
    
    
	//	//pos+1
	//	ps->a[i] = ps->a[i - 1];//pos->a[pos+1] = ps->a[pos]
	//}
	for (int i = ps->size - 1; i > pos - 1; i--)
	{
    
    
		//最后一次进来的i是pos
		ps->a[i + 1] = ps->a[i];//ps->a[pos+1] = ps->a[pos]
	}
	ps->a[pos] = x;
	ps->size++;
}
//删除指定位置的数据
void SLErase(SL* ps, int pos) {
    
    
	assert(ps);
	assert(!SLIsEmpty(ps));
	//pos的范围需要限制
	assert(pos >= 0 && pos < ps->size);

	for (int i = pos; i < ps->size - 1; i++)
	{
    
    
		//最后一次进来的i的数据ps->size-2
		ps->a[i] = ps->a[i + 1];//ps->a[ps->size-2] = ps->a[ps->size-1]
	}
	ps->size--;
}

//bool SLFind(SL* ps, SLDataType x) {
    
    
//	assert(ps);
//	for (int i = 0; i < ps->size; i++)
//	{
    
    
//		if (ps->a[i].name == x) {
    
    
//			//找到了
//			return true;
//		}
//	}
//	return false;
//}

3.3 Contact.h

#pragma once
//创建保存联系人数据的结构
#define NAME_MAX 120
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 50

typedef struct ContactInfo
{
    
     
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}CInfo;

//通讯录的底层是顺序表来实现
//给 SeqList 取名叫 contact
typedef struct SeqList contact;    

//1.通讯录的初始化和销毁
void ContactInit(contact* pcon);
void ContactDestory(contact* pcon);

//2.添加联系人
void ContactAdd(contact* pcon);

//3.删除联系人
void ContactDel(contact* pcon);

//4.修改联系人
void ContactModify(contact* pcon);

//5.查找联系人
void ContactFind(contact* pcon);

//6.查看通讯录
void ContactShow(contact* pcon);

3.4 Contact.c

#define _CRT_SECURE_NO_WARNINGS
#include"SeqList_copy.h"
#include"Contact.h"


//1.通讯录的初始化和销毁
void ContactInit(contact* pcon)
{
    
    
	SLInit(pcon);    //直接调用我们已经实现的顺序表的方法
}

void ContactDestory(contact* pcon)
{
    
    
	SLInit(pcon);
}

//2.添加联系人
//我们获取的都是CInfo结构体要求的数据
//name,sex,tel,addr都是字符串数组,整个数组代表数组的首元素地址,使用scanf,不需要再&取地址
//但是age是int类型,使用scanf,仍需要&取地址
void ContactAdd(contact* pcon)
{
    
    
	CInfo info;
	printf("输入联系人姓名:\n");
	scanf("%s", info.name);    
	printf("输入联系人性别:\n");
	scanf("%s", info.sex);
	printf("输入联系人年龄:\n");
	scanf("%d", &info.age);
	printf("输入联系人电话:\n");
	scanf("%s", info.tel);
	printf("输入联系人住址:\n");
	scanf("%s", info.addr);
	printf("输入完成\n\n");

	//往通讯录插入数据
	SLPushBack(pcon, info);
}

//3.删除联系人
//我们这里通过姓名删除联系人

int FindByName(contact* pcon,char name[])
{
    
    
	for (int i = 0; i < pcon->size; i++)
	{
    
    
		if (strcmp(pcon->a[i].name, name) == 0)  //比较字符串姓名
		{
    
    
			return i;   //找到了就返回索引i
		}
	}
	return -1;  //没有找到就用-1代替
}

void ContactDel(contact* pcon)
{
    
    
	printf("需要删除联系人的名字:\n");
	char name[NAME_MAX];
	scanf("%s", name);

	//找到人的下标记录一下
	int findindex = FindByName(pcon, name);
	//没找到联系人就是不存在
	if (findindex < 0) {
    
    
		printf("不存在!\n");
		return;
	}
	//这里找到联系人,删除findindex位置的数据 
	//参考函数void SLErase(SL* ps, int pos)  根据索引删除
	SLErase(pcon, findindex);
}

//4.修改联系人
void ContactModify(contact* pcon)
{
    
    
	char name[NAME_MAX];
	printf("请输入您要修改的联系人:\n");
	scanf("%s", name);

	//获取到的通讯录下标的位置find,利用数组修改
	int find = FindByName(pcon, name);
	if (find < 0)
	{
    
    
		printf("要修改的用户不存在\n");
		return;
	}
	printf("请输入新的用户名:\n");
	scanf("%s", pcon->a[find].name);
	printf("请输入新的用户性别\n");
	scanf("%s", pcon->a[find].sex);
	printf("请输入新的用户年龄:\n");
	scanf("%d", &pcon->a[find].age);   //age 是整型,我们要把地址传递过去
	printf("请输入新的用户电话:\n");
	scanf("%s", pcon->a[find].tel);
	printf("请输入新的用户地址:\n");
	scanf("%s", pcon->a[find].addr);

	printf("修改完成\n");
}

//5.查找联系人
void ContactFind(contact* pcon)
{
    
    
	char name[NAME_MAX];
	printf("请输入要查找的用户名:\n");
	scanf("%s", name);
	int find = FindByName(pcon, name);
	if (find < 0)
	{
    
    
		printf("该联系人不存在\n");
		return;
	}
	
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
	printf(
		"%s %s %d %s %s\n",
		pcon->a[find].name, 
		pcon->a[find].sex,
		pcon->a[find].age, 
		pcon->a[find].tel, 
		pcon->a[find].addr
	);
}

//6.查看通讯录
void ContactShow(contact* pcon)
{
    
    
	//打印第一列header
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
	for (int i = 0; i < pcon->size; i++)
	{
    
    
		printf("%s %s %d %s %s\n", pcon->a[i].name, pcon->a[i].sex,
			pcon->a[i].age, pcon->a[i].tel, pcon->a[i].addr);
	}

}

3.5 test.c

#define _CRT_SECURE_NO_WARNINGS
#include"SeqList_copy.h"
#include"Contact.h"

void Contact_Test()  //测试函数
{
    
    
	contact con;
	ContactInit(&con);
	//以下是测试

	//添加联系人测试
	ContactAdd(&con); // 1 1 1 1 1 
	ContactAdd(&con); // 2 2 2 2 2
	ContactShow(&con);// 1 1 1 1 1 2 2 2 2 2

	//删除联系人测试
	//ContactDel(&con);
	//ContactShow(&con);

	//修改联系人测试
	//ContactModify(&con);   //1 3 3 3 3 3 
	//ContactShow(&con);	//3 3 3 3 3  2 2 2 2 2


	//查找联系人测试
	ContactFind(&con);

	//以上是测试

	ContactDestory(&con);
}


void menu()
{
    
    
	printf("****************************\n");
	printf("****************************\n");
	printf("************通讯录***********\n");
	printf("*********1.添加联系人********\n");
	printf("*********2.删除联系人********\n");
	printf("*********3.修改联系人********\n");
	printf("*********4.查找联系人********\n");
	printf("*********5.查看通讯录********\n");
	printf("*********0.退  出************\n");
	printf("****************************\n");
	printf("****************************\n");
}
int main()
{
    
    
	//Contact_Test();
	//测试完成,函数封装成菜单,在以下展示

	int op = 0;
	contact con;
	ContactInit(&con);
	do {
    
    
		menu();
		printf("请选择:\n");
		scanf("%d", &op);
		switch (op)
		{
    
    
		case 1:
			ContactAdd(&con);
			break;
		case 2:
			ContactDel(&con);
			break;
		case 3:
			ContactModify(&con);
			break;
		case 4:
			ContactFind(&con);
			break;
		case 5:
			ContactShow(&con);
			break;
		case 0:
			printf("退出了哈");
			break;
		default:
			printf("输入错误,请重新输入");
			break;
		}

	} while (op!=0);
	ContactDestory(&con);



	//system("Pause");
	return 0;
}

Insert image description here

Guess you like

Origin blog.csdn.net/m0_73678713/article/details/134771480