当前位置:首页 » 《关注互联网》 » 正文

思路十分清晰的带大家入门:通讯录-----图书管理系统---学生信息管理系统等小项目的实现,还等什么呢?快来学习吧!_ai15013602354的博客

9 人参与  2022年01月15日 16:32  分类 : 《关注互联网》  评论

点击全文阅读


✨前言✨:

大家在学习完自定义类型结构体后,就可以尝试自己写一些小项目了,例如:通讯录--图书管理系统---学生信息管理系统等项目,它们的内在逻辑都是相同的,这不仅可以提升大家的coding能力,还可以提升大家对于结构体的理解。

本博客以通讯录的实现为例子


目录

✨前言✨:

💎预期功能💎

💎具体功能的实现💎

一:如何存放联系人的信息

二:如何创建通讯录

 三:如何添加联系人

四:如何打印出当前通讯录

五:如何删除指定联系人的信息

💎总代码的展示💎



💎预期功能💎

在做项目时,无论是大项目还是小项目,都要做到先理清:要实现项目的预期功能是什么----按照这些预期功能把项目进行拆解成一个个的功能----把每一个特定功能分装成一个函数。这其实就是模块化编程思想,在做项目时尤其重要。

🔑:预期通讯录的功能如下

      1:能存放联系人的信息(包括:姓名  年龄  性别  电话号码 家庭住址 等信息)

      2:支持在这个通讯录内部添加💎功能的具体实现💎联系人的信息

      3:支持删除这个通讯录中指定的联系人的信息

      4:支持打印出整个通讯录,显示出整个通讯录的信息

      5:支持查找指定联系人,并打印出该联系人的信息

      6:支持修改这个通讯录中指定联系人的信息


💡:由上述预期通讯录的功能可以将整个项目按功能拆成一个个模块,再把一个个模块分装成一个个函数。

💎具体功能的实现💎

一:如何存放联系人的信息

💡:由于要描述每一个联系人,我们需要记录下每一位联系人的姓名,年龄,性别,电话号码,家庭住址。所以我们知道想要描述一个联系人需要多种不同的数据类型,因此我们考虑用一个结构体来记录联系人的信息。

 🔑:具体代码的实现:

struct PeoInfo
{
	char name[NAME_MAX];//记录联系人的性别
	int age;//联系人的年龄
	char sex[SEX_MAX];//联系人的性别
	char tele[TELE_MAX];//联系人的电话号码
	char addr[ADDR_MAX];//联系人的家庭地址
};


二:如何创建通讯录

💡:首先我们要明确通讯录中包含什么?

1:通讯录中要有一块空间来储存联系人的信息,而联系人的信息我们明确了是结构体类型。

2:通讯录中要有一个变量记录当前通讯录中联系人的个数

3:通讯录中要有一个变量来记录当前通讯录的总容量

 🔑:读到这里,大家可能意识到了,创建一个通讯录遇到的最大困难是:如何为通讯录分配空间?

如果我们预先确定其最大容量,即写一个总容量大小确定的通讯录(例如创建一个最多放1000个联系人的通讯录),这时就存在问题,由于空间在运行前就固定好了,所以你无论开辟多大空间都不太合适。预先开辟的空间大了,就会浪费空间;预先开辟空间小了,就会导致放不下联系人。

在这里我们就可以引入动态内存开辟的思路,我们可以预先开辟一个较小空间。如果在放入数据时,发现通讯录满了,就给通讯录扩容。这样可以很好的减少空间的浪费。

 💡:在这里还要解决一个问题,那就是什么时候给通讯录进行扩容处理,很容易就能够分析出来,只有在准备添加联系人时,发现通讯录已经满了,此时才需要扩容,也就是说扩容发生在添加联系人的时候。

