Linux小项目:在线词典开发

在线词典介绍

  • 流程图如下:
    在这里插入图片描述
  • 项目的功能介绍
    • 在线英英词典
    • 项目功能描述
    • 用户注册和登录验证
    • 服务器端将用户信息和历史记录保存在数据中。客户端输入用户和密码,服务器端在数据库中查找、匹配,返回结果
    • 单词在线翻译
    • 根据客户端输入输入的单词在字典文件中搜索
    • 历史记录查询
    • 项目分析
  • 项目流程
    • 定义数据库中表的结构
    • 定义消息结构体
    • 分析服务端和客户端流程
    • 编码实现
  • 客户端流程图分析
    • 服务器和客户端通信的结构体
      在这里插入图片描述
    • 客户端流程图如下:
      在这里插入图片描述
    • 服务器端流程图如下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/64b2312c006e4298a3f382597ff62558.png

在线词典演示

  • 分别打开两个终端然后运行客户端和服务端如下:
    在这里插入图片描述
  • 然后用客户端注册一个用户
    在这里插入图片描述
  • 在客户端登录用户
    在这里插入图片描述
  • 执行查询功能如下:
    在这里插入图片描述
  • 客户端执行历史查询功能如下:
    在这里插入图片描述

在线词典的代码编写

  • 客户端代码的编写:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    
    #define   N  32
    
    #define  R  1   // user - register
    #define  L  2   // user - login
    #define  Q  3   // user - query
    #define  H  4   // user - history
    
    // 定义通信双方的信息结构体
    typedef struct {
    	int type;
    	char name[N];
    	char data[256];
    }MSG;
    
    
    int  do_register(int sockfd, MSG *msg)
    {
    	msg->type = R;
    
    	printf("Input name:");
    	scanf("%s", msg->name);
    	getchar();
    
    	printf("Input passwd:");
    	scanf("%s", msg->data);
    
    	if(send(sockfd, msg, sizeof(MSG),0) < 0)
    	{
    		printf("fail to send.\n");
    		return -1;
    	}
    
    	if(recv(sockfd, msg, sizeof(MSG), 0) < 0)
    	{
    		printf("Fail to recv.\n");
    		return -1;
    	}
    
    	// ok !  or  usr alread exist.
    	printf("%s\n", msg->data);
    
    	return 0;
    }
    
    int do_login(int sockfd, MSG *msg)
    {
    	msg->type = L;
    
    	printf("Input name:");
    	scanf("%s", msg->name);
    	getchar();
    
    	printf("Input passwd:");
    	scanf("%s", msg->data);
    
    	if(send(sockfd, msg, sizeof(MSG),0) < 0)
    	{
    		printf("fail to send.\n");
    		return -1;
    	}
    
    	if(recv(sockfd, msg, sizeof(MSG), 0) < 0)
    	{
    		printf("Fail to recv.\n");
    		return -1;
    	}
    
    	if(strncmp(msg->data, "OK", 3) == 0)
    	{
    		printf("Login ok!\n");
    		return 1;
    	}
    	else 
    	{
    		printf("%s\n", msg->data);
    	}
    
    	return 0;
    }
    
    int do_query(int sockfd, MSG *msg)
    {
    	msg->type = Q;
    	puts("--------------");
    
    	while(1)
    	{
    		printf("Input word:");
    		scanf("%s", msg->data);
    		getchar();
    
    		//客户端,输入#号,返回到上一级菜单
    		if(strncmp(msg->data, "#", 1) == 0)
    			break;
    
    		//将要查询的单词发送给服务器
    		if(send(sockfd,msg, sizeof(MSG), 0) < 0)
    		{
    			printf("Fail to send.\n");
    			return -1;
    		}
    
    		// 等待接受服务器,传递回来的单词的注释信息
    		if(recv(sockfd, msg,sizeof(MSG), 0) < 0)
    		{
    			printf("Fail to recv.\n");
    			return -1;
    		}
    		printf("%s\n", msg->data);
    	}
    		
    	return 0;
    }
    
    int do_history(int sockfd, MSG *msg)
    {
    
    	msg->type = H;
    
    	send(sockfd, msg, sizeof(MSG), 0);
    	
    	// 接受服务器,传递回来的历史记录信息
    	while(1)
    	{
    		recv(sockfd, msg, sizeof(MSG), 0);
    
    		if(msg->data[0] == '\0')
    			break;
    
    		//输出历史记录信息
    		printf("%s\n", msg->data);
    	}
    
    	return 0;
    }
    
    // ./server  192.168.3.196  10000
    int main(int argc, const char *argv[])
    {
    
    	int sockfd;
    	struct sockaddr_in  serveraddr;
    	int n;
    	MSG  msg;
    
    	if(argc != 3)
    	{
    		printf("Usage:%s serverip  port.\n", argv[0]);
    		return -1;
    	}
    
    	if((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0)
    	{
    		perror("fail to socket.\n");
    		return -1;
    	}
    
    	bzero(&serveraddr, sizeof(serveraddr));
    	serveraddr.sin_family = AF_INET;
    	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    	serveraddr.sin_port = htons(atoi(argv[2]));
    
    	if(connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
    	{
    		perror("fail to connect");
    		return -1;
    	}
    
    	while(1)
    	{
    		printf("*****************************************************************\n");
    		printf("* 1.register          2.login              3.quit               *\n");
    		printf("*****************************************************************\n");
    		printf("Please choose:");
    
    		scanf("%d", &n);
    		getchar();
    
    		switch(n)
    		{
    		case 1:
    			do_register(sockfd, &msg);
    			break;
    		case 2:
    			if(do_login(sockfd, &msg) == 1)
    			{
    				goto next;
    			}
    			break;
    		case 3:
    			close(sockfd);
    			exit(0);
    			break;
    		default:
    			printf("Invalid data cmd.\n");
    		}
    
    	}
    
    next:
    	while(1)
    	{
    		printf("*****************************************************\n");
    		printf("* 1.query_word   2.history_record   3.quit          *\n");
    		printf("*****************************************************\n");
    		printf("Please choose:");
    		scanf("%d", &n);
    		getchar();
    
    		switch(n)
    		{
    			case 1:
    				do_query(sockfd, &msg);
    				break;
    			case 2:
    				do_history(sockfd, &msg);
    				break;
    			case 3:
    				close(sockfd);
    				exit(0);
    				break;
    			default :
    				printf("Invalid data cmd.\n");
    		}
    
    	}
    	
    	return 0;
    

}
```

  • 服务器端代码编写如下:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <unistd.h>
    #include <sqlite3.h>
    #include <signal.h>
    #include <time.h>
    
    
    #define   N  32
    
    #define  R  1   // user - register
    #define  L  2   // user - login
    #define  Q  3   // user - query
    #define  H  4   // user - history
    
    #define  DATABASE  "my.db"
    
    // 定义通信双方的信息结构体
    typedef struct {
    	int type;
    	char name[N];
    	char data[256];
    }MSG;
    
    
    
    int do_client(int acceptfd, sqlite3 *db);
    void do_register(int acceptfd, MSG *msg, sqlite3 *db);
    int do_login(int acceptfd, MSG *msg, sqlite3 *db);
    int do_query(int acceptfd, MSG *msg, sqlite3 *db);
    int do_history(int acceptfd, MSG *msg, sqlite3 *db);
    int history_callback(void* arg,int f_num,char** f_value,char** f_name);
    int do_searchword(int acceptfd, MSG *msg, char word[]);
    int get_date(char *date);
    
    // ./server  192.168.3.196  10000
    int main(int argc, const char *argv[])
    {
    
    	int sockfd;
    	struct sockaddr_in  serveraddr;
    	int n;
    	MSG  msg;
    	sqlite3 *db;
    	int acceptfd;
    	pid_t pid;
    
    	if(argc != 3)
    	{
    		printf("Usage:%s serverip  port.\n", argv[0]);
    		return -1;
    	}
    
    	//打开数据库
    	if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
    	{
    		printf("%s\n", sqlite3_errmsg(db));
    		return -1;
    	}
    	else
    	{
    		printf("open DATABASE success.\n");
    	}
    
    	if((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0)
    	{
    		perror("fail to socket.\n");
    		return -1;
    	}
    
    	bzero(&serveraddr, sizeof(serveraddr));
    	serveraddr.sin_family = AF_INET;
    	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    	serveraddr.sin_port = htons(atoi(argv[2]));
    
    	if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
    	{
    		perror("fail to bind.\n");
    		return -1;
    	}
    
    	// 将套接字设为监听模式
    	if(listen(sockfd, 5) < 0)
    	{
    		printf("fail to listen.\n");
    		return -1;
    	}
    
    	//处理僵尸进程
    	signal(SIGCHLD, SIG_IGN);
    
    	while(1)
    	{
    		if((acceptfd = accept(sockfd, NULL, NULL)) < 0)
    		{
    			perror("fail to accept");
    			return -1;
    		}
    
    		if((pid = fork()) < 0)
    		{
    			perror("fail to fork");
    			return -1;
    		}
    		else if(pid == 0)  // 儿子进程
    		{
    			//处理客户端具体的消息
    			close(sockfd);
    			do_client(acceptfd, db);
    
    		}
    		else  // 父亲进程,用来接受客户端的请求的
    		{
    			close(acceptfd);
    		}
    	}
    	
    	return 0;
    }
    
    
    int do_client(int acceptfd, sqlite3 *db)
    {
    	MSG msg;
    	while(recv(acceptfd, &msg, sizeof(msg), 0) > 0)
    	{
    	  printf("type:%d\n", msg.type);
    	   switch(msg.type)
    	   {
    	  	 case R:
    			 do_register(acceptfd, &msg, db);
    			 break;
    		 case L:
    			 do_login(acceptfd, &msg, db);
    			 break;
    		 case Q:
    			 do_query(acceptfd, &msg, db);
    			 break;
    		 case H:
    			 do_history(acceptfd, &msg, db);
    			 break;
    		 default:
    			 printf("Invalid data msg.\n");
    	   }
    
    	}
    
    	printf("client exit.\n");
    	close(acceptfd);
    	exit(0);
    
    	return 0;
    }
    
    void do_register(int acceptfd, MSG *msg, sqlite3 *db)
    {
    	char * errmsg;
    	char sql[128];
    
    	sprintf(sql, "insert into usr values('%s', %s);", msg->name, msg->data);
    	printf("%s\n", sql);
    
    	if(sqlite3_exec(db,sql, NULL, NULL, &errmsg) != SQLITE_OK)
    	{
    		printf("%s\n", errmsg);
    		strcpy(msg->data, "usr name already exist.");
    	}
    	else
    	{
    		printf("client  register ok!\n");
    		strcpy(msg->data, "OK!");
    	}
    
    	if(send(acceptfd, msg, sizeof(MSG), 0) < 0)
    	{
    		perror("fail to send");
    		return ;
    	}
    
    	return ;
    }
    
    int do_login(int acceptfd, MSG *msg , sqlite3 *db)
    {
    	char sql[128] = {};
    	char *errmsg;
    	int nrow;
    	int ncloumn;
    	char **resultp;
    
    	sprintf(sql, "select * from usr where name = '%s' and pass = '%s';", msg->name, msg->data);
    	printf("%s\n", sql);
    
    	if(sqlite3_get_table(db, sql, &resultp, &nrow, &ncloumn, &errmsg)!= SQLITE_OK)
    	{
    		printf("%s\n", errmsg);
    		return -1;
    	}
    	else
    	{
    		printf("get_table ok!\n");
    	}
    
    	// 查询成功,数据库中拥有此用户
    	if(nrow == 1)
    	{
    		strcpy(msg->data, "OK");
    		send(acceptfd, msg, sizeof(MSG), 0);
    		return 1;
    	}
    
    	if(nrow == 0) // 密码或者用户名错误
    	{
    		strcpy(msg->data,"usr/passwd wrong.");
    		send(acceptfd, msg, sizeof(MSG), 0);}
    
    	return 0;
    }
    
    int do_searchword(int acceptfd, MSG *msg, char word[])
    {
    	FILE * fp;
    	int len = 0;
    	char temp[512] = {};
    	int result;
    	char *p;
    
    
    	//打开文件,读取文件,进行比对
    	
    	if((fp = fopen("dict.txt", "r")) == NULL)
    	{
    		perror("fail to fopen.\n");
    		strcpy(msg->data, "Failed to open dict.txt");
    		send(acceptfd, msg, sizeof(MSG), 0);
    		return -1;
    	}
    
    	//打印出,客户端要查询的单词
    	len = strlen(word);
    	printf("%s , len = %d\n", word, len);
    
    	//读文件,来查询单词
    	while(fgets(temp, 512, fp) != NULL)
    	{
    
    	//	printf("temp:%s\n", temp);
    
    		// abandon  ab
    		result = strncmp(temp,word,len);
    
    		if(result < 0)
    		{
    			continue;
    		}
    		if(result > 0 || ((result == 0) && (temp[len]!=' ')))
    		{
    			break;
    		}
    
    		// 表示找到了,查询的单词
    		p = temp + len; //  abandon   v.akdsf dafsjkj 
    	//	printf("found word:%s\n", p);
    		while(*p == ' ')
    		{
    			p++;
    		}
    
    		// 找到了注释,跳跃过所有的空格
    		strcpy(msg->data, p);
    		printf("found word:%s\n", msg->data);
    
    		// 注释拷贝完毕之后,应该关闭文件
    		fclose(fp);
    		return 1;
    	}
    
    	fclose(fp);
    
    	return 0;
    }
    
    int get_date(char *date)
    {
    	time_t t;
    	struct tm *tp;
    
    	time(&t);
    
    	//进行时间格式转换
    	tp = localtime(&t);
    
    	sprintf(date, "%d-%d-%d %d:%d:%d", tp->tm_year + 1900, tp->tm_mon+1, tp->tm_mday, 
    			tp->tm_hour, tp->tm_min , tp->tm_sec);
    	printf("get date:%s\n", date);
    
    	return 0;
    }
    
    int do_query(int acceptfd, MSG *msg , sqlite3 *db)
    {
    	char word[64];
    	int found = 0;
    	char date[128] = {};
    	char sql[128] = {};
    	char *errmsg;
    
    	//拿出msg结构体中,要查询的单词
    	strcpy(word, msg->data);
    
    	found = do_searchword(acceptfd, msg, word);
    	printf("查询一个单词完毕.\n");
    
    	// 表示找到了单词,那么此时应该将 用户名,时间,单词,插入到历史记录表中去。
    	if(found == 1)
    	{
    		// 需要获取系统时间
    		get_date(date);
    
            sprintf(sql, "insert into record values('%s', '%s', '%s')", msg->name, date, word);
    
    		if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    		{
    			printf("%s\n", errmsg);
    			return -1;
    		}
    		else
    		{
    			printf("Insert record done.\n");
    		}
    
    	}
    	else  //表示没有找到
    	{
    		strcpy(msg->data, "Not found!");
    	}
    
    	// 将查询的结果,发送给客户端
    	send(acceptfd, msg, sizeof(MSG), 0);
    
    	return 0;
    }
    
    // 得到查询结果,并且需要将历史记录发送给客户端
    int history_callback(void* arg,int f_num,char** f_value,char** f_name)
    {
    	// record  , name  , date  , word 
    	int acceptfd;
    	MSG msg;
    
    	acceptfd = *((int *)arg);
    
    	sprintf(msg.data, "%s , %s", f_value[1], f_value[2]);
    
    	send(acceptfd, &msg, sizeof(MSG), 0);
    
    	return 0;
    }
    
    
    int do_history(int acceptfd, MSG *msg, sqlite3 *db)
    {
    	char sql[128] = {};
    	char *errmsg;
    
    	sprintf(sql, "select * from record where name = '%s'", msg->name);
    
    	//查询数据库
    	if(sqlite3_exec(db, sql, history_callback,(void *)&acceptfd, &errmsg)!= SQLITE_OK)
    	{
    		printf("%s\n", errmsg);
    	}
    	else
    	{
    		printf("Query record done.\n");
    	}
    
    	// 所有的记录查询发送完毕之后,给客户端发出一个结束信息
    	msg->data[0] = '\0';
    
    	send(acceptfd, msg, sizeof(MSG), 0);
    
    	return 0;
    }
    
    
  • 字典文本文件如下:
    链接:https://pan.baidu.com/s/1dTUm-aVnJcXgsYFlyNLfeA?pwd=v3xc
    提取码:v3xc

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

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

相关文章

如何将动态IP代理转换为静态IP代理的方法与步骤

目录 前言 一、什么是动态IP代理 二、为什么需要静态IP代理 三、如何将动态IP代理转换为静态IP代理 步骤一&#xff1a;购买静态IP地址 步骤二&#xff1a;配置代理服务器 步骤三&#xff1a;验证静态IP代理 步骤四&#xff1a;测试代理服务器 四、代码示例 五、总结…

代理IP安全问题:在国外使用代理IP是否安全

目录 前言 一、国外使用代理IP的安全风险 1. 数据泄露 2. 恶意软件 3. 网络攻击 4. 法律风险 二、保护国外使用代理IP的安全方法 1. 选择可信的代理服务器 2. 使用加密协议 3. 定期更新系统和软件 4. 注意网络安全意识 三、案例分析 总结 前言 在互联网时代&…

C++如何跨模块释放内存

这篇文章主要为大家详细介绍了C中跨模块释放内存的相关知识,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以了解下 目录 一、MT改MD二、DLL提供释放接口三、使用进程堆申请内存 在开发主程序和动态库时&#xff0c;首要原则就是&#xff1a;避免跨模块申请和…

即时设计-高效易用的界面工具

界面工具是设计师的得力助手&#xff0c;为设计师快速创建精美易用的用户界面提供了丰富的功能和直观的界面。在众多的界面工具中&#xff0c;有的支持预设模板、图标库和样式库&#xff0c;有的更注重原型和互动。如何选择优秀的界面工具&#xff1f;这里有一个高效易用的界面…

教师辞职后还能再当老师吗

有人提出这样的问题&#xff1a;“我曾是一名教师&#xff0c;但因为种种原因辞职了&#xff0c;现在还想重回教育行业&#xff0c;还有可能吗&#xff1f;”这个问题看似简单&#xff0c;实则涉及了教师职业的几个关键因素。 老师这份工作不仅仅是一份职业&#xff0c;更是一份…

‘grafana.ini‘ is read only ‘defaults.ini‘ is read only

docker安装grafana 关闭匿名登录情况下的免密登录遇到问题 grafana.ini is read only defaults.ini is read only 参考回答&#xff08;Grafana.ini giving me the creeps - #2 by bartweemaels - Configuration - Grafana Labs Community Forums&#xff09; 正确启动脚本 …

面试数据库篇(mysql)- 03MYSQL支持的存储引擎有哪些, 有什么区别

存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式 。存储引擎是基于表的&#xff0c;而不是基于库的&#xff0c;所以存储引擎也可被称为表类型。 MySQL体系结构 连接层服务层引擎层存储层 存储引擎特点 InnoDB MYSQL支持的存储引擎有哪些, 有什么区别 ? my…

Mysql的备份还原

模拟环境准备 创建一个名为school的数据库&#xff0c;创建一个名为Stuent的学生信息表 mysql> create database school; Query OK, 1 row affected (0.00 sec)mysql> use school; Database changed mysql> CREATE TABLE Student (-> Sno int(10) NOT NULL COMME…

选择何种操作系统作为网站服务器

选择操作系统时&#xff0c;需考虑稳定性、安全性、成本、兼容性和技术支持等因素&#xff0c;常见选项有Windows Server和Linux发行版。 选择网站服务器的操作系统是一个关键的决策&#xff0c;因为它将影响到网站的性能、稳定性、安全性以及未来的扩展性&#xff0c;目前市场…

考完PMP后,项目经理有必要考NPDP吗?

其实项目经理让人反感的根本原因&#xff0c;就是他们不懂产品/技术/业务&#xff0c;却总盯着时间轴和日程表去催进度。 那项目经理只能选择继续当大冤种吗&#xff1f; 项目经理可以带着产品思维做项目&#xff01;不仅会有新发现&#xff0c;而且不会让人反感。 以项目经…

YOLOv8改进涨点,添加GSConv+Slim Neck,有效提升目标检测效果,代码改进(超详细)

目录 摘要 主要想法 GSConv GSConv代码实现 slim-neck slim-neck代码实现 yaml文件 完整代码分享 总结 摘要 目标检测是计算机视觉中重要的下游任务。对于车载边缘计算平台来说&#xff0c;巨大的模型很难达到实时检测的要求。而且&#xff0c;由大量深度可分离卷积层构…

4_怎么看原理图之协议类接口之SPI笔记

SPI&#xff08;Serial Peripheral Interface&#xff09;是一种同步串行通信协议&#xff0c;通常用于在芯片之间传输数据。SPI协议使用四根线进行通信&#xff1a;主设备发送数据&#xff08;MOSI&#xff09;&#xff0c;从设备发送数据&#xff08;MISO&#xff09;&#x…

抖音商品详情数据API接口采集(属性,主图,价格,sku等)item_get-获得抖音商品详情

item_get-获得抖音商品详情 douyin.item_get 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥WeChat18305163218api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,i…

用OpenArk查看Windows 11电脑中全部快捷键并解决热键冲突问题

本文介绍在Windows电脑中&#xff0c;基于OpenArk工具&#xff0c;查看电脑操作系统与所有软件的快捷键&#xff0c;并对快捷键冲突加以处理的方法。 最近&#xff0c;发现有道词典的双击Ctrl功能失效了&#xff0c;不能很方便地翻译界面中的英语&#xff1b;所以&#xff0c;就…

解决墨刀原型在谷歌中无法打开index.html

在谷歌预览原型的时候发现需要下载插件才能预览&#xff0c;经过网上搜索&#xff0c;找到了以下解决方案&#xff0c;整理如下&#xff1a; 1、打开原型文件夹&#xff0c;依次点开resources->chrome,找到axure-chrome-extension.crx。 2. 把axure-chrome-extension.crx后…

网站数据加密之Hook通用方案

文章目录 1. 写在前面2. 请求分析3. 编写Hook4. 其他案例 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向感兴趣的朋…

ArcgisForJS如何使用ArcGIS Server发布的GP服务?

文章目录 0.引言1.ArcGIS创建GP服务2.ArcGIS Server发布GP服务3.ArcgisForJS使用ArcGIS Server发布的GP服务 0.引言 ArcGIS for JavaScript&#xff08;或简称AGJS&#xff09;是一个强大的工具&#xff0c;它允许开发者使用JavaScript在Web浏览器中创建和运行ArcGIS应用程序。…

Leetcoder Day29| 贪心算法part03

1005.K次取反后最大化的数组和 给定一个整数数组 A&#xff0c;我们只能用以下方法修改该数组&#xff1a;我们选择某个索引 i 并将 A[i] 替换为 -A[i]&#xff0c;然后总共重复这个过程 K 次。&#xff08;我们可以多次选择同一个索引 i。&#xff09; 以这种方式修改数组后&a…

【数据结构】双链表解析+完整代码(创建、插入、删除)

3.2 双链表 3.2.1 双链表的定义 定义 单链表的缺点&#xff1a;无法逆向操作&#xff0c;插入删除时只能从头开始遍历&#xff0c;很不方便。 双链表&#xff1a;每个结点都定义两个指针prior和next&#xff0c;分别指向前驱和后继&#xff0c;可进可退。 typedef struct DNod…

STM32F103学习笔记(七) PWR电源管理(原理篇)

目录 1. PWR电源管理简介 2. STM32F103的PWR模块概述 2.1 PWR模块的基本工作原理 2.2 电源管理的功能和特点 3. PWR模块的常见应用场景 4. 常见问题与解决方案 1. PWR电源管理简介 PWR&#xff08;Power&#xff09;模块是STM32F103系列微控制器中的一个重要组成部分&…