通讯录小练习:柔性数组和文件操作实现

news2024/11/28 21:38:20

目录

一.程序功能

二.定义关键类型的头文件与枚举的应用

三.封装柔性数组的增容函数与缩容函数

四.添加联系人功能模块

五 .联系人信息打印模块

六. 查找指定联系人的模块

七.删除指定联系人模块

八.修改指定联系人信息模块

九.排序模块

九.文件操作模块

十.通讯录初始化模块

十一.代码总览

contact.h头文件

contactfunction.h头文件

通讯录基本功能模块源文件 

文件操作模块源文件

排序模块源文件: 

主函数测试模块源文件: 


一.程序功能

实现一个通讯录;
通讯录可以用来存储联系人的信息包括:姓名、性别、年龄、电话、住址
提供方法:
1.添加联系人信息
2.删除指定联系人信息
3.查找指定联系人信息
4.修改指定联系人信息
5.显示所有联系人信息
6.清空所有联系人
7.根据姓名 或 性别或 年龄 或 电话 或 住址 排序所有联系人

二.定义关键类型的头文件与枚举的应用

将存储联系人信息的结构体中各成员数组的大小封装为枚举常量,提高代码的可维护性

PeoIfo是存储联系人信息的结构体

listIfo是含有PeoIfo结构体柔性数组的结构体,通过一个listIfo结构体就可以维护整个通讯录列表,listIfo结构体中的Peonum成员用于维护柔性数组Conlist的高地址边界。

由于测试主程序要用到 switch语句,所以这里把菜单选项对应的数字定义为枚举常量来增强代码的可读性

contact .h
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <memory.h>
#include <errno.h>
#include <stdlib.h>


enum listchoice          /*定义一系列枚举常量 代替宏来表示菜单的选项数字*/
{
	Add = 1,
	Del,
	Search,
	Modify,
	show,
	reset,
	sort,
	Exit = 0
};
enum PeoDataSize         /*定义一系列枚举常量 代替宏来表示各个信息的字节数*/
{
	NameSize = 20,
	SexSize = 20,
	AgeSize = 20,
	TelSize = 20,
	AddrSize = 20,
};


typedef struct PeoIfo    //存储联系人信息的结构体
{
	char Name[NameSize];
	char Sex[SexSize];
	char Age[AgeSize];
	char Tel[TelSize];
	char Addr[AddrSize];
}PeoIfo;


typedef struct listIfo 
{
	int Peonum;          //记录联系人个数
	PeoIfo Conlist[];    //使用柔性数组
}listIfo;

 

在主程序中可以通过这样一段代码创建IistIfo结构体, 初始状态下,柔性数组Conlist的元素个数为0,后续柔性数组的大小可以通过realloc进行调整。

主函数测试模块总览:

​
int main()
{
	listIfo* plist = (listIfo*)malloc(sizeof(listIfo)); //创建柔性数组结构体
	if (NULL == plist)
	{
		perror("malloc:");
		return 1;
	}
	plist->Peonum = 0;
	plist=ReadFile(plist);                              //从文件中读取联系人信息


	int input = 0;
	do
	{
		menu();
		if(scanf("%d", &input));                        //选择执行的功能
		switch (input)                               
		{
		case Add:
			plist=ADD(plist);
			break;
		case Del:
			plist=DEL(plist);
			break;
		case Search:
			PrintNum(Search_byname(plist), plist);
			break;
		case Modify:
			MODIF(plist);
			break;
		case show:
			Show(plist);
			break;
		case reset:
			plist = InitList(plist);
			break;
		case sort:
			bubble_sort(plist->Conlist, plist->Peonum, sizeof(PeoIfo), sort_choice());
			break;
		case Exit:
			Writefile(plist);            //销毁通讯录前先将联系人信息保存到文件中
			free(plist);                 //退出程序销毁结构体
			plist = NULL;
			break;
		default:
			printf(" invalue input,please retry\n");
			break;
		}
	} while (input);

	return 0;
}

​

三.封装柔性数组的增容函数与缩容函数

由于增容和缩容的功能在很多地方都可能会被使用,因此将它们封装成函数是十分有必要的,可以很大程度上提高代码的简洁性和可维护性。