//由于通讯录中包含多种不同的数据类型
//因此通讯录应该是结构体类型
//动态容量版本
struct Contact
{
	struct PeoInfo* date;//指向n个联系人空间的起始地址 作用是维护整个整个通讯录
	int sz;//通讯录有效元素的个数
	int capcity;//当前通讯录的最大容量
};
//动态容量版本
//DEFAULT_SZ是定义的宏常量 初始值预开辟的较小容量是3 
void InitContact(struct Contact* pc)
{
	//给通讯录初始化较小的空间
	pc->sz = 0;
	pc->date=(struct PeoInfo*)malloc(DEFAULT_SZ *sizeof(struct PeoInfo));
	pc->capcity = DEFAULT_SZ;
}
void AddContact(struct Contact* pc)
{
	if (pc->sz == pc->capcity)
	{
		//需要进行扩容操作
		struct PeoInfo* tmp=(struct PeoInfo*)realloc(pc->date, (DEFAULT_SZ + 2) * sizeof(struct PeoInfo));
		if (tmp != NULL)
		{
			pc->date = tmp;
			pc->capcity += 2;
			printf("扩容成功\n");
		}
		else {
			printf("扩容失败,通讯录已满,无法添加联系人\n");
			return 0;
		}
	}
	//在动态增长的版本,不存在满的概念
	//只要空间满就会扩容,不存在添加失败的情况
	//if (pc->sz == MAX)
	//{
	//	printf("添加失败,通讯录已满了\n");
	//}
	printf("请输入姓名:>");
	scanf("%s", pc->date[pc->sz].name);
	printf("请输入年龄:>");
	scanf("%d",&(pc->date[pc->sz].age));
	printf("请输入性别:>");
	scanf("%s", pc->date[pc->sz].sex);
	printf("请输入电话:>");
	scanf("%s", pc->date[pc->sz].tele);
	printf("请输入地址:>");
	scanf("%s", pc->date[pc->sz].addr);
	pc->sz++;
	printf("添加成功\n");
}

 其中的代码块是从总代码中截取出来的,有一些函数,变量未曾声明定义。


 三:如何添加联系人

💡:想要在通讯录中添加联系人十分简单,由于我们的通讯录总容量是动态开辟的,所以在扩容成功的前提下不存在通讯录已经满了,无法添加的情况。我们只需要把人的信息一个个输入就够了。

🔑:代码展示

void AddContact(struct Contact* pc)
{
	if (pc->sz == pc->capcity)
	{
		//需要进行扩容操作
		struct PeoInfo* tmp=(struct PeoInfo*)realloc(pc->date, (DEFAULT_SZ + 2) * sizeof(struct PeoInfo));
		if (tmp != NULL)
		{
			pc->date = tmp;
			pc->capcity += 2;
			printf("扩容成功\n");
		}
		else {
			printf("扩容失败,通讯录已满,无法添加联系人\n");
			return 0;
		}
	}
	//在动态增长的版本,不存在满的概念
	//只要空间满就会扩容,不存在添加失败的情况
	//if (pc->sz == MAX)
	//{
	//	printf("添加失败,通讯录已满了\n");
	//}
	printf("请输入姓名:>");
	scanf("%s", pc->date[pc->sz].name);
	printf("请输入年龄:>");
	scanf("%d",&(pc->date[pc->sz].age));
	printf("请输入性别:>");
	scanf("%s", pc->date[pc->sz].sex);
	printf("请输入电话:>");
	scanf("%s", pc->date[pc->sz].tele);
	printf("请输入地址:>");
	scanf("%s", pc->date[pc->sz].addr);
	pc->sz++;
	printf("添加成功\n");
}


四:如何打印出当前通讯录

首先我们先来看一看预期达到的效果,再按照这个预期的效果来写代码

从这个表格可以看出我们预期实现的效果,类似一个表格,上面一行写标签,下面写具体联系人的信息。

想要达到这个效果,无疑我们必须要会灵活的运用格式化输出,如果不会的可以看看书本,在此不做过多的赘述。

🔑:代码展示:

void ShowContact(struct Contact* pc)
{
	int i = 0;
//打印表格标签名  注意格式化输出
	printf("%20s\t%5s\t%8s\t%20s\t%30s\n", "name", "age", "sex", "tele", "addr");
	for (i = 0; i < pc->sz; i++)
	{
		//利用循环逐个打印联系人的信息
		printf("%20s\t%5d\t%8s\t%20s\t%30s\n", pc->date[i].name,
			pc->date[i].age,
			pc->date[i].sex,
			pc->date[i].tele,
			pc->date[i].addr);
	}
}


五:如何删除指定联系人的信息

💡:我们想删除指定联系人的信息,前提条件是我们要通过联系人的姓名在通讯录中找到该联系人,所以这个问题的难点就在于以下两点:

  1:通过姓名找到该联系人后,要返回什么信息,执行什么样的操作?

  2:如何在date指针所维护的联系人信息空间中,删除指定的元素?

