数据结构小项目----通讯录的实现(这里用链表实现) 超详细~~~~૮(˶ᵔ ᵕ ᵔ˶)ა

news2024/11/18 10:51:14

目录

Contact.h说明:

结构体与头文件的包含:  ​编辑

 函数在头文件的声明与定义:

 Contact.c中各个函数的实现:

1.检查链表中的数据是否满了,满了就扩容

 2.链表的尾插

 3.链表的删除

4.查找名字是否匹配

 5.初始化通讯录

6. 通讯录的摧毁

7.添加联系人的信息

8.删除联系人的信息 

9.修改联系人信息

 10.查找联系人

11.通讯录当前的联系人展示

ConTest.c源文件:

测试数据: 

最后完整代码展示: 

Contact.h:

Contact.c:

ConTest.c:


Contact.h说明:

概述:为了实现这个小项目,我开创了一个头文件:Contact.h .和两个源文件:Contact.c,ConTest.c,在Contact.h中进行结构体的声明,函数的声明和头文件的包含。Contact.c文件主要用于各个函数的实现,而ConTest则用于测试函数。

 

结构体与头文件的包含:  

 这里通过结构体数组来进行数据的插入与删除操作,为了后续的书写方便,将各个结构体变量的名字重新定义为其缩写形式(底层原理是顺序表

 函数在头文件的声明与定义:

void SLCheckCapacity(Contact* pocn);//用于顺序表的扩容
void SLPushBack(Contact* ps, ConDataType x);//顺序表的尾插
void SLErase(Contact* ps, int pos);//顺序表的删除
int FindByName(Contact* pocn, char name[]);//查找名字是否匹配


void ContactInit(Contact* pocn);//通讯录的初始化
void ContactDestory(Contact* pocn);//通讯录的摧毁

void ContactAdd(Contact* pocn);//通讯录的增加联系人
void ContactDel(Contact* pocn);//通讯录的删除联系人
void ContactModify(Contact* pocn);//通讯录的修改联系人信息
void ContactFind(Contact* pocn);//通讯录的查找
void ContactShow(Contact* pocn);//当前通讯录的信息的展示

 

 Contact.c中各个函数的实现:

1.检查链表中的数据是否满了,满了就扩容

代码详解:

//检查链表中的数据是否满了,满了就扩容
void SLCheckCapacity(Contact* pocn) {
	if (pocn->size == pocn->capacity) {
		int newCapacity = pocn->capacity == 0 ? 4 : 2 * pocn->capacity;//这里通过realloc来申请空间
		ConDataType* tmp = (ConDataType*)realloc(pocn->arr, newCapacity * sizeof(ConDataType));
		if (tmp == NULL) {
			perror("realloc fail!");
			exit(1);
		}
		//扩容成功
		pocn->arr = tmp;//注意要将当前的指针指向开创好的空间
		pocn->capacity = newCapacity;//容量也不要遗漏
	}
}

 由于顺序表是由数组实现的,如果定义一个静态数组,很不利于数据的存储。定义得太大浪费空间,定义得太小空间不够,这里我选择使用动态链表的形式实现这个问题,所以这里定义了一个函数SLCheckCapacity来检查链表的大小(size)是否超过其最大容量(capacity)。如果超过了,就需要进行扩容操作。没有就不需要进行任何操作。同时,为了和里这里扩容两倍。

 2.链表的尾插

代码详解:

//链表的尾插
void SLPushBack(Contact* ps, ConDataType x) {
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
}

首先判断这里的结构体指针是否为空,简单粗暴的方法:断言(assert),注意要引用头文件#include<assert.h>。接着要检查顺序表的容量是否满了,如果满了就扩容。 接着将数据插入尾部。

 3.链表的删除

代码解释:

//链表的删除
void SLErase(Contact* ps, int pos) {
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	//pos以后的数据往前挪动一位
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];//ps->arr[i-2] = ps->arr[i-1];
	}
	ps->size--;
}

4.查找名字是否匹配

代码解释:

