C语言顺序表的应用:基于动态顺序表实现通讯录

本文详细描述了一个项目,涉及如何使用顺序表数据结构存储和管理100个联系人的信息,包括姓名、性别、年龄、电话和地址。文章重点介绍了通讯录的初始化、增加、删除、修改、查找和个人信息操作的实现过程。
摘要由CSDN通过智能技术生成

在这里插入图片描述

1.功能要求

1)⾄少能够存储100个⼈的通讯信息
2)能够保存用户信息:名字、性别、年龄、电话、地址等
3)增加联系⼈信息
4)删除指定联系⼈
5)查找制定联系⼈
6)修改指定联系⼈
7)显示联系⼈信息
其实这个项目的难点在于:将顺序表中加嵌套结构体,将外部的顺序表比作为通讯录让后向其中加入结构体来记录数据

2.功能分析

一个人的数据可以放在一个结构体中,再将这个结构体放在顺序表中

在这里插入图片描述
那么文件可以分为:
在这里插入图片描述
在这里插入图片描述
这里有两个文件之前已经写过了我们需要稍作修改就可以使用了:
SeqList.h:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//定义顺序表的结构
#define N 100
struct SeqList01
{
	int arr[N];
	int size;
};

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* arr;
	int size; //有效数据的个数
	int capacity;//数组空间的大小
}SL;
//typedef struct SeqList SL;

//顺序表的初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);

//顺序表的插入(头部和尾部)
void SLPushBack(SL* ps, SLDataType x);//尾部插入
void SLPushFront(SL* ps, SLDataType x);//头部插入
void SLPopBack(SL* ps);//尾部删除
void SLPopFront(SL* ps);//头部删除
//判断空间够不够
void SLCheckCapacity(SL* ps);

//顺序表的任意插入和删除
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
//顺序表的查找
int SLFind(SL* ps, SLDataType x);


void SLPrint(SL s);//链表的打印

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
//顺序表的初始化和销毁
void SLInit(SL* ps)
{
	ps->arr = 0;
	ps->size = 0;
	ps->capacity = 0;
}
void SLDestroy(SL* ps)
{
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

//顺序表的插入(头部和尾部)
//判断空间够不够
void SLCheckCapacity(SL* ps)
{
	if (ps->capacity == ps->size)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror(tmp);
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size] = x;
	ps->size++;
	/*ps->arr[ps->size++] = x;*/
}

void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);//判断空间够不够

	for (int i = ps->size;i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	ps->size++;
}

void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);//顺序表不为空
	ps->size--;
}

void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1 ; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}
//顺序表的任意插入和删除
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

//顺序表的查找
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;
}

//链表的打印
void SLPrint(SL s)
{
	for (int i = 0; i < s.size; i++)
	{
		printf("%d ", s.arr[i]);
	}
	printf("\n");
}

3.功能的实现

3.1通讯录的命名和修改前置代码

要改的地方:
在这里插入图片描述
这里不能存储整形,而是要存储为结构体的类型
在这里插入图片描述
这里将联系人的信息放入结构体中
在这里插入图片描述

对通讯录的操作实际上就是对顺序表进行操作,这里我们进行初始化

在这里插入图片描述
但这里有很怪,我们对通讯录的初始化却用顺序表的名字,所以我们要对通讯录重新命名
在这里插入图片描述

此时运行代码:
在这里插入图片描述
我们会发现一堆的错误,然后我们发现头文件包含的问题是大多数
先看SeqList.h的头文件包含
在这里插入图片描述
这里包含Contact.h是因为要将personInfo结构体进行包含到通讯录中(顺序表)
但是Contact.h又要将SL定义为Perinfo又要包SeqList.h头文件但又不能相互包含所以只能进行前置声明
在这里插入图片描述
将这个结构体声明一下就不会出现这样的问题了
改进成这样:
在这里插入图片描述
此时运行:
在这里插入图片描述
又有以下的错误实际上就是SeqList.c文件中直接使用的int我们将其注释掉即可
在这里插入图片描述

此时再次执行就能通过了
在这里插入图片描述
后续我们就可以对通讯录进行操作了

3.2通讯录中个人信息的有关操作

3.2.1通讯录的初始化和销毁

在这里插入图片描述

这里是进行初始化、销毁、增加、删除、修改、查找、展示数据等
而顺序表的初始化已经写好了,我们对于通讯录的初始化可以直接调用顺序表的初始化
在这里插入图片描述
测试:在这里插入图片描述
在这里插入图片描述
同样的销毁也是这样直接调用顺序表的销毁即可
在这里插入图片描述

