C语言之通讯录的实现(静态版,动态版,文件版)

个人主页(找往期文章包括但不限于本期文章中不懂的知识点): 我要学编程(ಥ_ಥ)-CSDN博客

目录

静态通讯录的实现逻辑 

test.c:通讯录的逻辑实现

Contact.h:函数的声明与头文件的包含

Contact.c:函数的实现 

通讯录源码: 

test.c:

Contact.c:

Contect.h:

动态版通讯录 

test.c:

Contact.h:

Contact.c: 

动态通讯录(文件版)

test.c: 

Contact.h: 

Contact.c: 


静态通讯录的实现逻辑 

test.c:通讯录的逻辑实现

我们今天就一起来用c语言写一个通讯录的小程序。

这个通讯录可以实现存储100个联系人。

首先,我们进去这个通讯录,肯定得有一些基本的功能。如下图:

这个就和我们在前面写游戏的时候是一样的。

void menu()
{
	printf("******************************************\n");
	printf("****  1.增加联系人      2.删除联系人  ****\n");
	printf("****  3.查找联系人      4.修改联系人  ****\n");
	printf("****  5.显示联系人     6.排序联系人   ****\n");
	printf("****           0.退出通讯录           ****\n");
	printf("******************************************\n");
}

打印出界面之后,我们就得根据需求来进行选择。

void test()
{
	int input = 0;
	//下面是对通讯录进行的各种操作,所以我们得先有一个通讯录
    //创建一个通讯录,包含一个人的各种信息,是一个复杂对象,用结构体来描述
	Contact con;
	InitContact(&con);//初始化通讯录
	do
	{
		menu();//打印基本功能
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			AddContact(&con);//增加联系人的信息
			break;
		case 2:
			DelContact(&con);//删除联系人的信息
			break;
		case 3:
			SearchContact(&con);//查找联系人的信息
			break;
		case 4:
			ModifyContact(&con);//修改联系人的信息
			break;
		case 5:
			ShowContact(&con);//显示联系人的信息
			break;
		case 6:
			SortContact(&con);//排序联系人
			break;
		case 0:
            printf("退出通讯录\n");
			break;
		default:
            printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);

}

为了让别人能够更清楚我们代码的功能,我们最好能把那些case后面的数字,改成ADD这些能够让别人一下就能够看懂。我们就可以联想到联合体。自定义类型:联合和枚举-CSDN博客

上面这篇博客,有关于联合体的知识。

void test()
{
	int input = 0;
	//下面是对通讯录进行的各种操作,所以我们得先有一个通讯录
	Contact con;
	InitContact(&con);
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&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:
            printf("退出通讯录\n");
			break;
		default:
            printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);

}

可以把test函数在main函数里调用。

#include "Contact.h"
int main()
{
	test();
	return 0;
}

写完这些基本的功能之后,就可以开始实现这些编辑通讯录的函数了。上面这些都是放在test.c函数(实现通讯录的基本逻辑)。

Contact.h:函数的声明与头文件的包含

这些函数的声明和头文件的声明,我们都可以放在一个Contact.h的头文件中。 

头文件的声明:

//头文件的声明
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>

联合体的创建: 

//把选项一 一列举出来
enum OPPION
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};

通讯录准备: 

//为后期增加联系人做准备
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30


//类型的声明
typedef struct people
{
	char name[MAX_NAME];//姓名
	int age;//年龄
	char sex[MAX_SEX];//性别
	//电话(我们正常的电话是11位,超过了int的范围,所以用字符串比较合适)
	char tele[MAX_TELE];
	char addr[MAX_ADDR];//住址
}people;


//通讯录的创建
typedef struct Contact
{
	people data[MAX];
	int sz;//记录当前通讯录的人数
}Contact;

函数的声明:

//初始化通讯录的函数的声明
void InitContact(Contact* pc);


//增加联系人信息的函数的声明
void AddContact(Contact* pc);


//显示联系人的信息的函数的声明
void ShowContact(const Contact* pc);


//删除联系人信息的函数的声明
void DelContact(Contact* pc);


//查找指定联系人信息的函数的声明
void SearchContact(const Contact* pc);


//修改指定联系人的信息
void ModifyContact(Contact* pc);

//排序联系人
void SortContact(const Contact* pc);

Contact.c:函数的实现 

初始化通讯录函数: 

#include "Contact.h"//声明头文件

//初始化通讯录的函数
void InitContact(Contact* pc)
{
	assert(pc);
    //把pc->data的空间全部初始化为0
	memset(pc->data, 0, sizeof(pc->data));//循环也可以,但是太麻烦。
	pc->sz = 0;
}

增加联系人信息的函数: 