//查找名字是否匹配
int FindByName(Contact* pocn, char name[]) {
	for (int i = 0; i < pocn->size; i++) {
		if (strcmp(pocn->arr[i].name, name) == 0) {
			return i;
		}
	}
	return -1;
}

如果有遗忘strcmp的小伙伴记得查收~

strcmp比较两个字符串的大小,一个字符一个字符比较,按ASCLL码比较
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字 

 5.初始化通讯录

 代码解释:

//初始化通讯录
void ContactInit(Contact* pocn) {
	pocn->arr = NULL;
	pocn->capacity = pocn->size = 0;
}

6. 通讯录的摧毁

代码解释:

//通讯录的摧毁
void ContactDestory(Contact* pocn) {
	assert(pocn);
	if (pocn->arr) {
		free(pocn->arr);
	}
	pocn->arr = NULL;
	pocn->capacity = pocn->size = 0;
}

7.添加联系人的信息

代码解释:

//添加联系人的信息
void ContactAdd(Contact* pocn) {
	Info info;
	//输入各个联系人的信息
	printf("请输入联系人姓名:\n");
	scanf("%s", info.name);
	printf("请输入联系人年龄:\n");
	scanf("%d", &info.age);
	printf("请输入联系人性别:\n");
	scanf("%s", info.gender);
	printf("请输入联系人电话:\n");
	scanf("%s", info.tel);
	printf("请输入联系人地址:\n");
	scanf("%s", info.addr);
	//用尾插法进行数据的增添
	SLPushBack(pocn, info);
}

输入联系人的各个信息后将其尾插到链表后

8.删除联系人的信息 

代码解释:

//删除联系人的信息
void ContactDel(Contact* pocn) {
	//删除之前要先查找
	//找到之后可以删除找不到,就不能进行删除操作
	printf("请输入要删除的联系人名字:\n");
	char name[NAME_MAX];
	scanf("%s", name);
	//定义findIndex来判断是否存在联系人信息
	int findIndex = FindByName(pocn, name);
	if (findIndex < 0) {
		printf("要删除的信息不存在!\n");
		return;
	}
	//存在就删除
	SLErase(pocn, findIndex);
	printf("联系人删除成功!\n");
}

9.修改联系人信息

代码解释:

//修改联系人信息
void ContactModify(Contact* pocn) {
	//修改之前先查找
	//如果没有找到,就无法进行修改操作
	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名:\n");
	scanf("%s", name);

	int findIndex = FindByName(pocn, name);
	if (findIndex < 0) {
		printf("要修改的联系人找不到!\n");
		return;
	}
	//修改后输入新的联系人的信息
	printf("请输入姓名:\n");
	scanf("%s", pocn->arr[findIndex].name);
	printf("请输入年龄:\n");
	scanf("%d", &pocn->arr[findIndex].age);
	printf("请输入性别:\n");
	scanf("%s", pocn->arr[findIndex].gender);
	printf("请输入电话:\n");
	scanf("%s", pocn->arr[findIndex].tel);
	printf("请输入地址:\n");
	scanf("%s", pocn->arr[findIndex].addr);
	printf("联系人修改成功!\n");
}

 10.查找联系人

代码解释:

//查找联系人
void ContactFind(Contact* pocn) {
	printf("请输入要查找的联系人姓名:\n");
	char name[NAME_MAX];
	scanf("%s", name);
	int findIndex = FindByName(pocn, name);
	if (findIndex < 0) {
		printf("找不到该联系人,联系人不存在!\n");
		return;
	}
	else printf("找到了,输出对应信息:\n");
	printf("%s %s %s %s %s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%s %d %s %s %s\n",
		pocn->arr[findIndex].name,
		pocn->arr[findIndex].age,
		pocn->arr[findIndex].gender,
		pocn->arr[findIndex].tel,
		pocn->arr[findIndex].addr
		);
}

11.通讯录当前的联系人展示

代码解释:

