当前位置: 首页 > article >正文

C语言笔记(通讯录)

目录

1.通讯录的架构

2.通讯录的功能

3.实现静态通讯录的功能步骤

3.1.创建通讯录数组

3.2.显示功能菜单

3.3.初始化通讯录

3.4.添加联系人的信息

3.5.显示联系人的信息

3.6.查找某个人的信息

3.7.删除某一个联系人信息

3.8.修改某一联系人的信息

3.9.按名字对联系人排序

3.10.清空通讯录

4.动态版本的实现

  4.1.重新定义通讯录

4.2.初始换通讯录

4.3.扩容和写入信息函数

5.将通讯录存入文件中

6.代码

6.1.contact.h文件

6.2.test.c文件

6.3.contact.c文件


  前言:

        本片通讯录分为两个版本;静态和动态版本,区别在静态版本就像是纸质的通讯录一样,无法增加容量;而动态版本使用动态内存函数(malloc、realloc)来实现扩容,达到使多少扩多少的目的,以节省内存空间。若有错误请批评指正。

1.通讯录的架构

        通讯录的编写分为了三个文件

1.test.c              主要编写 测试程序(程序运行的运行框架)

2.contact.c       主要编写测试程序中用到的自定义函数

3.contact.h      (1)包含相关的头文件

                         (2)创建全局变量

                         (3)声明contact.c中的函数

2.通讯录的功能

存储信息: 姓名 年龄 性别 地址 电话

静态版本实现功能:

  1.  显示功能菜单;
  2. 添加联系人的信息;
  3. 显示联系人的信息; 
  4. 查找某一个联系人信息;
  5. 删除某一联系人的信息;
  6. 修改某一联系人的信息;
  7. 按名字对联系人排序。

动态版本实现功能:

  1. 可以随着联系人的增多实现空间扩容。

3.实现静态通讯录的功能步骤

3.1.创建通讯录数组

        创建存储联系人信息的结构体 ,并重新命名为PeoInfo

typedef struct PeoInfo
{
	char name[20];
	int age;
	char sex[5];
	char addr[30];
	char tele[12];
}PeoInfo;

        创建通讯录数组;使用宏定义的通讯录大小以便查找和修改

#define MAX 1000//静态情况下定义的通讯录最大容量
typedef struct Contact
{
    PeoInfo data[MAX];//存放个人信息的
	int sz;           //当前已经存放几个人的信息
}contact;
3.2.显示功能菜单

        函数较为简单不做过多的说明;仅仅时printf函数的应用

void menu()
{
	printf("***********************************\n");
	printf("******  1.Add     2.Del     *******\n");
	printf("******  3.Search  4.Modify  *******\n");
	printf("******  5.Show    6.Sort    *******\n");
	printf("******  7.Clear   0.Exit    *******\n");
	printf("***********************************\n");
}
3.3.初始化通讯录

        初始化通讯录的目的就是将通讯录所占用的内存中的数据全部置为0。

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

memset函数  将 ptr 指向的内存块的前字节设置为指定

void * memset ( void * ptr, int value, size_t num );

ptr      指向要填充的内存块的指针

value  要设置的值。

num    要设置为该值的字节数

3.4.添加联系人的信息

        简单的说就是给一个信息数组输入数据,核心为scanf函数。

        第一个函数:判断通讯录是否还有空间;然后再调用信息输入函数;

        第二个函数:信息输入函数。

//添加信息函数
void AddContact(contact* pc)
{
	if (pc->sz == MAX)
	{
		printf("通讯录已满");
		return;
	}
	ScanfInformation(pc);
}
//录入信息函数,调出来方便后续的使用
void ScanfInformation(contact* pc)
{
	printf("请输入名字\n");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入地址\n");
	scanf("%s", pc->data[pc->sz].addr);
	printf("请输入电话\n");
	scanf("%s", pc->data[pc->sz].tele);
	printf("输入完成\n");
	pc->sz++;
	printf("录入成功\n");
}
3.5.显示联系人的信息

        显示联系人的核心是printf函数应用;

-  为右对齐

+ 为左对齐

\t 为水平制表符

pc为结构体指针;使用->符号对结构体数据进行访问。