🔑:现在我们来解决以上的两个问题

1:在找到时,我们希望能返回该联系人的下标(即把动态变化的空间视为一个数组),若找不到则返回-1

2:要在这个数组中删除一个联系人其实很简单,我们只需要把该联系人之后的所有联系人整体向左移动一个单位,然后让有效联系人个数减一就够了

💡:代码展示

//对于按名字查找指定联系人时我们定义如下规则
//如果查找到了,则返回date数组中该人信息的下标
//如果找不到,则返回-1
int SearchByNameContact(const char name[], struct Contact* pc)
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(name, pc->date[i].name) == 0)
		{
			return i;
		}
	}
	return -1;
}
//删除指定联系人
void DelContact(struct Contact* pc)
{
	if (pc->sz == 0)
	{
		printf("该通讯录为空,无法删除\n");
		return;
	}
	printf("请输入你要删除联系人的姓名:>");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int pos = SearchByNameContact(name,pc);
	if (pos == -1)
	{
		printf("你想删除的联系人不存在\n");
	}
	else
	{
		//对联系人进行删除
		for (int i = pos; i < pc->sz - 1; i++)
		{
			pc->date[i] = pc->date[i + 1];
		}
		pc->sz--;
		printf("删除成功\n");
	}
	 
}


而查找功能其实就是按名字查找函数和打印的组合。

而修改功能其实就是按名字查找和重新录入信息的组合。

这两种功能的思路和以上方法思路重合,在此就不做过多的赘述。


💎总代码的展示💎

有于该项目涉及到很多的函数,因此我们分模块来写,在contact.h中声明函数 ,在contact.c中给出函数的具体定义 在text.c中使用函数并打印菜单

💡;contact.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 20
#define ADDR_MAX 30
#define MAX 1000
#define DEFAULT_SZ 3
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
};
//静态版本
//struct Contact
//{
将1000个人的数据放在date数组中
//    struct PeoInfo date[MAX];
//    int sz;//记录当前通讯录有效学生信息的个数
//};
//动态版本
struct Contact
{
	struct PeoInfo* date;
	int sz;//通讯录有效元素的个数
	int capcity;//当前通讯录的最大容量
};
//初始化通讯录
void InitContact(struct Contact* pc);
//添加联系人
void AddContact(struct Contact* pc);
//显示通讯录(打印通讯录)
void ShowContact(struct Contact* pc);
//查找练习人,并输出
void SearchContact(const struct Contact* pc);
//删除指定的联系人
void DelContact(struct Contact* pc);
//修改指定的联系人
void ModifyContact(struct Contact* pc);


💡:text.c的代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"contact.h"

//写一个通讯录头文件
void menu()
{
	printf("***********************************\n");
	printf("*****   1.add   2.del *************\n");
	printf("*****3.search 4.modify    *********\n");
	printf("*****    5.show  6.sort  **********\n");
	printf("******       0.exit        ********\n");
	printf("***********************************\n");
}
enum option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};
int main()
{
	//1:创建一个通讯录
	struct Contact con;
	//2:对通讯录进行初始化
	InitContact(&con);
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		case SEARCH:
			SearchContact(&con);			
			break;
		case MODIFY:
			ModifyContact(&con);
		default:
			printf("选择错误,请重新选择\n");
			break;
		}

	} while (input);
	return 0;
}