listIfo* IncreSize (listIfo*ListInfo)     //扩容函数
{
	listIfo* tem = (listIfo *)realloc(ListInfo, (sizeof(listIfo) + sizeof(PeoIfo)*(size_t)((ListInfo->Peonum)+1)));
	if (tem == NULL)                      //空间调整失败则返回原指针
	{
		perror("reallocInc:");
		return ListInfo;
	}
	return tem;
}
listIfo* DecreSize(listIfo* ListInfo)     //缩容函数
{
	if (ListInfo->Peonum == 0)
	{
		return ListInfo;
	}
	listIfo* tem = (listIfo*)realloc(ListInfo, (sizeof(listIfo) + sizeof(PeoIfo) * ListInfo->Peonum-1));
	if (tem == NULL)                      //空间调整失败则返回原指针
	{
		perror("reallocInc:");
		return ListInfo;
	}
	return tem;
}

使用realloc函数注意判断空间动态调整是否成功

两个函数都要返回新调整后的空间的地址

四.添加联系人功能模块

listIfo* ADD(listIfo* ListInfo)
{
	ListInfo = IncreSize(ListInfo);       调用增容函数使柔性数组增加一个元素
	memset((ListInfo->Conlist) + (ListInfo->Peonum), 0, sizeof(PeoIfo));
	int ret = 0;
	printf("请输入姓名:>");
	ret = scanf("%s", (ListInfo->Conlist[ListInfo->Peonum]).Name);
	printf("请输入性别:>");
	ret = scanf("%s", (ListInfo->Conlist[ListInfo->Peonum]).Sex);
	printf("请输入年龄:>");
    ret = scanf("%s", (ListInfo->Conlist[ListInfo->Peonum]).Age);
	printf("请输入电话:>");
    ret = scanf("%s", (ListInfo->Conlist[ListInfo->Peonum]).Tel);
	printf("请输入地址:>");
	ret = scanf("%s", (ListInfo->Conlist[ListInfo->Peonum]).Addr);
	ListInfo->Peonum++;                   联系人信息填完后记得令人数自增
	printf("ADD success\n");
	return ListInfo;
}

五 .联系人信息打印模块

void Show(listIfo* ListInfo)
{
	int i = 0;
	printf("%-10s  %-4s  %-3s %-10s %-10s \n", "姓名", "性别", "年龄", "电话", "地址");
	for (i = 0; i < ListInfo->Peonum; i++)
	{
		printf("%-10s  ", ListInfo->Conlist[i].Name);
		printf("%-4s  ", ListInfo->Conlist[i].Sex);
		printf("%-3s  ", ListInfo->Conlist[i].Age);
		printf("%-10s ", ListInfo->Conlist[i].Tel);
		printf("%-10s ", ListInfo->Conlist[i].Addr);
		printf("\n");
	}
}

六. 查找指定联系人的模块

int Search_byname(listIfo* ListIfo)
{
    int i = 0;
    char name[NameSize] = { 0 };
    printf("输入联系人姓名:>");
    int ret=scanf("%s", name);
    for (i = 0; i < ListIfo->Peonum; i++)
    {
        if (strcmp(name, ListIfo->Conlist[i].Name) == 0)
        {
            return i;
        }
    }
    printf("联系人不存在\n");
    return -1;
}

Search_byname函数返回柔性数组对应元素的下标

Search_byname函数同样在很多其他模块可能被调用

打印单个联系人信息的函数

void PrintNum(int i, listIfo* ListIfo)
{
	printf("%-10s  ", ListIfo->Conlist[i].Name);
	printf("%-4s  ", ListIfo->Conlist[i].Sex);
	printf("%-3s  ", ListIfo->Conlist[i].Age);
	printf("%-10s ", ListIfo->Conlist[i].Tel);
	printf("%-10s ", ListIfo->Conlist[i].Addr);
	printf("\n");
}

Search_byname 和 PrintNum函数一起使用可以完成查找指定联系人信息的功能

七.删除指定联系人模块

listIfo* DEL(listIfo* ListIfo)
{
	int ret = Search_byname(ListIfo);
	if (ret != -1)
	{
		memmove((ListIfo->Conlist) + ret, (ListIfo->Conlist) + ret + 1,
			sizeof(PeoIfo) * (long long)((ListIfo->Peonum) - ret - 1));
		
		ListIfo = DecreSize(ListIfo);   //调用缩容函数
		ListIfo->Peonum--;
		printf("DELATE success\n");
	}
	return ListIfo;
}

八.修改指定联系人信息模块