void ShowContact(const contact* pc)
{
	printf("%-10s\t %-10s\t %-9s\t %-9s\t %-10s\n","姓名" ,"年龄"," 性别"," 地址"," 电话");
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-10s\t %-10d\t %-10s\t %-10s\t %-10s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].addr,
			pc->data[i].tele);
	}

}
3.6.查找某个人的信息

思路

  1. 找到这个人
  2. 然后显示信息
void SearchContact(contact* pc)
{
	//通过名字寻找联系人信息
	printf("请输入要搜索联系人的姓名\n");
	int pos = FindByName(pc);
	ShowContactone(pc, pos);
}

int FindByName(contact* pc)
{
	char name[20] = { 0 };
	
	scanf("%s", name);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{	
			return i;
		}
	}
	return -1;
}


void ShowContactone(const contact* pc,int pos)//打印一个人的信息
{
	printf("%-10s\t %-10s\t %-9s\t %-9s\t %-10s\n", "姓名", "年龄", " 性别", " 地址", " 电话");
	
		printf("%-10s\t %-10d\t %-10s\t %-10s\t %-10s\n",
			pc->data[pos].name,
			pc->data[pos].age,
			pc->data[pos].sex,
			pc->data[pos].addr,
			pc->data[pos].tele);
}
3.7.删除某一个联系人信息

        按照名字来找联系人,并显示这个人的信息;主要就是strcmp函数比较

strcmp函数  比较两个字符串

int strcmp ( const char * str1, const char * str2 );

  1. 函数1:要找个人的大体思路;
  2. 函数2:按名字找人;
  3. 函数3:输出这个人的信息。
int FindByName(contact* pc)
{
	char name[20] = { 0 };
	
	scanf("%s", name);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{	
			return i;
		}
	}
	return -1;
}


void DelContact(contact* pc)//找到删除人的名字然后向前递增一下
{
	printf("请输入要删除的人的名字\n");
	int del = FindByName(pc);
	//然后信息覆盖
	if (del >= 0)
	{
		for (;  del < pc->sz; del++)
		{
			pc->data[del] = pc->data[del + 1];
		}
		pc->sz--;
		printf("删除成功\n");
	}
	else if (del < 0)
	{
		printf("未找到该联系人\n");
	}
}
3.8.修改某一联系人的信息

思路

  1. 找到这个人
  2. 重新录入信息
    void ModifyContact(contact* pc)
    {
    	printf("请输入要修改联系人的姓名\n");
    	int pos = FindByName(pc);
    	if (-1 == pos)
    	{
    		printf("未查找到此人\n");
    	}
    	else //修改某人的信息
    	{
    		printf("请输入名字\n");
    		scanf("%s", pc->data[pos].name);
    		printf("请输入年龄\n");
    		scanf("%d", &(pc->data[pos].age));
    		printf("请输入性别\n");
    		scanf("%s", pc->data[pos].sex);
    		printf("请输入地址\n");
    		scanf("%s", pc->data[pos].addr);
    		printf("请输入电话\n");
    		scanf("%s", pc->data[pos].tele);
    		printf("输入完成\n");
    		printf("修改成功,修改信息如下\n");
    		ShowContactone(pc, pos);
    	}
    }
    
    
    int FindByName(contact* pc)
    {
    	char name[20] = { 0 };
    	
    	scanf("%s", name);
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		if (strcmp(pc->data[i].name, name) == 0)
    		{	
    			return i;
    		}
    	}
    	return -1;
    }
    
    

3.9.按名字对联系人排序

qsort函数

void qsort (void* base, size_t num, size_t size,
            int (*compar)(const void*,const void*));

base 指向要排序的数组的第一个对象的指针,转换为 .void*

num 指向的数组中的元素数。

size 指向的数组中的元素数。(以字节为单位)

int (*compar)(const void*,const void*)

指向比较两个元素的函数的指针。
此函数

int CompareByName(const void * a, const void * b)
{
	return (((PeoInfo*)a)->name ,((PeoInfo*)b)->name);
}
void SortContact(contact* pc) 
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录没有人\n");
		return;
	}
	qsort(pc->data, pc->sz, sizeof(pc->data[0]),CompareByName);//数组 数组的大小 数组有几个元素,数组元素的大小
	printf("排序完成\n");

}
3.10.清空通讯录

        思路:通讯录不清零和初始化一样所以