//增加联系人信息的函数
void AddContact(Contact* pc)
{
	assert(pc);
    //首先得判断这个通讯录是否已经满了
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法增加\n");
		//通讯录满了,就无需执行下面的语句了
		return;//因为是void。所以无需返回任何值
	}
	else
	{
		printf("请输入姓名:");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入年龄:");
		scanf("%d", &(pc->data[pc->sz].age));//age是int类型
		printf("请输入性别:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入住址:");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("成功增加联系人\n");
	}
}

显示联系人的信息的函数: 

//显示联系人的信息的函数
void ShowContact(const Contact* pc)
{
	assert(pc);
    //要有一定的排版(采用左对齐)
	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

 删除联系人信息的函数的声明:

//删除联系人信息的函数的声明
void DelContact(Contact* pc)
{
	assert(pc);
    //判断是否能删除
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
    //创建一个name数组来存放我们要寻找的联系人
	char name[MAX_NAME] = { 0 };
	//知道要删除谁
	printf("请输入要删除的人的名字:");
	scanf("%s", name);

	//找到要删除的人(字符串)
	int del = 0;
	int flag = 0;
    //遍历数组,一个一个的比较字符串
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			del = i;//记录当前的位置
			flag = 1;
	    	break;
		}
	}
	//开始删除(删除的方法就是把后面一个往前覆盖)
	if (flag == 0)
	{
		printf("要删除的联系人不存在\n");
		return;//后面的代码无需执行
	}
	else
	{
	    for (int i = del; i < pc->sz - 1; i++)
		{
			pc->data[i] = pc->data[i + 1];
		}
	}
	//删除最后一个元素时,虽然不能在循环中删除,但是pc->sz--了,致使访问不到最后一个元素了
	//因此,我们在打印时也不会打印出来

	pc->sz--;
	printf("删除成功\n");
}

其实我们会发现在这里寻找名字的时候,在后面查找联系人也会用到,不如我们直接分装成一个寻找名字的函数。

//查找联系人名字的函数
//这个函数我们只想在内部使用,没必要暴露给别人
static int FindByName(const Contact* pc, char name[])
{
	assert(pc);
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

那么上面的删除函数就可以改造成:

//删除联系人信息的函数的声明
void DelContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	char name[MAX_NAME] = { 0 };
	//知道要删除谁
	printf("请输入要删除的人的名字:");
	scanf("%s", name);
    //找到要删除的人(字符串)
	int del = FindByName(pc, name);
	if (del == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	for (int i = del; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	//删除最后一个元素时,虽然不能在循环中删除,但是pc->sz--了,致使访问不到最后一个元素了
	//因此,我们在打印时也不会打印出来
	pc->sz--;
	printf("删除成功\n");
}

查找指定联系人信息的函数: 

//查找指定联系人信息的函数
void SearchContact(const Contact* pc)
{
	assert(pc);
    //存放名字的数组
	char name[MAX_NAME];
	printf("请输入要查找的联系人:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}

修改指定联系人的信息: 

void menu1()
{
	printf("*******************************\n");
	printf("****  1.姓名     2.年龄    ****\n");
	printf("****  3.性别     4.电话    ****\n");
	printf("****        5.住址         ****\n");
	printf("*******************************\n");
}
//修改指定联系人的信息
void ModifyContact(Contact* pc)
{
	assert(pc);
    //存放名字的数组
	char name[MAX_NAME];
	printf("请输入要修改的联系人:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
		return;
	}
	menu1();
	printf("请选择要修改的选项:");
	int n = 0;
	scanf("%d", &n);
	switch (n)
	{
	case 1:printf("请输入姓名:");
		scanf("%s", pc->data[pos].name);
		break;
	case 2:printf("请输入年龄:");
		scanf("%d", &(pc->data[pos].age));
		break;
	case 3:printf("请输入性别:");
		scanf("%s", pc->data[pos].sex);
		break;
	case 4:printf("请输入电话:");
		scanf("%s", pc->data[pos].tele);
		break;
	case 5:printf("请输入住址:");
		scanf("%s", pc->data[pos].addr);
		break;
	}

	printf("修改成功\n");
    //看看是否修改成功
	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}
int cmp_peo_by_name(const void* e1, const void* e2)
{
	return strcmp(((people*)e1)->name, ((people*)e2)->name);
}

int cmp_peo_by_age(const void* e1, const void* e2)
{
	return ((people*)e1)->age - ((people*)e2)->age;
}
//排序联系人
void SortContact(const Contact* pc)
{
	printf("请选择想要排的序:\n");
	printf("********************************\n");
	printf("*****   1.按照名字排序    ******\n");
	printf("*****   2.按照年龄排序    ******\n");
	printf("********************************\n");
	int n = 0;
	printf("请选择:");
	scanf("%d", &n);
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_name);
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_age);
    //看看是否排序成功
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
	printf("排序成功\n");
}

通讯录源码: 

test.c:

#include "Contact.h"

void menu()
{
	printf("******************************************\n");
	printf("****  1.增加联系人      2.删除联系人  ****\n");
	printf("****  3.查找联系人      4.修改联系人  ****\n");
	printf("****  5.显示联系人     6.排序联系人   ****\n");
	printf("****           0.退出通讯录           ****\n");
	printf("******************************************\n");
}

void test()
{
	int input = 0;
	//下面是对通讯录进行的各种操作,所以我们得先有一个通讯录
	Contact con;
	InitContact(&con);
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&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:
            printf("退出通讯录\n");
			break;
		default:
            printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);

}

int main()
{
	test();
	return 0;
}

Contact.c:

#include "Contact.h"

//初始化通讯录的函数
void InitContact(Contact* pc)
{
	assert(pc);
	memset(pc->data, 0, sizeof(pc->data));//循环也可以
	pc->sz = 0;
}


//增加联系人信息的函数
void AddContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法增加\n");
		//通讯录满了,就无需执行下面的语句了
		return;//因为是void。所以无需返回任何值
	}
	else
	{
		printf("请输入姓名:");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入年龄:");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入性别:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入住址:");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("成功增加联系人\n");
	}
}