void MODIF(listIfo* ListIfo)
{
	int ret = Search_byname(ListIfo);     调用查找函数
	if (ret != -1)
	{
		printf("请输入姓名:>");
		int i=scanf("%s", (ListIfo->Conlist[ret]).Name);
		printf("请输入性别:>");
		i = scanf("%s", (ListIfo->Conlist[ret]).Sex);
		printf("请输入年龄:>");
		i = scanf("%s", (ListIfo->Conlist[ret]).Age);
		printf("请输入电话:>");
		i = scanf("%s", (ListIfo->Conlist[ret]).Tel);
		printf("请输入地址:>");
		i = scanf("%s", (ListIfo->Conlist[ret]).Addr);
		printf("modify success\n");
	}
}

九.排序模块

排序模块函数比较多,因此单独为其创建了一个源文件。 

这里我们使用模拟qsort的冒泡排序函数来实现通讯录排序功能。

首先是一系列比较函数:

int cmpbyname(void* e1, void* e2)
{
	return strcmp(((PeoIfo*)e1)->Name, ((PeoIfo*)e2)->Name);
}
int cmpbysex(void* e1, void* e2)
{
	return strcmp(((PeoIfo*)e1)->Sex, ((PeoIfo*)e2)->Sex);
}
int cmpbyage(void* e1, void* e2)
{
	return strcmp(((PeoIfo*)e1)->Age, ((PeoIfo*)e2)->Age);
}
int cmpbytel(void* e1, void* e2)
{
	return strcmp(((PeoIfo*)e1)->Tel, ((PeoIfo*)e2)->Tel);
}
int cmpbyaddr(void* e1, void* e2)
{
	return strcmp(((PeoIfo*)e1)->Addr, ((PeoIfo*)e2)->Addr);
}

然后设计一个函数可以让用户自行选择根据何种信息排序,该函数的返回值是一个函数指针类型为:int (*)(void * , void *),为了代码的简洁性,我们使用函数指针数组构建转移表

#define ChoiceNum 5
static void sortmenu(void)
{
	printf("***********************************\n");
	printf("*****       1.sort by name     ****\n");
	printf("*****       2.sort by sex      ****\n");
	printf("*****       3.sort by Age      ****\n");
	printf("*****       4.sort by Tel      ****\n");
	printf("*****       5.sort by addr     ****\n");
	printf("***********************************\n");
}
int (*sort_choice(void))(void*, void*)
{
	int input = 0;
	int (*Funarr[ChoiceNum])(void*, void*) = { cmpbyname,
                                               cmpbysex,
                                               cmpbyage,
                                               cmpbytel,
                                               cmpbyaddr };  转移表
	
    sortmenu();
	int ret = scanf("%d", &input);
	while (input<0 || input >ChoiceNum - 1)
	{
		printf("invalued input,please retry\n");
		sortmenu();
	}
	return *(Funarr+input - 1);                返回对应的比较函数
}

多功能bubble_sort模块

static void swap(void* e1, void* e2,int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tem = *((char*)e1 + i);
		*((char*)e1 + i) = *((char*)e2 + i);
		*((char*)e2 + i) = tem;
	}
}

void* bubble_sort(void* base, long long num, int width, int(*cmp)(void*, void*))
{
	int i = 0;
	long long j = 0;
	int flag = 0;
	for (i = 0; i < num-1; i++)
	{
		flag = 1;
		for (j = 0; j < num - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				flag = 0;
				swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
			}
		}
		if (flag)
		{
			break;
		}
	}
	printf("sorted success\n");
	return base;
}

在主函数中以如下形式调用bubble_sort便可完成根据任意联系人信息进行排序的功能

bubble_sort(plist->Conlist, plist->Peonum, sizeof(PeoIfo), sort_choice());

九.文件操作模块

运行程序并创建了含柔性数组成员的结构体后,需要将文件中的联系人信息读入柔性数组中。我们采用二进制读写来完成通讯录的文件操作。

文件读取模块:

listIfo* ReadFile(listIfo* ListIfo)
{
	FILE* pfile = fopen("text.txt", "rb");     打开文件并检验是否发生错误
	if (NULL == pfile) 
	{
		perror("fopen:");
		return ListIfo;
	}

	ListIfo = IncreSize(ListIfo);              读取文件前先为0个元素的柔性数组增容
	while (fread(((ListIfo->Conlist) + (ListIfo->Peonum)), sizeof(PeoIfo), 1, pfile))
	{
		ListIfo->Peonum++;
		ListIfo = IncreSize(ListIfo);          每读取一个联系人增容一次
	}
	if (ferror(pfile))                         检验读取是否成功
	{
		printf("reading error occurred\n");
	}
	else if (feof(pfile))
	{
		printf("readfile success\n");
	}
	fclose(pfile);
	pfile = NULL;
	return ListIfo;                            关闭文件并 返回调整后的柔性数组结构体的地址
}

 