//通讯录当前的联系人展示
void ContactShow(Contact* pocn) {
	printf("%s %s %s %s %s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pocn->size; i++) {
		printf("%s %d %s %s %s\n",
			pocn->arr[i].name,
			pocn->arr[i].age,
			pocn->arr[i].gender,
			pocn->arr[i].tel,
			pocn->arr[i].addr
			);
	}
}

ConTest.c源文件:

代码详解:

//引入头文件
#include"Contact.h"

void menu()//菜单的打印
{
	printf("-------------------------请输入--------------------------------\n");
	printf("----------------1.增加联系人  2.删除联系人---------------------\n");
	printf("---------------3.修改联系人   4.查找联系人---------------------\n");
	printf("---------------5.查看通讯录   0.退出通讯录---------------------\n");
	printf("---------------------------------------------------------------\n");
}

int main()
{
	int op = -1;
	Contact con;
	ContactInit(&con);
	do {
		menu();
		printf("请选择操作:");
		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("通讯录退出中……\n");
			break;
		default :
			break;
		}
	} while (op != 0);
	ContactDestory(&con);//注意结束时要摧毁通讯录,防止内存泄漏
	return 0;
}

在ConTest文件中,主要是实现菜单的打印与各个函数操作的选择

测试数据: 

 

 

最后完整代码展示: 

 

Contact.h:

#include<assert.h>
#include<stdlib.h>

//为了后续方便,这里将所要用到的数组的数据都重新定义
#define NAME_MAX 100
#define GENDER_MAX 10
#define TEL_MAX 12
#define ADDR_MAX 100
//联系人信息的存储(用结构体实现)
typedef struct PresonInformation
{
	char name[NAME_MAX];
	int age;
	char gender[GENDER_MAX];
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}Info;

typedef Info ConDataType;
//对链表的声明与定义(结构体数组),用于对上述结构体信息存储
typedef struct SeqList
{
	ConDataType* arr;
	int capacity;
	int size;
}Contact;

void SLCheckCapacity(Contact* pocn);//用于顺序表的扩容
void SLPushBack(Contact* ps, ConDataType x);//顺序表的尾插
void SLErase(Contact* ps, int pos);//顺序表的删除
int FindByName(Contact* pocn, char name[]);//查找名字是否匹配


void ContactInit(Contact* pocn);//通讯录的初始化
void ContactDestory(Contact* pocn);//通讯录的摧毁

void ContactAdd(Contact* pocn);//通讯录的增加联系人
void ContactDel(Contact* pocn);//通讯录的删除联系人
void ContactModify(Contact* pocn);//通讯录的修改联系人信息
void ContactFind(Contact* pocn);//通讯录的查找
void ContactShow(Contact* pocn);//当前通讯录的信息的展示

Contact.c:

#include"Contact.h"
//检查链表中的数据是否满了,满了就扩容
void SLCheckCapacity(Contact* pocn) {
	if (pocn->size == pocn->capacity) {
		int newCapacity = pocn->capacity == 0 ? 4 : 2 * pocn->capacity;//这里通过realloc来申请空间
		ConDataType* tmp = (ConDataType*)realloc(pocn->arr, newCapacity * sizeof(ConDataType));
		if (tmp == NULL) {
			perror("realloc fail!");
			exit(1);
		}
		//扩容成功
		pocn->arr = tmp;//注意要将当前的指针指向开创好的空间
		pocn->capacity = newCapacity;//容量也不要遗漏
	}
}
//链表的尾插
void SLPushBack(Contact* ps, ConDataType x) {
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
}
//链表的删除
void SLErase(Contact* ps, int pos) {
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	//pos以后的数据往前挪动一位
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];//ps->arr[i-2] = ps->arr[i-1];
	}
	ps->size--;
}
//查找名字是否匹配
int FindByName(Contact* pocn, char name[]) {
	for (int i = 0; i < pocn->size; i++) {
		if (strcmp(pocn->arr[i].name, name) == 0) {
			return i;
		}
	}
	return -1;
}

