C言語データ構造 - 動的シーケンステーブルに基づくアドレス帳の実装


1 基本要件

C 言語の基本要件: 構造体、動的メモリ管理、シーケンス テーブル、ファイル操作

アイデア: 完成したシーケンス テーブルを使用して、シーケンス テーブルを簡単に変更し、アドレス帳に適用します。

2 アドレス帳機能

アドレス帳は100人まで登録可能
ユーザー情報:名前、性別、年齢、電話番号、
住所 アドレス帳の表示、追加、削除、変更、検索、検索。

2.1 シーケンステーブルを導入するファイル

シーケンス テーブルが完成しました。バックアップして名前を変更しSeqList_copy.hコードと参照されるヘッダー ファイルの機能を作成してテストましSeqList_copy.c
Contact.hContact.ctest.c
test.cContact.cContact.hSeqList_copy.h

ここに画像の説明を挿入します

2.2 連絡先データ構造の定義

Contact.hヘッダー ファイルでは、
名前の最大長、性別の最大長、電話番号の最大長、およびアドレスの最大長を定義します。

#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 アドレス帳の初期化と破棄

シーケンス テーブルは初期化および破棄されているので、ここではそれを直接適用します。

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

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

2.4 連絡先の追加

連絡先を段階的に追加したかったので、段階的に追加していましたが、肥大化したように見えました。

取得するものは、CInfo 構造体に必要なすべてのデータです。
名前、性別、電話番号、およびアドレスはすべて文字列配列です。配列全体は、配列の最初の要素のアドレスを表します。scanf を使用すると、 & get する必要はありません。ただし
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);   //这里注意,定义age是int类型数组,使用scanf,仍需要&取地址
	printf("输入联系人电话:\n");
	scanf("%s", info.tel);
	printf("输入联系人住址:\n");
	scanf("%s", info.addr);
	printf("输入完成\n\n");

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

2.5 連絡先の削除

ここでは、比較的単純な名前で連絡先を削除します。
ポイント 1:FindByName関数を作成し、名前で検索できるかどうかを確認します。
ポイント 2: シーケンス テーブルで関数を使用しSLErase、そのパラメーターを観察し、添字を上手に使用します

FindByName関数の作成

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 連絡先の変更

機能を再度使用しますFindByName。連絡先を名前で変更します。

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 連絡先を探す

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 アドレス帳の表示

このロジックはシーケンステーブルとは少し異なるので書き直しました。

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 完全なコード表示

3.1 SeqList_copy.h

SeqList_copy.hコードの一部であるシーケンス テーブルの検索機能はアドレス帳には適用されないため、
このステップをコメントしてください。必ず動的シーケンス テーブルのデータ型をアドレス帳のデータ型に変更してください。

#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()機能は対象外ですFindByName()アドレス帳に名前が存在するかどうかを名前で確認する機能です
SLPrint()機能も対象外ですのでContactShow()機能があります

#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 連絡先.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 連絡先.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 テスト.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;
}

ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/m0_73678713/article/details/134771480
おすすめ