程序结束前需要将柔性数组中存储的信息以二进制数据的形式写入文件中。

文件写入模块:

void Writefile(listIfo* ListIfo)
{
	FILE* pfile = fopen("text.txt", "wb");
	if (NULL == pfile)
	{
		perror("fopen:");
		return ;
	}
	int i = 0;
	for (i = 0; i < ListIfo->Peonum; i++)      将每个联系人信息写入文件中
	{
		if (!fwrite(((ListIfo->Conlist) + i), sizeof(PeoIfo), 1, pfile))
		{
			perror("fwrite:");
			return;
		}
	}
	printf("contact successfully saved\n");
	fclose(pfile);
	pfile = NULL;
	return;
}

十.通讯录初始化模块

listIfo * InitList(listIfo* ListIfo)
{
	listIfo* tem = NULL;
	tem = (listIfo*)realloc(ListIfo, sizeof(listIfo)); 将柔性数组调整为0个元素
	if (tem == NULL)
	{
		perror("realloc and init failed:");
		return ListIfo;
	}
	tem->Peonum = 0;
	printf("Init success\n");
	return tem;
}

十一.代码总览

contact.h头文件

#pragma once
//contact .h
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <memory.h>
#include <errno.h>
#include <stdlib.h>


enum listchoice          /*定义一系列枚举常量 代替宏来表示菜单的选项数字*/
{
	Add = 1,
	Del,
	Search,
	Modify,
	show,
	reset,
	sort,
	Exit = 0
};
enum PeoDataSize         /*定义一系列枚举常量 代替宏来表示各个信息的字节数*/
{
	NameSize = 20,
	SexSize = 20,
	AgeSize = 20,
	TelSize = 20,
	AddrSize = 20,
};


typedef struct PeoIfo    //存储联系人信息的结构体
{
	char Name[NameSize];
	char Sex[SexSize];
	char Age[AgeSize];
	char Tel[TelSize];
	char Addr[AddrSize];
}PeoIfo;


typedef struct listIfo 
{
	int Peonum;          //存储的联系人数
	PeoIfo Conlist[];    //使用柔性数组
}listIfo;

contactfunction.h头文件

#include "contact.h"
#pragma once
void menu(void);
listIfo* ADD(listIfo* ListInfo);
void Show(listIfo* ListIfo);
listIfo* InitList(listIfo* ListIfo);
int Search_byname(listIfo* ListIfo);
void PrintNum(int i, listIfo* ListIfo);
listIfo* DEL(listIfo* ListIfo);
void MODIF(listIfo* ListIfo);
void* bubble_sort(void* base, long long num, int width, int(*cmp)(void*, void*));
listIfo* DecreSize(listIfo* ListInfo);
listIfo* IncreSize(listIfo* ListInfo);
int (*sort_choice(void))(void*, void*);
listIfo* ReadFile(listIfo* ListIfo);
void Writefile(listIfo* ListIfo);

通讯录基本功能模块源文件 

#include  "contact.h"
#include  "contactfunction.h"

//封装菜单函数
void menu(void)
{
	printf("*********************************\n");
	printf("******   1.Add contact      *****\n");
	printf("******                      *****\n");
	printf("******   2.del contact      *****\n");
	printf("******                      *****\n");
	printf("******   3.search contact   *****\n");
	printf("******                      *****\n");
	printf("******   4.modify contact   *****\n");
	printf("******                      *****\n");
	printf("******   5.show list        *****\n");
	printf("******                      *****\n");
	printf("******   6.reset list       *****\n");
	printf("******                      *****\n");
	printf("******   7.sort             *****\n");
	printf("******                      *****\n");
	printf("******   0.exit             *****\n");
	printf("*********************************\n");
	printf("---------please choose-----------\n");
}