3.2.2通讯录的增加、删除和展示信息

3.2.2.1通讯录的增加信息

首先要获取信息可以直接将信息存入到已经构建好的结构体中
在这里插入图片描述

然后将数据这一个的个人信息存入到我们的通讯录中,这里我们使用尾插来插入
在这里插入图片描述

这里的年龄要加&操作符是因为字符数组的首元素就是该字符数组的地址
测试:
在这里插入图片描述

3.2.2.2通讯录的删除信息、展示信息

要想删除数据就要先判断数据在不在,我们可以通过遍历的方式来判断
在这里插入图片描述
在这里插入图片描述
这里要删除已经知道下标位置的联系人数据就可以调用顺序表任意位置的删除
在这里插入图片描述
这里调试的太麻烦了我们可以写一个打印函数直接运行就行
在这里插入图片描述
与之前不同的是遍历后要进入到结构体中取要的内容
测试:
在这里插入图片描述
这里发现表头对的不是很齐,我们可以稍微进行调整
在这里插入图片描述
更改成这样就大致对其了

3.2.3通讯录的修改和查找

3.2.3.1通讯录的修改

大前提:修改的联系人必须存在,直接用之前的进行判断
在这里插入图片描述
在这里插入图片描述

如果找到就直接让用户输入信息进行修改,这里可以直接到通讯录中的联系人进行修改
测试:
在这里插入图片描述

在这里插入图片描述

3.2.3.2通讯录的查找

在这里插入图片描述

前面判断联系人的方法一样,后面如果找到了就打印出联系人的全部信息
在这里插入图片描述
将展示的代码稍微修改即可
测试:
在这里插入图片描述

在这里插入图片描述

3.3通讯录界面设置

在这里插入图片描述

简单的循环嵌套就可以了,这里只是多加了通讯录的创建和销毁
下面就是测试了,由于内容过多就不进行展示了,大家可以自行测试,代码是没有问题的

以上就是本文的全部内容了,希望对大家有所帮助,大家加油!!!

本文代码:

SeqList.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "Contact.h"
#include <string.h>
//定义顺序表的结构
#define N 100
struct SeqList01
{
	int arr[N];
	int size;
};

//typedef int SLDataType;
typedef struct personInfo SLDataType;
typedef struct SeqList
{
	SLDataType* arr;
	int size; //有效数据的个数
	int capacity;//数组空间的大小
}SL;
//typedef struct SeqList02 SL;

//顺序表的初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);

//顺序表的插入(头部和尾部)
void SLPushBack(SL* ps, SLDataType x);//尾部插入
void SLPushFront(SL* ps, SLDataType x);//头部插入
void SLPopBack(SL* ps);//尾部删除
void SLPopFront(SL* ps);//头部删除
//判断空间够不够
void SLCheckCapacity(SL* ps);

//顺序表的任意插入和删除
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
//顺序表的查找
//int SLFind(SL* ps, SLDataType x);
//
//
//void SLPrint(SL s);//链表的打印

Contact.h

#pragma once

//联系人数据
//姓名、性别、年龄、电话、地址
#define NAME_MAX 20
#define GENDER_MAX 10 //male female boy girl
#define TEL_MAX 20
#define ADDR_MAX 100
typedef struct personInfo
{
	char name[NAME_MAX];
	char gender[GENDER_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}Perinfo;

typedef struct SeqList Contact;
//通讯录的相关方法
//初始化、销毁、增加、删除、修改、查找、展示数据等
void ContactInit(Contact* con);
void ContactDesTroy(Contact* con);
void ContactAdd(Contact* con);
void ContactDel(Contact* con);
void ContactModify(Contact* con);
void ContactFind(Contact* con);
void ContactShow(Contact* con);
int FindByName(Contact* con, char name[]);

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
//顺序表的初始化和销毁
void SLInit(SL* ps)
{
	ps->arr = 0;
	ps->size = 0;
	ps->capacity = 0;
}
void SLDestroy(SL* ps)
{
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

//顺序表的插入(头部和尾部)
//判断空间够不够
void SLCheckCapacity(SL* ps)
{
	if (ps->capacity == ps->size)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror(tmp);
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size] = x;
	ps->size++;
	/*ps->arr[ps->size++] = x;*/
}

void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);//判断空间够不够

	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	ps->size++;
}

void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);//顺序表不为空
	ps->size--;
}

void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}
//顺序表的任意插入和删除
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