//初始化通讯录
void ContactInit(Contact* pocn) {
	pocn->arr = NULL;
	pocn->capacity = pocn->size = 0;
}
//通讯录的摧毁
void ContactDestory(Contact* pocn) {
	assert(pocn);
	if (pocn->arr) {
		free(pocn->arr);
	}
	pocn->arr = NULL;
	pocn->capacity = pocn->size = 0;
}
//添加联系人的信息
void ContactAdd(Contact* pocn) {
	Info info;
	//输入各个联系人的信息
	printf("请输入联系人姓名:\n");
	scanf("%s", info.name);
	printf("请输入联系人年龄:\n");
	scanf("%d", &info.age);
	printf("请输入联系人性别:\n");
	scanf("%s", info.gender);
	printf("请输入联系人电话:\n");
	scanf("%s", info.tel);
	printf("请输入联系人地址:\n");
	scanf("%s", info.addr);
	//用尾插法进行数据的增添
	SLPushBack(pocn, info);
}

//删除联系人的信息
void ContactDel(Contact* pocn) {
	//删除之前要先查找
	//找到之后可以删除找不到,就不能进行删除操作
	printf("请输入要删除的联系人名字:\n");
	char name[NAME_MAX];
	scanf("%s", name);
	//定义findIndex来判断是否存在联系人信息
	int findIndex = FindByName(pocn, name);
	if (findIndex < 0) {
		printf("要删除的信息不存在!\n");
		return;
	}
	//存在就删除
	SLErase(pocn, findIndex);
	printf("联系人删除成功!\n");
}
//修改联系人信息
void ContactModify(Contact* pocn) {
	//修改之前先查找
	//如果没有找到,就无法进行修改操作
	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名:\n");
	scanf("%s", name);

	int findIndex = FindByName(pocn, name);
	if (findIndex < 0) {
		printf("要修改的联系人找不到!\n");
		return;
	}
	//修改后输入新的联系人的信息
	printf("请输入姓名:\n");
	scanf("%s", pocn->arr[findIndex].name);
	printf("请输入年龄:\n");
	scanf("%d", &pocn->arr[findIndex].age);
	printf("请输入性别:\n");
	scanf("%s", pocn->arr[findIndex].gender);
	printf("请输入电话:\n");
	scanf("%s", pocn->arr[findIndex].tel);
	printf("请输入地址:\n");
	scanf("%s", pocn->arr[findIndex].addr);
	printf("联系人修改成功!\n");
}
//查找联系人
void ContactFind(Contact* pocn) {
	printf("请输入要查找的联系人姓名:\n");
	char name[NAME_MAX];
	scanf("%s", name);
	int findIndex = FindByName(pocn, name);
	if (findIndex < 0) {
		printf("找不到该联系人,联系人不存在!\n");
		return;
	}
	else printf("找到了,输出对应信息:\n");
	printf("%s %s %s %s %s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%s %d %s %s %s\n",
		pocn->arr[findIndex].name,
		pocn->arr[findIndex].age,
		pocn->arr[findIndex].gender,
		pocn->arr[findIndex].tel,
		pocn->arr[findIndex].addr
		);
}
//通讯录当前的联系人展示
void ContactShow(Contact* pocn) {
	printf("%s %s %s %s %s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pocn->size; i++) {
		printf("%s %d %s %s %s\n",
			pocn->arr[i].name,
			pocn->arr[i].age,
			pocn->arr[i].gender,
			pocn->arr[i].tel,
			pocn->arr[i].addr
			);
	}
}

ConTest.c:

//引入头文件
#include"Contact.h"

void menu()//菜单的打印
{
	printf("-------------------------请输入--------------------------------\n");
	printf("----------------1.增加联系人  2.删除联系人---------------------\n");
	printf("---------------3.修改联系人   4.查找联系人---------------------\n");
	printf("---------------5.查看通讯录   0.退出通讯录---------------------\n");
	printf("---------------------------------------------------------------\n");
}