//显示联系人的信息的函数
void ShowContact(const Contact* pc)
{
	assert(pc);
	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}


//查找联系人名字的函数
static int FindByName(const Contact* pc, char name[])
{
	assert(pc);
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}


//删除联系人信息的函数的声明
void DelContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	char name[MAX_NAME] = { 0 };
	//知道要删除谁
	printf("请输入要删除的人的名字:");
	scanf("%s", name);
	//找到要删除的人(字符串)
	int del = FindByName(pc, name);
	if (del == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	for (int i = del; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	//删除最后一个元素时,虽然不能在循环中删除,但是pc->sz--了,致使访问不到最后一个元素了
	//因此,我们在打印时也不会打印出来
	pc->sz--;
	printf("删除成功\n");
}


//查找指定联系人信息的函数
void SearchContact(const Contact* pc)
{
	assert(pc);
	char name[MAX_NAME];
	printf("请输入要查找的联系人:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}


void menu1()
{
	printf("*******************************\n");
	printf("****  1.姓名     2.年龄    ****\n");
	printf("****  3.性别     4.电话    ****\n");
	printf("****        5.住址         ****\n");
	printf("*******************************\n");
}
//修改指定联系人的信息
void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[MAX_NAME];
	printf("请输入要修改的联系人:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
		return;
	}
	menu1();
	printf("请选择要修改的选项:");
	int n = 0;
	scanf("%d", &n);
	switch (n)
	{
	case 1:printf("请输入姓名:");
		scanf("%s", pc->data[pos].name);
		break;
	case 2:printf("请输入年龄:");
		scanf("%d", &(pc->data[pos].age));
		break;
	case 3:printf("请输入性别:");
		scanf("%s", pc->data[pos].sex);
		break;
	case 4:printf("请输入电话:");
		scanf("%s", pc->data[pos].tele);
		break;
	case 5:printf("请输入住址:");
		scanf("%s", pc->data[pos].addr);
		break;
	}

	printf("修改成功\n");

	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}


int cmp_peo_by_name(const void* e1, const void* e2)
{
	return strcmp(((people*)e1)->name, ((people*)e2)->name);
}


int cmp_peo_by_age(const void* e1, const void* e2)
{
	return ((people*)e1)->age - ((people*)e2)->age;
}

void SortContact(const Contact* pc)
{
	printf("请选择想要排的序:\n");
	printf("********************************\n");
	printf("*****   1.按照名字排序    ******\n");
	printf("*****   2.按照年龄排序    ******\n");
	printf("********************************\n");
	int n = 0;
	printf("请选择:");
	scanf("%d", &n);
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_name);
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_age);
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
	printf("排序成功\n");
}

Contect.h:

//头文件的声明
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>


//为后期增加联系人做准备
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30


//把选项一 一列举出来
enum OPPION
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};


//类型的声明
typedef struct people
{
	char name[MAX_NAME];//姓名
	int age;//年龄
	char sex[MAX_SEX];//性别
	//电话(我们正常的电话是11位,超过了int的长度,所以用字符串比较合适)
	char tele[MAX_TELE];
	char addr[MAX_ADDR];//住址
}people;


//通讯录
typedef struct Contact
{
	people data[MAX];
	int sz;
}Contact;


//初始化通讯录的函数的声明
void InitContact(Contact* pc);


//增加联系人信息的函数的声明
void AddContact(Contact* pc);


//显示联系人的信息的函数的声明
void ShowContact(const Contact* pc);


//删除联系人信息的函数的声明
void DelContact(Contact* pc);


//查找指定联系人信息的函数的声明
void SearchContact(const Contact* pc);


//修改指定联系人的信息
void ModifyContact(Contact* pc);