listIfo* IncreSize (listIfo*ListInfo)     //扩容函数
{
	listIfo* tem = (listIfo *)realloc(ListInfo, (sizeof(listIfo) + sizeof(PeoIfo)*(size_t)((ListInfo->Peonum)+1)));
	if (tem == NULL)                      //空间调整失败则返回原指针
	{
		perror("reallocInc:");
		return ListInfo;
	}
	return tem;
}
listIfo* DecreSize(listIfo* ListInfo)     //缩容函数
{
	if (ListInfo->Peonum == 0)
	{
		return ListInfo;
	}
	listIfo* tem = (listIfo*)realloc(ListInfo, (sizeof(listIfo) + sizeof(PeoIfo) * ListInfo->Peonum-1));
	if (tem == NULL)                      //空间调整失败则返回原指针
	{
		perror("reallocInc:");
		return ListInfo;
	}
	return tem;
}
//void InitListNUM(listIfo* ListIfo)
//{
//	memset((ListIfo->Conlist)+(ListIfo->Peonum), 0, sizeof(PeoIfo));
//	memset(ListIfo->Conlist[ListIfo->Peonum].Sex, 0, SexSize);
//	memset(ListIfo->Conlist[ListIfo->Peonum].Age, 0, AgeSize);
//	memset(ListIfo->Conlist[ListIfo->Peonum].Tel, 0, TelSize);
//	memset(ListIfo->Conlist[ListIfo->Peonum].Addr, 0, AddrSize);
//}


listIfo* ADD(listIfo* ListInfo)
{
	ListInfo = IncreSize(ListInfo);
	memset((ListInfo->Conlist) + (ListInfo->Peonum), 0, sizeof(PeoIfo));
	int ret = 0;
	printf("请输入姓名:>");
	ret = scanf("%s", (ListInfo->Conlist[ListInfo->Peonum]).Name);
	printf("请输入性别:>");
	ret = scanf("%s", (ListInfo->Conlist[ListInfo->Peonum]).Sex);
	printf("请输入年龄:>");
    ret = scanf("%s", (ListInfo->Conlist[ListInfo->Peonum]).Age);
	printf("请输入电话:>");
    ret = scanf("%s", (ListInfo->Conlist[ListInfo->Peonum]).Tel);
	printf("请输入地址:>");
	ret = scanf("%s", (ListInfo->Conlist[ListInfo->Peonum]).Addr);
	ListInfo->Peonum++;
	printf("ADD success\n");
	return ListInfo;
}
listIfo * InitList(listIfo* ListIfo)
{
	listIfo* tem = NULL;
	tem = (listIfo*)realloc(ListIfo, sizeof(listIfo));
	if (tem == NULL)
	{
		perror("realloc and init failed:");
		return ListIfo;
	}
	tem->Peonum = 0;
	printf("Init success\n");
	return tem;
}

void Show(listIfo* ListInfo)
{
	int i = 0;
	printf("%-10s  %-4s  %-3s %-10s %-10s \n", "姓名", "性别", "年龄", "电话", "地址");
	for (i = 0; i < ListInfo->Peonum; i++)
	{
		printf("%-10s  ", ListInfo->Conlist[i].Name);
		printf("%-4s  ", ListInfo->Conlist[i].Sex);
		printf("%-3s  ", ListInfo->Conlist[i].Age);
		printf("%-10s ", ListInfo->Conlist[i].Tel);
		printf("%-10s ", ListInfo->Conlist[i].Addr);
		printf("\n");
	}
}



int Search_byname(listIfo* ListIfo)
{
	int i = 0;
	char name[NameSize] = { 0 };
	printf("输入联系人姓名:>");
	int ret=scanf("%s", name);
	for (i = 0; i < ListIfo->Peonum; i++)
	{
		if (strcmp(name, ListIfo->Conlist[i].Name) == 0)
		{
			return i;
		}
	}
	printf("联系人不存在\n");
	return -1;
}

void PrintNum(int i, listIfo* ListIfo)
{
	printf("%-10s  ", ListIfo->Conlist[i].Name);
	printf("%-4s  ", ListIfo->Conlist[i].Sex);
	printf("%-3s  ", ListIfo->Conlist[i].Age);
	printf("%-10s ", ListIfo->Conlist[i].Tel);
	printf("%-10s ", ListIfo->Conlist[i].Addr);
	printf("\n");
}

listIfo* DEL(listIfo* ListIfo)
{
	int ret = Search_byname(ListIfo);
	if (ret != -1)
	{
		memmove((ListIfo->Conlist) + ret, (ListIfo->Conlist) + ret + 1,
			sizeof(PeoIfo) * (long long)((ListIfo->Peonum) - ret - 1));
		
		ListIfo = DecreSize(ListIfo);   //调用缩容函数
		ListIfo->Peonum--;
		printf("DELATE success\n");
	}
	return ListIfo;
}