void DestoryContact(contact* pc)
{
	pc->data = NULL;
    pc->sz = 0;
    pc-capacity = 0;
}

4.动态版本的实现

  4.1.重新定义通讯录
typedef struct Contact
{
	PeoInfo* data;//存放个人信息的
	int sz;           //当前已经存放几个人的信息
	int capacity;     //目前通讯录的容量
}contact;
4.2.初始换通讯录

        使用malloc函数开辟空间;

1.功能:

  malloc:向内存申请一块连续可用的空间,返回指向这块空间起始的指针;

  free:   释放动态开辟的内存。

2.使用形式

void* malloc (size_t size);
void free (void* ptr);

1.void* 返回值类型为空指针,需要强转换再使用,申请成功返回内存块起始指针,申请内存失败,返回位空指针;

2.size 内存块的大小,字节位单位,size_t无符号整型;

注意:

1.malloc函数申请的空间是不会初始化的,内存块不初始化是随机值。

2.在free释放内存块之后,void* 函数的返回值保留之前的开辟内存块的时候指针变量,

如果再访问就是非法访问了,因此使用完内存空间要将返回值置为NULL,可看示例。

#define DEFAULT_SZ 3 //初始开辟空间
#define INC_SZ 3     //每次扩容的大小

void InitContact2(contact* pc)
{
	assert(pc);
    pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
	if (pc == NULL)
	{
		perror("Init_Contact2:");
		return;
	}
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
}
4.3.扩容和写入信息函数
  1. 判断通讯录是否还有空间
  2. 有空间录入信息,无空间扩容后再录入新信息

realloc函数

        1.功能:Reallocate memory block,重新分配内存块的大小,扩展原有的内存块,或者申请新的内存块,

        特点:保留之前的内存中的数据。

        2.使用形式:

void* realloc (void* ptr, size_t size);
int Checkcapacity(contact* pc)
{
	//判断是否要扩容
	PeoInfo* str;
	if (pc->sz == pc->capacity)
	{
		str = (PeoInfo*)realloc(pc->data, (pc->sz + INC_SZ) * sizeof(PeoInfo));
	
		if (str==NULL)
		{
			perror("Check_capacity");
			printf("扩容失败\n");
			return 0;
		}
		else
		{
			pc->data = str;
			pc->capacity += INC_SZ;
			printf("扩容成功\n");
		}
	}
	return 1;
}

void AddContact2(contact* pc)
{
	assert(pc);
	int ret = Checkcapacity(pc);
	if (0 == ret)
	{
		return ;

	}
	//录入信息
	else
	ScanfInformation(pc);
}

5.将通讯录存入文件中

        选择使用二进制的存储较为方便

void SaveContact(contact* pc)
{

	assert(pc);
	//打开文件
	FILE* pf = fopen("contact.txt","wb");//二进制方打开
	if (NULL == pf)
	{
		perror("SaveContact");
		return;
	}
	else 
	{
		int i = 0;
		for (i = 0; i < pc->sz; i++)
		{
			fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);//写入
		}
		fclose(pf);
		pf == NULL;
	}
}

6.代码

6.1.contact.h文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

//定义变量
#define MAX 1000//静态情况下定义的通讯录最大容量
#define DEFAULT_SZ 3
#define INC_SZ 3

typedef struct PeoInfo
{
	char name[20];
	int age;
	char sex[5];
	char addr[30];
	char tele[12];
}PeoInfo;
//创建通讯录
//typedef struct Contact
//{
//	PeoInfo data[MAX];//存放个人信息的
//	int sz;           //当前已经存放几个人的信息
//}contact;

typedef struct Contact
{
	PeoInfo* data;//存放个人信息的
	int sz;           //当前已经存放几个人的信息
	int capacity;     //目前通讯录的容量
}contact;


//功能菜单
void menu();
//初始化通讯录
//静态版本
void InitContact( contact* pc);
//动态版本
void InitContact2(contact* pc);
//输入信息
void AddContact(contact* pc);
//动态版本在输入信息之前容量增大需要扩容
int Checkcapacity(contact* pc);
void AddContact2(contact* pc);