//按名字排序联系人
void SortContact(const Contact* pc);

动态版通讯录 

有关动态内存开辟的知识点:动态内存管理-CSDN博客

上述是静态版的通讯录。

下面我们来实现一下动态版的通讯录。

目标:1. 可以实现储存通讯录人数不限。2. 默认可以放3个人的信息,如果不够,就每次增加2个人的信息(这样方便我们测试,也可以默认别的数,但数据太大,不好测试)。

首先,存放人信息的空间大小是不需要改变的,但是我们用的那个联系人数组要变成一个由malloc函数开辟的空间。其次,我们想要知道这个空间当前用了几个,还剩几个。记录用了几个,就可以用sz来记录,而还剩几个空间,就可以用count来记录一下。

//通讯录
typedef struct Contact
{
	people* data;//指向通讯录的那块空间
	int sz;//记录当前的联系人个数
	int count;//记录总共开辟了多少空间
}Contact;

既然通讯录里的数据变了,那么我们的初始化函数也得变化。

//初始化通讯录的函数
void InitContact(Contact* pc)
{
    assert(pc);
	//开辟一块空间给通讯录
	pc->data = (people*)malloc(3 * sizeof(people));
	if (pc->data == NULL)//空间开辟失败
	{
		perror("InitContact");
		return;
	}
	pc->sz = 0;
	pc->count = DEFAULT_SZ;//在头文件中定义一个宏,默认数据表示初始数据
}

容量变了,那我们增加联系人的函数也得发生变化。 

static int CheckCount(Contact* pc)//判断是否需要增加空间
{
	if (pc->sz == pc->count)
	{
		people *ptr = (people*)realloc(pc->data, (pc->count + INC_SZ) * sizeof(people));
		if (ptr == NULL)
		{
			perror("CheckCount");
			return 0;
		}
		pc->data = ptr;
		pc->count += INC_SZ;
        printf("增容成功\n");
		return 1;
	}
	return 1;
}

//增加联系人信息的函数
void AddContact(Contact* pc)
{
	assert(pc);
	if (CheckCount(&pc) == 0)//增加失败就不需要往下走了
	{
		return;
	}
	else
	{
		printf("请输入姓名:");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入年龄:");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入性别:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入住址:");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("成功增加联系人\n");
	}
}

删除,查找,显示,修改,排序这些就不需要更改了。

但我们还得在退出通讯录的时候,把动态开辟的内存给释放掉。 

void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->count = 0;
	pc->sz = 0;
}

test.c:

#include "Contact.h"

void menu()
{
	printf("******************************************\n");
	printf("****  1.增加联系人      2.删除联系人  ****\n");
	printf("****  3.查找联系人      4.修改联系人  ****\n");
	printf("****  5.显示联系人     6.排序联系人   ****\n");
	printf("****           0.退出通讯录           ****\n");
	printf("******************************************\n");
}

void test()
{
	int input = 0;
	//下面是对通讯录进行的各种操作,所以我们得先有一个通讯录
	Contact con;
	InitContact(&con);
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&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:
			DestroyContact(&con);//销毁通讯录
			printf("退出通讯录\n");
			break;
		default:printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);

}


int main()
{
	test();
	return 0;
}

Contact.h:

//头文件的声明
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>


//为后期增加联系人做准备
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30

#define DEFAULT_SZ 3
#define INC_SZ 2


//把选项一 一列举出来
enum OPPION
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};


//类型的声明
typedef struct people
{
	char name[MAX_NAME];//姓名
	int age;//年龄
	char sex[MAX_SEX];//性别
	//电话(我们正常的电话是11位,超过了int的长度,所以用字符串比较合适)
	char tele[MAX_TELE];
	char addr[MAX_ADDR];//住址
}people;


//通讯录
typedef struct Contact
{
	people* data;
	int sz;
	int count;
}Contact;


//初始化通讯录的函数的声明
void InitContact(Contact* pc);


//增加联系人信息的函数的声明
void AddContact(Contact* pc);


//显示联系人的信息的函数的声明
void ShowContact(const Contact* pc);


//删除联系人信息的函数的声明
void DelContact(Contact* pc);


//查找指定联系人信息的函数的声明
void SearchContact(const Contact* pc);


//修改指定联系人的信息
void ModifyContact(Contact* pc);

//按名字排序联系人
void SortContact(const Contact* pc);

//销毁通讯录的函数
void DestroyContact(Contact* pc);

Contact.c: 

#include "Contact.h"


//初始化通讯录的函数
void InitContact(Contact* pc)
{
	assert(pc);
	//开辟一块空间给通讯录
	pc->data = (people*)malloc(3 * sizeof(people));
	if (pc->data == NULL)//空间开辟失败
	{
		perror("InitContact");
		return;
	}
	pc->sz = 0;
	pc->count = DEFAULT_SZ;
}