void MODIF(listIfo* ListIfo)
{
	int ret = Search_byname(ListIfo);
	if (ret != -1)
	{
		printf("请输入姓名:>");
		int i=scanf("%s", (ListIfo->Conlist[ret]).Name);
		printf("请输入性别:>");
		i = scanf("%s", (ListIfo->Conlist[ret]).Sex);
		printf("请输入年龄:>");
		i = scanf("%s", (ListIfo->Conlist[ret]).Age);
		printf("请输入电话:>");
		i = scanf("%s", (ListIfo->Conlist[ret]).Tel);
		printf("请输入地址:>");
		i = scanf("%s", (ListIfo->Conlist[ret]).Addr);
		printf("modify success\n");
	}
}

文件操作模块源文件

#include "contactfunction.h"
#include "contact.h"

//文件的读写我们采用二进制读写

listIfo* ReadFile(listIfo* ListIfo)
{
	FILE* pfile = fopen("text.txt", "rb");
	if (NULL == pfile)
	{
		perror("fopen:");
		return ListIfo;
	}

	ListIfo = IncreSize(ListIfo);
	while (fread(((ListIfo->Conlist) + (ListIfo->Peonum)), sizeof(PeoIfo), 1, pfile))
	{
		ListIfo->Peonum++;
		ListIfo = IncreSize(ListIfo);
	}
	if (ferror(pfile))
	{
		printf("reading error occurred\n");
	}
	else if (feof(pfile))
	{
		printf("readfile success\n");
	}
	fclose(pfile);
	pfile = NULL;
	return ListIfo;
}

void Writefile(listIfo* ListIfo)
{
	FILE* pfile = fopen("text.txt", "wb");
	if (NULL == pfile)
	{
		perror("fopen:");
		return ;
	}
	int i = 0;
	for (i = 0; i < ListIfo->Peonum; i++)
	{
		if (!fwrite(((ListIfo->Conlist) + i), sizeof(PeoIfo), 1, pfile))
		{
			perror("fwrite:");
			return;
		}
	}
	printf("contact successfully saved\n");
	fclose(pfile);
	pfile = NULL;
	return;
}

排序模块源文件: 

#include "contact.h"
#include "contactfunction.h"
#define ChoiceNum 5


static void sortmenu(void)
{
	printf("***********************************\n");
	printf("*****       1.sort by name     ****\n");
	printf("*****       2.sort by sex      ****\n");
	printf("*****       3.sort by Age      ****\n");
	printf("*****       4.sort by Tel      ****\n");
	printf("*****       5.sort by addr     ****\n");
	printf("***********************************\n");
}


int cmpbyname(void* e1, void* e2)
{
	return strcmp(((PeoIfo*)e1)->Name, ((PeoIfo*)e2)->Name);
}
int cmpbysex(void* e1, void* e2)
{
	return strcmp(((PeoIfo*)e1)->Sex, ((PeoIfo*)e2)->Sex);
}
int cmpbyage(void* e1, void* e2)
{
	return strcmp(((PeoIfo*)e1)->Age, ((PeoIfo*)e2)->Age);
}
int cmpbytel(void* e1, void* e2)
{
	return strcmp(((PeoIfo*)e1)->Tel, ((PeoIfo*)e2)->Tel);
}
int cmpbyaddr(void* e1, void* e2)
{
	return strcmp(((PeoIfo*)e1)->Addr, ((PeoIfo*)e2)->Addr);
}


int (*sort_choice(void))(void*, void*)
{
	int input = 0;
	int (*Funarr[ChoiceNum])(void*, void*) = { cmpbyname ,cmpbysex,cmpbyage,cmpbytel,cmpbyaddr };
	sortmenu();
	int ret = scanf("%d", &input);
	while (input<0 || input >ChoiceNum - 1)
	{
		printf("invalued input,please retry\n");
		sortmenu();
	}
	return *(Funarr+input - 1);
}


static void swap(void* e1, void* e2,int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tem = *((char*)e1 + i);
		*((char*)e1 + i) = *((char*)e2 + i);
		*((char*)e2 + i) = tem;
	}
}

void* bubble_sort(void* base, long long num, int width, int(*cmp)(void*, void*))
{
	int i = 0;
	long long j = 0;
	int flag = 0;
	for (i = 0; i < num-1; i++)
	{
		flag = 1;
		for (j = 0; j < num - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				flag = 0;
				swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
			}
		}
		if (flag)
		{
			break;
		}
	}
	printf("sorted success\n");
	return base;
}

主函数测试模块源文件: 