int main()
{
	int op = -1;
	Contact con;
	ContactInit(&con);
	do {
		menu();
		printf("请选择操作:");
		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("通讯录退出中……\n");
			break;
		default :
			break;
		}
	} while (op != 0);
	ContactDestory(&con);//注意结束时要摧毁通讯录,防止内存泄漏
	return 0;
}

博客到这里也是结束了,制作不易,喜欢的小伙伴可以点赞加关注支持下博主,这对我真的很重要~~

 

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

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

相关文章

Vagrant安装Oracle Data Guard环境示例

在Windows 11下&#xff0c;通过Vagrant安装标准的Data Guard环境&#xff08;默认为non-CDB模式&#xff09;&#xff0c;耗时约26分钟&#xff0c;共生成2台虚机。以下为安装日志&#xff1a; ...host2: Welcome to DGMGRL, type "help" for information.host2: C…

b+树的理解

二叉树&#xff1a; 每个节点支持两个分支的树结构&#xff0c;相比于单向链表&#xff0c;多了一个分支。 二叉查找树&#xff1a; 在二叉树的基础上增加了一个规则&#xff0c;左子树的所有节点都小于它的根节点&#xff0c;右子树的所有节点都大于他的根节点。 二叉查找树…

Beego之Beego快速入门

1、beego快速入门 1.1 新建项目 新建一个项目&#xff1a; [rootzsx src]# bee new quickstart 2023/02/19 15:55:50.370 [D] init global config instance failed. If you do not use this, just ignore it. open conf/app.conf: no such file or directory 2023/02/19 1…

易优demo网站测试结果

易优demo网站测试结果-06 1、信息收集 网站账号&#xff1a;admin 密码&#xff1a;Aa123456 2、存在的漏洞 2.1 后台弱口令漏洞 http://eyoucms-s347fqn.gxalabs.com/login.php?sAdmin/login网站账号&#xff1a;admin 密码&#xff1a;Aa123456 成功登陆 2.2 代码远程…

递归、搜索与回溯算法(专题二:深搜)

往期文章&#xff08;希望小伙伴们在看这篇文章之前&#xff0c;看一下往期文章&#xff09; &#xff08;1&#xff09;递归、搜索与回溯算法&#xff08;专题零&#xff1a;解释回溯算法中涉及到的名词&#xff09;【回溯算法入门必看】-CSDN博客 &#xff08;2&#xff09…

linux基础学习(5):yum

yum是为了解决rpm包安装依赖性而产生的一种安装工具 1.yum源 1.1配置文件位置 yum源的配置文件在/etc/yum.repos.d/中 *Base源是网络yum源&#xff0c;也就是需要联网才能使用的yum源。默认情况下&#xff0c;系统会使用Base源 *Media源是光盘yum源&#xff0c;是本地yum源…

openjdk源码了解

openjdk给出debug配置选项&#xff0c;common/autoconf/jdk-options.m4 AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL], [################################################################################# Set the debug level# release: no debug information, all opti…

Jenkins实现CICD(1)_Windows10 安装Jenkins

文章目录 一、打开Jenkins官网&#xff0c;下载安装包二、安装Jenkins三、JAVA环境_JDK17下载安装&#xff08;Windows版&#xff09;四、将jdk-17添加到系统环境变量五、jenkins关联jdk-17六、安装常用插件(例如&#xff1a;git、gitlab、钉钉) 一、打开Jenkins官网&#xff0…

PDshell16逆向PostgreSQL 工程显示字段comment备注

现状&#xff1a;当刚逆向成功的表结构是没有原来表结构中的&#xff0c;comment备注如下 然后pd逆向工程的sql已经返回了这个备注的含义 解决方案&#xff1a; 1、设置显示注释列 tools——Display Preferences…如下 勾选-按照下面得方式勾选这三个 复制这里的VBS脚本&a…

Python数据分析案例37——基于分位数神经网络(QRNN)的汇率预测

案例背景 我导师的研究方向是少有的做"分位数回归"方向&#xff0c;作为研究机器学习深度学习方向的我自然就继承了这个特色&#xff0c;改进出了很多特殊结合方法&#xff0c;我会结合各种机器学习方法和各种分位数回归的方法。 之前写过分位数随机森林&#xff0…