static int CheckCount(Contact* pc)//判断是否需要增加空间
{
	if (pc->sz == pc->count)
	{
		people *ptr = (people*)realloc(pc->data, (pc->count + INC_SZ) * sizeof(people));
		if (ptr == NULL)
		{
			perror("CheckCount");
			return 0;
		}
		pc->data = ptr;
		pc->count += INC_SZ;
		printf("增容成功\n");
		return 1;
	}
	return 1;
}

//增加联系人信息的函数
void AddContact(Contact* pc)
{
	assert(pc);
	if (CheckCount(pc) == 0)//增加失败就不需要往下走了
	{
		return;
	}
	else
	{
		printf("请输入姓名:");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入年龄:");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入性别:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入住址:");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("成功增加联系人\n");
	}
}


//显示联系人的信息的函数
void ShowContact(const Contact* pc)
{
	assert(pc);
	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}


//查找联系人名字的函数
static int FindByName(const Contact* pc, char name[])
{
	assert(pc);
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

//删除联系人信息的函数的声明
void DelContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	char name[MAX_NAME] = { 0 };
	//知道要删除谁
	printf("请输入要删除的人的名字:");
	scanf("%s", name);	


	//找到要删除的人(字符串)
	int del = FindByName(pc, name);
	if (del == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	for (int i = del; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	//删除最后一个元素时,虽然不能在循环中删除,但是pc->sz--了,致使访问不到最后一个元素了
	//因此,我们在打印时也不会打印出来
	pc->sz--;
	printf("删除成功\n");
}


//查找指定联系人信息的函数
void SearchContact(const Contact* pc)
{
	assert(pc);
	char name[MAX_NAME];
	printf("请输入要查找的联系人:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}


void menu1()
{
	printf("*******************************\n");
	printf("****  1.姓名     2.年龄    ****\n");
	printf("****  3.性别     4.电话    ****\n");
	printf("****        5.住址         ****\n");
	printf("*******************************\n");
}
//修改指定联系人的信息
void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[MAX_NAME];
	printf("请输入要修改的联系人:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
		return;
	}
	menu1();
	printf("请选择要修改的选项:");
	int n = 0;
	scanf("%d", &n);
	switch (n)
	{
	case 1:printf("请输入姓名:");
		scanf("%s", pc->data[pos].name);
		break;
	case 2:printf("请输入年龄:");
		scanf("%d", &(pc->data[pos].age));
		break;
	case 3:printf("请输入性别:");
		scanf("%s", pc->data[pos].sex);
		break;
	case 4:printf("请输入电话:");
		scanf("%s", pc->data[pos].tele);
		break;
	case 5:printf("请输入住址:");
		scanf("%s", pc->data[pos].addr);
		break;
	}

	printf("修改成功\n");

	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}


int cmp_peo_by_name(const void* e1, const void* e2)
{
	return strcmp(((people*)e1)->name, ((people*)e2)->name);
}


int cmp_peo_by_age(const void* e1, const void* e2)
{
	return ((people*)e1)->age - ((people*)e2)->age;
}

void SortContact(const Contact* pc)
{
	printf("请选择想要排的序:\n");
	printf("********************************\n");
	printf("*****   1.按照名字排序    ******\n");
	printf("*****   2.按照年龄排序    ******\n");
	printf("********************************\n");
	int n = 0;
	printf("请选择:");
	scanf("%d", &n);
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_name);
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_age);
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
	printf("排序成功\n");
}


void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->count = 0;
	pc->sz = 0;
}

动态通讯录(文件版)

 有关文件的读写的知识点:C语言之文件操作(万字详解)-CSDN博客

上面是动态版的通讯录,可以实现空间不受限制。但是如果我们想要知道我们上一次是存放什么呢?那就得用文件来保存上一次的信息。我们应该是在销毁前保存。