#include "contact.h"
#include "contactfunction.h"


int main()
{
	listIfo* plist = (listIfo*)malloc(sizeof(listIfo)); //创建柔性数组结构体
	if (NULL == plist)
	{
		perror("malloc:");
		return 1;
	}
	plist->Peonum = 0;
	plist=ReadFile(plist);


	int input = 0;
	do
	{
		menu();
		if(scanf("%d", &input));
		switch (input)
		{
		case Add:
			plist=ADD(plist);
			break;
		case Del:
			plist=DEL(plist);
			break;
		case Search:
			PrintNum(Search_byname(plist), plist);
			break;
		case Modify:
			MODIF(plist);
			break;
		case show:
			Show(plist);
			break;
		case reset:
			plist = InitList(plist);
			break;
		case sort:
			bubble_sort(plist->Conlist, plist->Peonum, sizeof(PeoIfo), sort_choice());
			break;
		case Exit:
			Writefile(plist);
			free(plist);                 //退出程序销毁结构体
			plist = NULL;
			break;
		default:
			printf(" invalue input,please retry\n");
			break;
		}
	} while (input);

	return 0;
}

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/166389.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何实现外网远程登录访问jupyter notebook?

Jupyter Notebook是一个交互式笔记本&#xff0c;本质是一个 Web 应用程序&#xff0c;支持运行 40 多种编程语言&#xff0c;此前被称为 IPython notebook。Jupyter Notebook 便于创建和共享程序文档、支持实时代码、数学方程、可视化和 markdown&#xff0c;应用场景有数据清…

机器学习基础——k-近邻算法概述和简单实现

本章内容 k-近邻分类算法 从文本文件中解析数据 前言 众所周知&#xff0c;电影可以按照题材分类&#xff0c;然而题材本身是如何定义的?由谁来判定某部电影属于哪个题材?也就是说同一题材的电影具有哪些公共特征?这些都是在进行电影分类时必须要考虑的问题。没有哪个电影人…

Revit问题:降板表面填充图案和构件上色

一、Revit中如何为降板表面填充不同的图案 在平面图中该如何利用填充图案来区别降板跟楼板&#xff1f; 1、中间的楼板为降板(120)/-150mm,下面我们通过“过滤器”来为其填充表面图案。 2、通过快捷键VV打开“可见性/图形替换”对话框&#xff0c;单击选择“过滤器”一项。 3、…

2023/1 寒假期间自学c++计划安排

寒假一期学习总结 寒假一期学习是在线下进行的&#xff0c;总的来说&#xff0c;非常充实&#xff0c;也很有收获&#xff0c;成体系的学习了 二分&#xff0c;高精度&#xff0c;函数&#xff0c;结构体&#xff0c;STL 等等内容&#xff0c;既开心有学到了知识。 在这7天的集…

最新ios证书申请流程

苹果官方申请ios证书的方法&#xff0c;需要mac电脑&#xff0c;需要使用钥匙串管理先生成csr文件&#xff0c;然后去苹果开发者中心生成证书&#xff0c;然后再用mac电脑导出p12证书。假如我们没有mac电脑&#xff0c;又如何申请证书呢&#xff1f;这个教程我将教会大家如何使…

从汇编的角度了解C++原理——类的储存结构和函数调用

本文用到的反汇编工具是objconv&#xff0c;使用方法可以看我另一篇文章https://blog.csdn.net/weixin_45001971/article/details/128660642。 1、类的储存结构和函数调用 以这段代码为例。 编译后对obj文件反汇编&#xff0c;得到以下汇编代码&#xff0c;配合常量的值来分…

大数据技术架构(组件)——Hive:环境准备2

1.0.1.5、Mysql安装1.0.1.5.1、软件包下载解压缩官网或者直接从百度云盘中下载即可。https://dev.mysql.com/downloads/mysql/1.0.1.5.2、环境变量配置1.0.1.5.2.1、创建系统环境变量MYSQL_HOME1.0.1.5.2.2、将系统环境变量配置到Path上1.0.1.5.2.3、生成Data文件使用系统管理员…

【MySQL进阶教程】MySQL管理

前言 本文为 【MySQL进阶教程】MySQL管理 相关知识&#xff0c;下边将对系统数据库&#xff0c;常用工具&#xff08;包括&#xff1a;mysql、mysqladmin、mysqlbinlog、mysqlshow、mysqldump、mysqlimport/source&#xff09;等进行详尽介绍~ &#x1f4cc;博主主页&#xff…