💡:contact.c的代码

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
//OK 已经实现功静态容量的通讯录
//将静态容量的通讯录-->动态容量的通讯录  升级版本
//void InitContact(struct Contact* pc)
//{
//	pc->sz = 0;
//	memset(pc->date,0,sizeof(pc->date));
//}
//动态容量版本
void InitContact(struct Contact* pc)
{
	//给通讯录初始化较小的空间
	pc->sz = 0;
	pc->date=(struct PeoInfo*)malloc(DEFAULT_SZ *sizeof(struct PeoInfo));
	pc->capcity = DEFAULT_SZ;
}
void AddContact(struct Contact* pc)
{
	if (pc->sz == pc->capcity)
	{
		//需要进行扩容操作
		struct PeoInfo* tmp=(struct PeoInfo*)realloc(pc->date, (DEFAULT_SZ + 2) * sizeof(struct PeoInfo));
		if (tmp != NULL)
		{
			pc->date = tmp;
			pc->capcity += 2;
			printf("扩容成功\n");
		}
		else {
			printf("扩容失败,通讯录已满,无法添加联系人\n");
			return 0;
		}
	}
	//在动态增长的版本,不存在满的概念
	//只要空间满就会扩容,不存在添加失败的情况
	//if (pc->sz == MAX)
	//{
	//	printf("添加失败,通讯录已满了\n");
	//}
	printf("请输入姓名:>");
	scanf("%s", pc->date[pc->sz].name);
	printf("请输入年龄:>");
	scanf("%d",&(pc->date[pc->sz].age));
	printf("请输入性别:>");
	scanf("%s", pc->date[pc->sz].sex);
	printf("请输入电话:>");
	scanf("%s", pc->date[pc->sz].tele);
	printf("请输入地址:>");
	scanf("%s", pc->date[pc->sz].addr);
	pc->sz++;
	printf("添加成功\n");
}
void ShowContact(struct Contact* pc)
{
	int i = 0;
	printf("%20s\t%5s\t%8s\t%20s\t%30s\n", "name", "age", "sex", "tele", "addr");
	for (i = 0; i < pc->sz; i++)
	{
		//进行通讯表的打印
		printf("%20s\t%5d\t%8s\t%20s\t%30s\n", pc->date[i].name,
			pc->date[i].age,
			pc->date[i].sex,
			pc->date[i].tele,
			pc->date[i].addr);
	}
}
//静态版通讯录--->升级到动态版
// 
//如果在通讯录中找到了联系人,则打印出该联系人的信息
//如果没有该联系人则返回false
//并不是像hash 查找一样 需要一个个的查找

//对于按名字查找指定联系人时我们定义如下规则
//如果查找到了,则返回date数组中该人信息的下标
//如果找不到,则返回-1
int SearchByNameContact(const char name[], struct Contact* pc)
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(name, pc->date[i].name) == 0)
		{
			return i;
		}
	}
	return -1;
}
//删除指定联系人
void DelContact(struct Contact* pc)
{
	if (pc->sz == 0)
	{
		printf("该通讯录为空,无法删除\n");
		return;
	}
	printf("请输入你要删除联系人的姓名:>");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int pos = SearchByNameContact(name,pc);
	if (pos == -1)
	{
		printf("你想删除的联系人不存在\n");
	}
	else
	{
		//对联系人进行删除
		for (int i = pos; i < pc->sz - 1; i++)
		{
			pc->date[i] = pc->date[i + 1];
		}
		pc->sz--;
		printf("删除成功\n");
	}
	 
}
void SearchContact(const struct Contact* pc)
{
	printf("请输入你要查找联系人的名字:>");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int ret = SearchByNameContact(name,pc);
	if (ret == -1)
	{
		printf("查无此人\n");
		return 0;
	}
	printf("%20s\t%5s\t%8s\t%20s\t%30s\n", "name", "age", "sex", "tele", "addr");
	printf("%20s\t%5d\t%8s\t%20s\t%30s\n", pc->date[ret].name,
		pc->date[ret].age,
		pc->date[ret].sex,
		pc->date[ret].tele,
		pc->date[ret].addr);
}
void ModifyContact(struct Contact* pc)
{
	printf("请输入你要修改的联系人\n");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int pos = SearchByNameContact(name,pc);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
		return;
	}
	else
	{
		printf("请输入姓名:>");
		scanf("%s", pc->date[pos].name);
		printf("请输入年龄:>");
		scanf("%d", &(pc->date[pos].age));
		printf("请输入性别:>");
		scanf("%s", pc->date[pos].sex);
		printf("请输入电话:>");
		scanf("%s", pc->date[pos].tele);
		printf("请输入地址:>");
		scanf("%s", pc->date[pos].addr);
		printf("修改成功\n");
	}
}

以上代码,还可做优化在此仅作参考,若有更好的算法,还望能够私信告知,多谢各位。

由于本人水平十分有限,若有错误请即使告知!如果有帮助别忘了,万分感谢。

点赞👍         收藏✨    关注✌


点击全文阅读


本文链接:http://zhangshiyu.com/post/33329.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1