顺序表的查找
//int SLFind(SL* ps, SLDataType x)
//{
//	assert(ps);
//	for (int i = 0; i < ps->size; i++)
//	{
//		if (ps->arr[i] == x)
//		{
//			return i;
//		}
//	}
//	return -1;
//}
//
链表的打印
//void SLPrint(SL s)
//{
//	for (int i = 0; i < s.size; i++)
//	{
//		printf("%d ", s.arr[i]);
//	}
//	printf("\n");
//}

Contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
#include "SeqList.h"

//初始化和销毁数据
void ContactInit(Contact* con)
{
	SLInit(con);
}
void ContactDesTroy(Contact* con)
{
	SLDestroy(con);
}

//增加、删除、修改、查找、展示数据等
void ContactAdd(Contact* con)
{
	//获取信息(姓名、性别、年龄、电话、地址)
	Perinfo info;//创建联系人的结构体
	printf("请输入要添加联系人的姓名:\n");
	scanf("%s", info.name);
	printf("请输入要添加联系人的性别:\n");
	scanf("%s", info.gender);
	printf("请输入要添加联系人的年龄:\n");
	scanf("%d", &info.age);
	printf("请输入要添加联系人的电话:\n");
	scanf("%s", info.tel);
	printf("请输入要添加联系人的地址:\n");
	scanf("%s", info.addr);
	//向通讯录中插入数据
	SLPushBack(con, info);
}

void ContactDel(Contact* con)
{
	//要出在才能执行删除
	//查找
	printf("请输入要删除联系人的姓名:\n");
	char name[NAME_MAX];
	scanf("%s", name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		printf("要删除的联系人不存在!\n");
		return;
	}
	//删除联系人(已经知道了要删除联系人的下标)
	SLErase(con, find);
	printf("删除成功\n");
}

int FindByName(Contact* con, char name[])
{
	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->arr[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

void ContactShow(Contact* con)
{
	//表头:
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (int i = 0; i < con->size; i++)
	{
		printf("%3s %4s %4d %4s %4s\n",
			con->arr[i].name,
			con->arr[i].gender,
			con->arr[i].age,
			con->arr[i].tel,
			con->arr[i].addr);
	}
}

void ContactModify(Contact* con)
{
	char name[NAME_MAX];
	printf("请输入要修改联系人的姓名:\n");
	scanf("%s", name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		printf("要修改的联系人数据不存在!\n");
		return;
	}
	printf("请输入新的姓名:\n");
	scanf("%s", con->arr[find].name);
	printf("请输入新的性别:\n");
	scanf("%s", con->arr[find].gender);
	printf("请输入新的年龄:\n");
	scanf("%d", &con->arr[find].age);
	printf("请输入新的电话:\n");
	scanf("%s", con->arr[find].tel);
	printf("请输入新的地址:\n");
	scanf("%s", con->arr[find].addr);
	printf("修改成功!\n");
}

void ContactFind(Contact* con)
{
	char name[NAME_MAX];
	printf("请输入要查找联系人的姓名:\n");
	scanf("%s", name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		printf("要修改的联系人数据不存在!\n");
		return;
	}
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("%3s %4s %4d %4s %4s\n",
		con->arr[find].name,
		con->arr[find].gender,
		con->arr[find].age,
		con->arr[find].tel,
		con->arr[find].addr);
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"

void ContactTest01()
{
	Contact con;
	ContactInit(&con);
	//增加、删除、修改、查找、展示数据等
	ContactAdd(&con);
	ContactAdd(&con); 
	ContactShow(&con);
	/*ContactDel(&con);
	ContactShow(&con);
	ContactShow(&con);*/
	ContactModify(&con);
	ContactShow(&con);
	ContactFind(&con);
	ContactDesTroy(&con);
}

void menu()
{
	printf("******************通讯录****************\n");
	printf("**************1.增加联系人**************\n");
	printf("**************2.删除联系人**************\n");
	printf("**************3.修改联系人**************\n");
	printf("**************4.查找联系人**************\n");
	printf("**************5.展示联系人**************\n");
	printf("*****************0.退出*****************\n");
}
int main() 
{
	int input = 0;
	Contact con;
	ContactInit(&con);
	do
	{
		menu();
		printf("请选择您的操作:\n");
		scanf("%d", &input);
		switch (input)
		{
		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;
		default:
			printf("输入错误请重新选择您的操作\n");
			break;
		}
	} while (input);
	printf("退出成功!");
	ContactDesTroy(&con);
	/*ContactTest01();*/
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值