开发微信小程序过程中遇到的问题笔记

时间绑定bindtap的基础用法 <view id"tapTest" data-hi"WeChat" bindtap"tapName"> Click me! </view>这里要注意的是data-xxx中的xxx需要小写&#xff0c;否则获取不到。 使用for循环的时候&#xff0c;这种方法是拿不到数据的。 …

系统分析师案例必备知识点汇总---2023系列文章三

系统设计 1、面向对象设计 分析类图是从用户的角度出发得到的业务“系统”&#xff0c;而设计类图更多的是从系统、软件的角 度来描述和表达系统。二者具体的区别&#xff1a; 分析类图&#xff1a;在需求分析阶段&#xff0c;类图是研究领域中的概念&#xff1b;分析类图主要…

C语言实现密码检查

这道题目并不算难&#xff0c;实现时可能会写出一些bug&#xff0c;需要耐心去调试。有两种方法&#xff0c;首先这些题目要求可以频繁使用字符串的库函数&#xff0c;这里不介绍这些库函数&#xff0c;我的方法是直接比较阿斯克码值的大小进行删选&#xff0c;频繁使用if语句。…

模板的补充

1. 非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中可将该参数当成…

【ElasticSearch01】ElasticSearch入门

目录1.数据类型2.Elasticsearch是什么3.全文搜索引擎4.Elasticsearch安装5.Restful和JSON6.Postman客户端工具7.倒排索引8.Elasticsearch基本操作8.1 索引操作8.1.1 创建索引8.1.2查询索引1.查询指定索引2.查询所有索引8.1.3删除索引8.2 文档操作8.2.1 创建文档8.2.2 创建文档时…

力扣 2287. 重排字符形成目标字符串

题目 给你两个下标从 0 开始的字符串 s 和 target 。你可以从 s 取出一些字符并将其重排&#xff0c;得到若干新的字符串。 从 s 中取出字符并重新排列&#xff0c;返回可以形成 target 的 最大 副本数。 示例 输入&#xff1a;s “ilovecodingonleetcode”, target “co…

人工智能入门基础概念—教你正确打开人工智能世界的大门

一、机器学习 1.1机器学习概述 机器学习简介 机器学习&#xff0c;通俗地讲就是让机器拥有学习的能力&#xff0c;从而改善系统自身的性能。 这里的“学习”指的是从数据中学习&#xff0c;从数据中产生模型的算法&#xff0c;即学习算法。有了学习算法&#xff0c;只要把经验…

力扣(131.93)补9.21

131.分割回文串 又是不会做的一题呢。 代码看起来不难&#xff0c;但想出代码还是很难得。 class Solution { public List<List<String>> partition(String s) { List<List<String>> ansnew ArrayList<>(); List<String> listnew ArrayLis…

Python学习笔记-PyQt6对话框

对话框是界面编程中重要的窗体&#xff0c;一般用于提示或者一些其他特定操作。一、使用QDialog显示通用消息框直接使用QDialog类&#xff0c;可以及通过对话框进行通用对话框显示&#xff0c;亦可以通过自定义设置自己需要的对话框。# _*_ coding:utf-8 _*_import sysfrom PyQ…

自动驾驶专题介绍 ———— 超声波雷达

文章目录介绍工作原理特点常见参数介绍 在汽车碰撞事故中&#xff0c;有大约15%的事故是因为倒车时汽车的后视能力不足引起的&#xff0c;因为增加汽车的后视能力的超声波雷达的研究成为了当下的热点之一。安全避免碰撞的前提是快速准确的测量障碍物于汽车之间的距离。超声波雷…

小白必看!用JMeter+ANT进行接口自动化测试,并生成HTML测试报告

小伙伴们&#xff0c;用python做接口自动化是不是写代码比较繁琐&#xff0c;而且没有python代码基础的小伙伴根本无从下手对吧&#xff01;今天我们来学习一下如何使用JMeter工具实现接口自动化测试。 01 安装 1、安装JDK&#xff0c;配置java环境变量&#xff08;安装过程略…

Win11玩不了红警怎么办?Win11玩不了红警解决方法分享

Win11玩不了红警怎么办&#xff1f;红警是非常耐玩的一款电脑游戏&#xff0c;有用户在电脑上安装这款游戏的时候&#xff0c;发现游戏无法正常的运行&#xff0c;那么这个情况是什么原因导致的呢&#xff1f;接下来我们就一起来看看Win11玩不了红警解决方法分享吧。 Win11玩不…