void SaveContact(Contact* pc)
{
	//打开文件
	FILE* pf = fopen("data.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	//写数据
	for (int i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(people), 1, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

我们保存的信息是为了下一次打开的时候,可以直接查看到这些数据。那么我们在初始化通讯录的时候,就应该把数据放到通讯录里,如果我们要查看的话,就可以选择显示通讯录的信息即可。

void LoadContact(Contact* pc)
{
	//把文件中的信息加载到通讯录中
	FILE* pf = fopen("data.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	//读文件
	people tmp = {0};
	while (fread(&tmp, sizeof(people), 1, pf))//读一个判断一个,当返回为0时,就说明已经读完了
	{
		if (CheckCount(pc) == 0)//存放的时候,判断是否需要增加空间
		{
			return;
		}
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}

	//关闭文件
	fclose(pf);
	pf = NULL;
}


//初始化通讯录的函数
void InitContact(Contact* pc)
{
	assert(pc);
	//开辟一块空间给通讯录
	pc->data = (people*)malloc(3 * sizeof(people));
	if (pc->data == NULL)//空间开辟失败
	{
		perror("InitContact");
		return;
	}
	pc->sz = 0;
	pc->count = DEFAULT_SZ;

	//把文件中的信息加载到通讯录中
	LoadContact(pc);
}

test.c: 

#include "Contact.h"

void menu()
{
	printf("******************************************\n");
	printf("****  1.增加联系人      2.删除联系人  ****\n");
	printf("****  3.查找联系人      4.修改联系人  ****\n");
	printf("****  5.显示联系人     6.排序联系人   ****\n");
	printf("****           0.退出通讯录           ****\n");
	printf("******************************************\n");
}

void test()
{
	int input = 0;
	//下面是对通讯录进行的各种操作,所以我们得先有一个通讯录
	Contact con;
	InitContact(&con);
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&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);//把信息保存在文件里
			DestroyContact(&con);//销毁通讯录
			printf("退出通讯录\n");
			break;
		default:printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);

}


int main()
{
	test();
	return 0;
}

Contact.h: 

//头文件的声明
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>


//为后期增加联系人做准备
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30

#define DEFAULT_SZ 3
#define INC_SZ 2


//把选项一 一列举出来
enum OPPION
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};


//类型的声明
typedef struct people
{
	char name[MAX_NAME];//姓名
	int age;//年龄
	char sex[MAX_SEX];//性别
	//电话(我们正常的电话是11位,超过了int的长度,所以用字符串比较合适)
	char tele[MAX_TELE];
	char addr[MAX_ADDR];//住址
}people;


//通讯录
typedef struct Contact
{
	people* data;
	int sz;
	int count;
}Contact;


//初始化通讯录的函数的声明
void InitContact(Contact* pc);


//增加联系人信息的函数的声明
void AddContact(Contact* pc);


//显示联系人的信息的函数的声明
void ShowContact(const Contact* pc);


//删除联系人信息的函数的声明
void DelContact(Contact* pc);


//查找指定联系人信息的函数的声明
void SearchContact(const Contact* pc);


//修改指定联系人的信息
void ModifyContact(Contact* pc);

//按名字排序联系人
void SortContact(const Contact* pc);

//销毁通讯录的函数
void DestroyContact(Contact* pc);

//加载通讯录的函数
void SaveContact(Contact* pc);

Contact.c: 

#include "Contact.h"


int CheckCount(Contact* pc);


void LoadContact(Contact* pc)
{
	//把文件中的信息加载到通讯录中
	FILE* pf = fopen("data.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	//读文件
	people tmp = {0};
	while (fread(&tmp, sizeof(people), 1, pf))
	{
		if (CheckCount(pc) == 0)
		{
			return;
		}
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}

	//关闭文件
	fclose(pf);
	pf = NULL;
}


//初始化通讯录的函数
void InitContact(Contact* pc)
{
	assert(pc);
	//开辟一块空间给通讯录
	pc->data = (people*)malloc(3 * sizeof(people));
	if (pc->data == NULL)//空间开辟失败
	{
		perror("InitContact");
		return;
	}
	pc->sz = 0;
	pc->count = DEFAULT_SZ;

	//把文件中的信息加载到通讯录中
	LoadContact(pc);
}


static int CheckCount(Contact* pc)//判断是否需要增加空间
{
	if (pc->sz == pc->count)
	{
		people *ptr = (people*)realloc(pc->data, (pc->count + INC_SZ) * sizeof(people));
		if (ptr == NULL)
		{
			perror("CheckCount");
			return 0;
		}
		pc->data = ptr;
		pc->count += INC_SZ;
		printf("增容成功\n");
		return 1;
	}
	return 1;
}

//增加联系人信息的函数
void AddContact(Contact* pc)
{
	assert(pc);
	if (CheckCount(pc) == 0)//增加失败就不需要往下走了
	{
		return;
	}
	else
	{
		printf("请输入姓名:");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入年龄:");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入性别:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入住址:");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("成功增加联系人\n");
	}
}


//显示联系人的信息的函数
void ShowContact(const Contact* pc)
{
	assert(pc);
	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}


//查找联系人名字的函数
static int FindByName(const Contact* pc, char name[])
{
	assert(pc);
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

//删除联系人信息的函数的声明
void DelContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	char name[MAX_NAME] = { 0 };
	//知道要删除谁
	printf("请输入要删除的人的名字:");
	scanf("%s", name);


	//找到要删除的人(字符串)
	int del = FindByName(pc, name);
	if (del == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	for (int i = del; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	//删除最后一个元素时,虽然不能在循环中删除,但是pc->sz--了,致使访问不到最后一个元素了
	//因此,我们在打印时也不会打印出来
	pc->sz--;
	printf("删除成功\n");
}


//查找指定联系人信息的函数
void SearchContact(const Contact* pc)
{
	assert(pc);
	char name[MAX_NAME];
	printf("请输入要查找的联系人:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}


void menu1()
{
	printf("*******************************\n");
	printf("****  1.姓名     2.年龄    ****\n");
	printf("****  3.性别     4.电话    ****\n");
	printf("****        5.住址         ****\n");
	printf("*******************************\n");
}
//修改指定联系人的信息
void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[MAX_NAME];
	printf("请输入要修改的联系人:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
		return;
	}
	menu1();
	printf("请选择要修改的选项:");
	int n = 0;
	scanf("%d", &n);
	switch (n)
	{
	case 1:printf("请输入姓名:");
		scanf("%s", pc->data[pos].name);
		break;
	case 2:printf("请输入年龄:");
		scanf("%d", &(pc->data[pos].age));
		break;
	case 3:printf("请输入性别:");
		scanf("%s", pc->data[pos].sex);
		break;
	case 4:printf("请输入电话:");
		scanf("%s", pc->data[pos].tele);
		break;
	case 5:printf("请输入住址:");
		scanf("%s", pc->data[pos].addr);
		break;
	}

	printf("修改成功\n");

	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}


int cmp_peo_by_name(const void* e1, const void* e2)
{
	return strcmp(((people*)e1)->name, ((people*)e2)->name);
}


int cmp_peo_by_age(const void* e1, const void* e2)
{
	return ((people*)e1)->age - ((people*)e2)->age;
}

void SortContact(const Contact* pc)
{
	printf("请选择想要排的序:\n");
	printf("********************************\n");
	printf("*****   1.按照名字排序    ******\n");
	printf("*****   2.按照年龄排序    ******\n");
	printf("********************************\n");
	int n = 0;
	printf("请选择:");
	scanf("%d", &n);
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_name);
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_age);
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
	printf("排序成功\n");
}


void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->count = 0;
	pc->sz = 0;
}


void SaveContact(Contact* pc)
{
	//打开文件
	FILE* pf = fopen("data.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	//写数据
	for (int i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(people), 1, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

好啦!本期的通讯录的实现就到此结束啦!下一期,我们再一起学习吧! 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

git常见使用

1. 概念 分布式&#xff0c;有远程仓库和本地仓库的概念&#xff0c;因此要注意同步问题git是面向对象的&#xff0c;本质是内容寻址系统。.git目录下有个文件夹objects&#xff0c;存储git库中的对象&#xff0c;git就是根据object建立一种树形结构&#xff0c;将文件和通过h…

sentinel黑白名单权限控制

黑白名单权限控制 规则配置 规则创建 创建一个 AuthorityRule 规则对象三个关键要素 setStrategy: 黑白名单类型setResource: 规则和资源的绑定关系setLimitApp: 限制的来源 调用 AuthorityRuleManager.loadRules()加载规则 监听器实例化和管理 AuthorityPropertyListener…

SpringCloud Alibaba 入门简介

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第十一篇&#xff0c;即介绍 SpringCloud Alibaba 的入门信息。 二、出现的原因 Spring Cloud Netflix…

基于django的CRM客户关系管理系统的python设计与开发flask-vue

本基于django的CRM系统是根据当前客户关系相关的内容实际情况开发的&#xff0c;在系统语言选择上我们使用的python语言&#xff0c;数据库是小巧灵活的MySQL数据库&#xff0c;本系统的开发可以极大的提高基于django的CRM系统的管理效率。 本基于django的CRM系统采用python语言…

计算机网络分层模型介绍

计算机网络分层模型是一种组织网络通信的方法&#xff0c;它将复杂的网络通信任务分解为多个较小的、更易于管理的层次。每个层次负责处理特定的通信任务&#xff0c;并与上下层交互。最著名的分层模型是OSI&#xff08;开放系统互联&#xff09;模型和TCP/IP模型。下面将详细介…

Python爬虫新手村上手指南②

HTTP与HTTPS HTTP协议 全称是Hypertext Transfer Protocol 中文意思是&#xff1a;超文本传输协议&#xff0c;是一种发布和接收HTML(Hypertext Markup Language)页面的方法。 服务端口号为80端口 HTTPS协议 全称是Hypertext Transfer Protocol over Securesocket Layer …

BootScrap详细教程

文章目录 前言一、BootScrap入门二、导航三、栅格系统四、container五、面板六、媒体对象七、分页八、图标九、实现动态效果 前言 BootScrap是别人帮我们写好的CSS样式。如果想要使用BootScrap&#xff0c;需要先下载下来&#xff0c;在页面上引入&#xff0c;编写HTML需要按照…

【C语言】空心正方形图案

思路&#xff1a; 1&#xff0c;两行两列打印* &#xff1a;第一行和最后一行&#xff0c;第一列和最后一列。 2&#xff0c;其他地方打印空格。 代码如下&#xff1a; #include<stdio.h> int main() { int n 0; int i 0; int j 0; while (scanf("…

【LabVIEW FPGA入门】并行执行

利用图形化编程的并行特性以及 FPGA 上 LabVIEW 图的真正并行实现&#xff0c;您可以通过将应用程序代码划分为更小的进程来进一步优化执行速度。与整个应用程序在一个循环中运行相比&#xff0c;这使得每个进程能够实现更高的循环速率和更高的应用程序整体执行速率。 …

除了 ChatGPT,还有哪些好用的AI工具?

0. 前言 OnlyFans 订阅教程移步&#xff1a;【保姆级】2024年最新Onlyfans订阅教程 Midjourney 订阅教程移步&#xff1a; 【一看就会】五分钟完成MidJourney订阅 GPT-4.0 升级教程移步&#xff1a;五分钟开通GPT4.0 如果你需要使用Wildcard开通GPT4、Midjourney或是Onlyfa…

哪些超声波清洗机值得买?百元内超声波清洗机值得买推荐

日常生活中&#xff0c;无论是精致的珠宝首饰、眼镜&#xff0c;还是日常使用的化妆刷、剃须刀等&#xff0c;难免会沾染灰尘与污垢&#xff0c;长久下来不仅影响外观&#xff0c;更可能对使用效果造成负面影响。而传统的手工清洁往往既费时又费力&#xff0c;且难以彻底清洁到…

2024年度最佳大型语言模型(LLMs)汇总

大型语言模型(LLMs)是人工智能文本处理的主要类型&#xff0c;也现在最流行的人工智能应用形态。ChatGPT是迄今为止最著名的使用LLM的工具&#xff0c;它由OpenAI的GPT模型的特别调整版本提供动力。但还有许多其他聊天机器人和文本生成器&#xff0c;包括从Google Bard和Anthro…

机器学习_正则化

文章目录 代价函数 如果我们有非常多的特征&#xff0c;我们通过学习得到的假设可能能够非常好地适应训练集&#xff08;代价函数可能几乎为 0&#xff09;&#xff0c;但是可能会不能推广到新的数据。 下图是一个回归问题的例子&#xff1a; 第一个模型是一个线性模型&#xf…

Anaconda下载以前的旧版本

由于Anaconda新的版本&#xff0c;可能不太适合我们当前开发&#xff0c;我们需要下载历史版本 访问Anaconda官网的历史版本下载页面: https://repo.anaconda.com/archive/

PostgreSQL开发与实战(7)多版本并发控制1

作者&#xff1a;太阳 一、 表系统字段几个比较重要概念 1.1 tuple tuple表示表中的数据行&#xff0c;在MySQL中用row表示。 在表数据页中&#xff0c;主要分为普通的数据元祖和TOAST元祖。以下是一个普通数据元祖的结构&#xff0c;主要由三部分组成&#xff1a;HeapTupl…

如何进行软件安全性测试?CMA、CNAS软件安全测试报告获取

软件安全性测试是保障软件应用安全的重要手段&#xff0c;通过对软件系统的安全性进行全面评估和检测&#xff0c;以确保软件能够抵御各种潜在的安全威胁和风险。那么如何进行软件安全性测试?CMA、CNAS软件安全测试报告又该如何获取呢? 软件安全性测试是一种基于黑盒测试的方…

数据可视化-ECharts Html项目实战(3)

在之前的文章中&#xff0c;我们学习了如何创建堆积折线图&#xff0c;饼图以及较难的瀑布图并更改图标标题。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢。 …

C#类型转换

C#类型转换 隐式类型转换 类型转换从根本上说是类型铸造&#xff0c;或者说是把数据从一种类型转换为另一种类型。在 C# 中&#xff0c;类型铸造有两种形式&#xff1a; 隐式类型转换 - 这些转换是 C# 默认的以安全方式进行的转换, 不会导致数据丢失。例如&#xff0c;从小的…

深入理解与实践AB测试:从理论到实战案例解析

一、引言 在互联网产品优化和运营策略制定中&#xff0c;AB测试&#xff08;也称为分组测试或随机化对照实验&#xff09;是一种科学且严谨的方法。它通过将用户群体随机分配至不同的实验组&#xff08;通常是A组和B组&#xff09;&#xff0c;对比不同版本的产品或策略对关键…

CMake+vcpkg+VS2022配置github上的cmake开源项目外部库

我们以采用 GitHub 上的开源库 cuda-bundle-adjustment 为例&#xff0c;其不能直接用vcpkg进行安装&#xff0c;只能通过cmake编译后链接到VS2022。 将 cuda-bundle-adjustment 库通过 CMake 编译链接到 Visual Studio 2022 步骤操作&#xff1a; 克隆存储库&#xff1a;使用…