哈希表 -- 刷题(查找算法)

目录 &#x1f4bb;哈希 -- 知识点 &#x1f40d;刷题 &#x1f33c;1&#xff0c;雪花 AC -- vector AC -- 链式前向星 &#x1f33c;2&#xff0c;公式 &#x1f4bb;哈希 -- 知识点 线性表 和 树表&#xff0c;通过比较关键字进行查找 而 散列表&#xff0c;基于…

【MATLAB源码-第119期】基于matlab的GMSK系统1bit差分解调误码率曲线仿真,输出各个节点的波形以及功率谱。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 GMSK&#xff08;高斯最小频移键控&#xff09;是一种数字调制技术&#xff0c;广泛应用于移动通信&#xff0c;例如GSM网络。它是一种连续相位调频制式&#xff0c;通过改变载波的相位来传输数据。GMSK的关键特点是其频谱的…

【接上篇】二、Flask学习之CSS(下篇)

上篇&#xff1a;二、Flask学习之CSS 3.8hover hover是用来美化鼠标悬停的效果的&#xff0c;当鼠标停放在某个区域&#xff0c;就会执行对应的hover操作。可以操作本标签的内容&#xff0c;也可以操作本标签下某一个标签的内容 3.9after <!DOCTYPE html> <html l…

Navicat平替工具,一款免费开源的通用数据库工具

前言 前段时间有小伙伴在群里提问说&#xff1a;因为公司不允许使用破解版的Navicat&#xff0c;有好用的Navicat平替工具推荐吗&#xff1f;今天分享一款免费开源的通用数据库工具&#xff1a;DBeaver。 DBeaver工具介绍 DBeaver是一款免费的跨平台数据库工具&#xff0c;适…

灵活扩展:深入理解MyBatis插件机制

第1章&#xff1a;MyBatis插件的重要性 大家好&#xff0c;我是小黑&#xff0c;咱们今天要聊的是MyBatis插件&#xff0c;MyBatis&#xff0c;大家都不陌生&#xff0c;它是一个ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;让咱们在操作数据库时能更加优雅。但今…

“深入理解 Docker 和 Nacos 的单个部署与集成部署“

目录 引言&#xff1a;Docker Nacos 单个部署1.1 什么是 Docker&#xff1f;Docker 的概念和工作原理Docker 为什么受到广泛应用和认可 1.2 什么是 Nacos&#xff1f;Nacos 的核心功能和特点Nacos 在微服务架构中的作用 1.3 Docker 单个部署 Nacos Docker Nacos 集成部署总结&a…

sfml使用opengl着色器实现2d水面波浪

SFML中使用GLSL着色器来绘制水波。 效果 代码 #include <SFML/Graphics.hpp> #include <iostream>int main() {const int WIDTH = 800;

用C语言实现简单的三子棋游戏

目录 1 -> 模块简介 2 -> test.c 3 -> game.c 4 -> game.h 1 -> 模块简介 test.c:测试游戏逻辑 game.c: 函数的实现 game.h:函数的声明 2 -> test.c #define _CRT_SECURE_NO_WARNINGS 1#include "game.h";void menu() {printf("****…

大模型学习与实践笔记(七)

一、环境配置 1.平台&#xff1a; Ubuntu Anaconda CUDA/CUDNN 8GB nvidia显卡 2.安装 # 构建虚拟环境 conda create --name xtuner0.1.9 python3.10 -y # 拉取 0.1.9 的版本源码 git clone -b v0.1.9 https://github.com/InternLM/xtuner# 从源码安装 XTuner pip insta…

python爬取图片(thumbURL和html文件标签分别爬取)

当查看源代码&#xff0c;发现网址在thumbURL之后时&#xff0c;用此代码: # 当查看源代码&#xff0c;发现网址在thumbURL之后时&#xff0c;用此代码:import requestsheaders {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121…