//显示通讯录
void ShowContact( contact* pc);
//删除指定人信息
void DelContact( contact* pc);
//寻找某一的联系人的联系方式
void SearchContact(contact* pc);
//修改某一的联系人的联系方式
void ModifyContact(contact* pc);
//排序
void SortContact(contact* pc);
//清空联系人 初始化
void DestoryContact(contact* pc);
//存储通讯录中的信息到文件中
void SaveContact(contact* pc);
6.2.test.c文件

        使用了一个枚举变量,和do……while循环以及swich()分支语句

#define _CRT_SECURE_NO_WARNINGS
#include "contact.h"
enum 
{
	Exit = 0,
	Add,     
	Del,
	Search,  
	Modify,
	Show,    
	Sort	
};
void menu();
int main()
{
	int input = 0;
	contact con;
	//初始化通讯录
	InitContact2(&con);
	do 
	{
		menu();
		printf("            请选择模式\n");
		scanf("%d", &input);
		switch(input)
		{
		case Add:
			AddContact2(&con);
			break;
		case Del:	
			DelContact(&con);
			break;
		case Search:
			SearchContact(&con);
			break;
		case Modify:
			ModifyContact(&con);
			break;
		case Show:
			ShowContact(&con);
			break;
		case Sort:
			SortContact(&con);
			break;
		case Exit:
			SaveContact(&con);
			DestoryContact(&con);
			printf("退出编辑\n");
		default:
			printf("输入错误,请重新输入\n");
		}
	} 
	while (input);

	return 0;
}
6.3.contact.c文件

        contact.c文件起始就是函数来回调用;模块化更为简单易懂,看着方便。

#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("******  7.Clear   0.Exit    *******\n");
	printf("***********************************\n");


}
//按照名字寻找某人
int FindByName(contact* pc)
{
	char name[20] = { 0 };
	
	scanf("%s", name);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{	
			return i;
		}
	}
	return -1;
}
void ScanfInformation(contact* pc)
{
	printf("请输入名字\n");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入地址\n");
	scanf("%s", pc->data[pc->sz].addr);
	printf("请输入电话\n");
	scanf("%s", pc->data[pc->sz].tele);
	printf("输入完成\n");
	pc->sz++;
	printf("录入成功\n");
}

//初始化通信录//清空通讯录
void InitContact( contact* pc) 
{
     assert(pc);
	 pc->sz = 0;
	 memset(pc->data, 0, sizeof(pc->data));
}
//动态版本
void InitContact2(contact* pc)
{
	assert(pc);
    pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
	if (pc == NULL)
	{
		perror("Init_Contact2:");
		return;
	}
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
}
//录入信息 静态 不再扩容的情况
//检查容量
int Checkcapacity(contact* pc)
{
	//判断是否要扩容
	PeoInfo* str;
	if (pc->sz == pc->capacity)
	{
		str = (PeoInfo*)realloc(pc->data, (pc->sz + INC_SZ) * sizeof(PeoInfo));
	
		if (str==NULL)
		{
			perror("Check_capacity");
			printf("扩容失败\n");
			return 0;
		}
		else
		{
			pc->data = str;
			pc->capacity += INC_SZ;
			printf("扩容成功\n");
		}
	}
	return 1;
}

void AddContact2(contact* pc)
{
	assert(pc);
	int ret = Checkcapacity(pc);
	if (0 == ret)
	{
		return ;

	}
	//录入信息
	else
	ScanfInformation(pc);
}


void AddContact(contact* pc)
{
	if (pc->sz == MAX)
	{
		printf("通讯录已满");
		return;
	}
	ScanfInformation(pc);
}
//录入信息 静态 不再扩容的情况



//显示通讯录
void ShowContact(const contact* pc)
{
	printf("%-10s\t %-10s\t %-9s\t %-9s\t %-10s\n","姓名" ,"年龄"," 性别"," 地址"," 电话");
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-10s\t %-10d\t %-10s\t %-10s\t %-10s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].addr,
			pc->data[i].tele);
	}

}
void ShowContactone(const contact* pc,int pos)//打印一个人的信息
{
	printf("%-10s\t %-10s\t %-9s\t %-9s\t %-10s\n", "姓名", "年龄", " 性别", " 地址", " 电话");
	
		printf("%-10s\t %-10d\t %-10s\t %-10s\t %-10s\n",
			pc->data[pos].name,
			pc->data[pos].age,
			pc->data[pos].sex,
			pc->data[pos].addr,
			pc->data[pos].tele);
}

//pos为位置信息
//删除某人的信息
void DelContact(contact* pc)//找到删除人的名字然后向前递增一下
{
	printf("请输入要删除的人的名字\n");
	int del = FindByName(pc);
	//然后信息覆盖
	if (del >= 0)
	{
		for (;  del < pc->sz; del++)
		{
			pc->data[del] = pc->data[del + 1];
		}
		pc->sz--;
		printf("删除成功\n");
	}
	else if (del < 0)
	{
		printf("未找到该联系人\n");
	}
}

void SearchContact(contact* pc)
{
	//通过名字寻找联系人信息
	printf("请输入要搜索联系人的姓名\n");
	int pos = FindByName(pc);
	ShowContactone(pc, pos);
}
void ModifyContact(contact* pc)
{
	printf("请输入要修改联系人的姓名\n");
	int pos = FindByName(pc);
	if (-1 == pos)
	{
		printf("未查找到此人\n");
	}
	else //修改某人的信息
	{
		printf("请输入名字\n");
		scanf("%s", pc->data[pos].name);
		printf("请输入年龄\n");
		scanf("%d", &(pc->data[pos].age));
		printf("请输入性别\n");
		scanf("%s", pc->data[pos].sex);
		printf("请输入地址\n");
		scanf("%s", pc->data[pos].addr);
		printf("请输入电话\n");
		scanf("%s", pc->data[pos].tele);
		printf("输入完成\n");
		printf("修改成功,修改信息如下\n");
		ShowContactone(pc, pos);
	}
}
int CompareByName(const void * a, const void * b)
{
	return (((PeoInfo*)a)->name ,((PeoInfo*)b)->name);
}
void SortContact(contact* pc) 
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录没有人\n");
		return;
	}
	qsort(pc->data, pc->sz, sizeof(pc->data[0]),CompareByName);//数组 数组的大小 数组有几个元素,数组元素的大小
	printf("排序完成\n");

}
void DestoryContact(contact* pc)
{
	InitContact(pc);
}

void SaveContact(contact* pc)
{

	assert(pc);
	//打开文件
	FILE* pf = fopen("contact.txt","wb");
	if (NULL == pf)
	{
		perror("SaveContact");
		return;
	}
	else 
	{
		int i = 0;
		for (i = 0; i < pc->sz; i++)
		{
			fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
		}
		fclose(pf);
		pf == NULL;
	}
}


http://www.kler.cn/a/580222.html

相关文章:

  • Linux系统的安全加固与安全防护
  • postgresql json和jsonb问题记录
  • 基于物联网技术的分布式光伏监控系统设计与实现
  • 【STM32】ADC功能-单通道多通道(学习笔记)
  • 面试题之vue和react的异同
  • 机电公司管理信息系统小程序+论文源码调试讲解
  • Electron应用中获取设备唯一ID和系统信息
  • 中国证监会主席吴清:进一步优化差异化安排 更精准支持优质科技企业上市
  • springboot-自定义注解
  • CDefView::_GetPIDL函数分析之ListView_GetItem函数的参数item的item.mask 为LVIF_PARAM
  • React:类组件(中)
  • Redis 发布订阅模式详解:实现高效的消息通信
  • DApp开发全解析:构建去中心化应用的流程与实践指南
  • 无公网IP也能远程控制Windows:Linux rdesktop内网穿透实战
  • 重生之我在学Vue--第6天 Vue 3 状态管理(Pinia)
  • 2025年四川烟草工业计算机岗位备考详细内容
  • CSS 入门指南(一):基本概念 选择器 常用元素属性
  • uniapp+Vue3 开发小程序的下载文件功能
  • 【C++】 —— 笔试刷题day_1
  • thinkphp5对接腾讯云文字识别ocr试卷切题