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

SQLite数据库(数据库和链表双向转换)

文章目录

  • SQLite数据库
    • 一、SQLite简介
      • 1、SQLite和MySQL
      • 2、基于嵌入式的数据库
    • 二、SQLite数据库安装
    • 三、SQLite的常用命令
    • 四、SQLite的编程操作
      • 1、SQLite数据库相关API
        • (1)头文件
        • (2)sqlite3_open()
        • (3)sqlite3_close()
        • (4)sqlite3_errmsg()
        • (5)sqlite3_exec()
        • (6)sqlite3_prepare_v2()
        • (7)sqlite3_step()
        • (8)sqlite3_column_*
        • (9)sqlite3_mprintf()
      • 2、编程实现
        • (1)打开数据库
        • (2)实现增删改查
          • 1.向数据库中增加数据:创建一个表,并且插入三条数据
          • 2.更改数据库中的数据:将数据库中num = 1的color改成white
          • 3.删除num = 1 的数据
        • (3)链表和SQLite数据转换
          • 1.静态链表插入SQLite
          • 2.动态创建链表插入数据库
          • 3.链表方式读取SQLite数据

SQLite数据库

一、SQLite简介

轻量化,易用的嵌入式数据库,用于设备端的数据管理,可以理解成单点的数据库。传统服务器型数据
库用于管理多端设备,更加复杂。

1、SQLite和MySQL

  • SQLite是一个无服务器的数据库,是自包含的。这也称为嵌入式数据库,这意味着数据库引擎作为
    应用程序的一部分运行。

  • MySQL需要运行服务器,MySQL将需要客户端和服务器架构通过网络进行交互。

数据库优点缺点
SQLite基于文件,易于设置和使用适合基础开发和测试,轻松携带使用标准SQL语法,进行微小修改使用方便缺乏用户管理和安全功能,不容易扩展,不适合大数据库无法定制
MySQL使用方便,提供了许多与数据库相关的功能良好的安全功能易于扩展,适用于大型数据库。提供良好的速度和性能提供良好的用户管理和多种访问控制需要一些技术专业知识来设置与传统SQL相比,语法略有不同

2、基于嵌入式的数据库

基于嵌入式的数据库主要有:SQLite,Firebird,Berkeley DB,eXtremeDB

  • Firebird 是关系型数据库,功能强大,支持存储过程,SQL兼容等
  • SQLite 关系型数据库,体积小,支持ACID事务
  • Berkeley DB 并没有数据库服务器的概念,他的程序直接链接到应用程序中
  • eXtremeDB 是内存数据库,运行效率高

二、SQLite数据库安装

安装方式一:

sudo apt-get -y install sqlite

安装方式二:

https://www.sqlite.org/download.html

在这里插入图片描述

把下载的文件sqlite-autoconf-3390000.tar.gz上传到开发板
tar xvf sqlite-autoconf-3390000.tar.gz 解压
cd sqlite-autoconf-3390000 进入文件夹
./configure --prefix=/usr/local 配置安装路径在/usr/local
make 编译//比较久10分钟
sudo make install 安装

在这里插入图片描述

如上图,安装成功过,运行sqlite3 进入SQL命令操作流程

三、SQLite的常用命令

1、创建一个数据库

方式一:

sqlite3 //进入数据库
.open test.db //打开(创建)一个名为test的数据库
.quit//退出数据库
数据库退出后在命令当前路径创建数据库test.db

方式二:

sqlite3 test.db //在命令运行当前窗口创建(打开)数据库test.db
.databases //列出当前打开的数据库
.quit //退出

2、创建一张表格

create table stu(id Integer,name char,score Integer);
//创建一个叫stu的表,内容包括id,name,和score

3、插入一条记录

给stu中的值赋值:
insert into stu values(106,'huang',99);
//id = 106,name = huang,score = 99
insert into stu values(101,"gang",100);// ''和""都行
//id = 101,name = gang,score = 100
insert into stu(name,score) values("huanggang",98); //插入部分字段内容

4、查看数据库的记录

.schema stu;//显示指定表的结构(列、数据类型等)。
select * from stu; //查询所有字段的结果
select name,score from stu; //查询数据库中部分字段的内容

5、删除一条记录

delete from stu where id = 101;//删除id = 101的这一项内容

6、更改一条记录

update stu set name = 'huangg' where id = 106;//将id = 106中呢name修改成'huangg'

7、删除一张表

drop table stu;//将名为stu的表删除

8、增加一列

alter table stu add column sex char;//在stu的表中增加一列内容sex

四、SQLite的编程操作

1、SQLite数据库相关API

带有数据库相关API函数编译时要加上 -l sqlite3

(1)头文件
#include <sqlite3.h>
(2)sqlite3_open()

sqlite3_open 函数是 SQLite API 中用于打开或创建 SQLite 数据库的 C 语言函数。

int sqlite3_open( const char *filename,sqlite3 **ppDb);
//返回值:如果成功打开数据库连接,返回 SQLITE_OK(通常为 0)。如果发生错误,返回相应的错误代码。

参数说明:

  • filename:指向以 UTF-8 编码的字符串,表示要打开的数据库文件的路径。如果文件不存在,SQLite 将尝试创建它。
  • ppDb:一个指向 sqlite3 指针的指针,用于存储新创建的数据库连接句柄。即使发生错误,该参数也会被更新,除非是因为内存分配失败导致无法创建 sqlite3 对象。
(3)sqlite3_close()

sqlite3_close函数用于关闭一个打开的 SQLite 数据库连接。

int sqlite3_close(sqlite3 *db);//db:指向 sqlite3 结构的指针,表示要关闭的数据库连接。
//返回值:SQLITE_OK(通常为 0)表示成功关闭连接。错误返回SQLite 错误代码。
(4)sqlite3_errmsg()

sqlite3_errmsg函数用于获取最近一次 SQLite 操作的错误消息。

const char *sqlite3_errmsg(sqlite3 *db);//db:指向 sqlite3的指针,表示已打开的数据库连接。
//返回一个指向错误消息字符串的指针,该字符串描述了调用 SQLite 函数时发生的任何错误。

在这里插入图片描述

(5)sqlite3_exec()

sqlite3_exec是 SQLite 库中的一个便捷函数,它封装了多个任务,用于执行 SQL 语句并可通过回调函数接口收集返回数据。

int sqlite3_exec(sqlite3 *db,            // 数据库连接句柄const char *sql,        // 要执行的 SQL 语句int (*callback)(void*, int, char **, char **), // 回调函数void *,                // 给回调函数传的参数char **errmsg           // 错误信息
);
//返回值:SQLITE_OK(通常为 0)表示执行成功。其他值表示发生错误。

参数说明:

  • db:指向 sqlite3 结构的指针,表示已打开的数据库连接。
  • sql:指向包含要执行的 SQL 语句的零结尾字符串的指针。
  • callback:每成功执行一次 SQL 语句,就执行一次此回调函数。如果 SQL 语句不是一个查询(例如 INSERTUPDATEDELETE),则此参数可以设置为 NULL
  • **void ***:这是传递给回调函数的用户定义参数,对应于 sqlite3_exec 函数的第四个参数。
  • errmsg:如果提供了这个参数,并且函数返回了错误(非 SQLITE_OK),则错误信息将被存储在这个参数指向的位置。调用者应该在处理完错误消息后使用 sqlite3_free 释放这个指针。

其中回调函数callback要注意的是:

回调函数应该返回一个整数,一般是return 0。通常,返回 SQLITE_OK(值为 0)表示继续处理下一行。如果返回非零值,sqlite3_exec 将停止执行 SQL 语句并返回。
typedef int (*sqlite3_callback)(void *arg,            		// 用户定义的数据指针int column_size,              // 列的数量char *column_value[],        // 列值的数组char *column_name[]          // 列名的数组
);

参数说明:

  • arg:这是一个用户定义的数据指针,它被传递给 sqlite3_exec 函数,并且最终传递给回调函数。这可以用来在回调函数内部访问额外的数据或状态。
  • column_size:表示查询结果中的列数。
  • *column_value[]:这是一个指向字符指针数组的指针,每个元素包含一行中每个列的文本表示形式。可以通过column_value[i] 来访问第 i 列的名称,索引从 0 开始。
  • *column_name[]:这是一个指向列名的指针数组。每个元素对应一列的名称,可以通过column_name[i] 来访问第 i 列的名称。
(6)sqlite3_prepare_v2()

sqlite3_prepare_v2函数用于编译 SQL 语句,并生成一个准备语句(prepared statement),这个准备语句可以被进一步用于参数绑定和执行。相比于 sqlite3_exec,使用 sqlite3_prepare_v2 可以提高执行效率,因为 SQL 语句只需要编译一次,可以被重复执行多次。

int sqlite3_prepare_v2(sqlite3 *db,            /* Database handle */const char *zSql,       /* SQL statement, UTF-8 encoded */int nByte,              /* Maximum length of zSql in bytes. */sqlite3_stmt **ppStmt,  /* OUT: Statement handle */const char **pzTail     /* OUT: Pointer to unused portion of zSql */
);
//返回值:成功返回 SQLITE_OK,失败返回相应的错误码。

参数说明:

  • db :指向 SQLite 数据库连接的指针。
  • zSql: 指向要编译的 SQL 语句的指针,该语句是 UTF-8 编码。
  • nByte: 是SQL 语句的最大字节长度。如果设置为负数,则 SQLite 会自己确定字符串的长度。
  • ppStmt: 是指向 sqlite3_stmt 指针的指针,用于接收编译后的 SQL 语句的句柄。
    • 它不是普通的 SQL 语句字符串,而是一个已经编译成二进制形式的实例,可以直接执行。
    • 通过调用 sqlite3_step 函数,可以执行 sqlite3_stmt 对象中的 SQL 语句。这个函数可以被调用一次或多次,用于循环执行。
    • 执行完所有操作后,使用 sqlite3_finalize 函数销毁 sqlite3_stmt 对象,释放与之关联的所有资源。
  • pzTail: 是指向剩余未编译 SQL 语句部分的指针的指针,如果 SQL 语句被成功编译,这个参数会被设置为指向 zSql 之后的第一个字符。
(7)sqlite3_step()

sqlite3_step是SQLite中用于执行或继续执行由 sqlite3_stmt 表示的准备语句的函数。这个函数通常在调用 sqlite3_prepare_v2sqlite3_prepare 准备 SQL 语句后使用。

int sqlite3_step(sqlite3_stmt *stmt);

执行流程:

  1. 第一次调用:当 sqlite3_step 被首次调用时,它会开始执行 SQL 语句。
  2. 后续调用:如果 SQL 语句是一个查询,并且有多行结果,sqlite3_step 会在后续调用中返回下一行结果。

使用场景:

  1. 查询:当执行一条 SELECT 语句时,sqlite3_step 用于逐行获取查询结果。
  2. 插入、更新、删除:对于这类操作,sqlite3_step 通常只被调用一次,完成操作后返回 SQLITE_DONE

返回值:sqlite3_step 函数返回一个状态码,表示执行的状态

  • SQLITE_DONE:表示语句已经成功执行完成,没有更多的结果行。
  • SQLITE_ROW:表示 SQL 语句是一条查询,且 sqlite3_step 返回了一行结果。此时,可以使用 sqlite3_column_* 系列函数访问结果列的数据。
  • SQLITE_BUSY:表示数据库忙,通常是因为另一个操作正在使用数据库。
  • SQLITE_ERROR:表示执行过程中发生了错误。可以使用 sqlite3_errmsgsqlite3_errcode 函数获取错误详情。
  • 其他错误码:SQLite 定义了其他错误码,表示特定的错误情况。
(8)sqlite3_column_*

**sqlite3_column_***是一组 SQLite API 函数,用于从 sqlite3_stmt 对象中检索单个列的数据,该对象是通过执行 SQL 查询语句得到的。

TYPE sqlite3_column_COLUMNNAME(sqlite3_stmt *stmt, int iCol);

函数说明:

  • TYPE: 是数据类型,例如 intdoubletext 等。
  • COLUMNNAME: 是列的类型或特定属性的名称,例如 intrealblob 等。
  • stmt: 是指向 sqlite3_stmt 对象的指针,该对象包含了查询结果。
  • iCol: 是列的索引号(从 0 开始)。

常用函数

  • sqlite3_column_blob:返回列的 BLOB 数据。
  • sqlite3_column_double:返回列的 REAL 数据。
  • sqlite3_column_int:返回列的 INTEGER 数据。
  • sqlite3_column_int64:返回列的 64位 INTEGER 数据。
  • sqlite3_column_text:返回列的 TEXT 数据的指针。
  • sqlite3_column_value:返回列的 sqlite3_value 对象。

这些函数用于访问由 sqlite3_step 返回的当前行的数据。每调用一次 sqlite3_step 并返回 SQLITE_ROW 后,就可以使用 sqlite3_column_* 函数来访问当前行的列数据。

(9)sqlite3_mprintf()

sqlite3_mprintf函数用于格式化字符串,类似于标准 C 语言中的 printf 函数,但它使用 SQLite 的内存分配函数来分配生成的字符串。这个函数在 SQLite 的 API 中非常有用,特别是在需要构造 SQL 语句时。

char *sqlite3_mprintf(const char *format, ...);
//返回值:函数返回一个指向新分配的字符串的指针,该字符串是格式化后的输出。如果分配内存失败,返回 NULL。

参数说明:

  • format:这是格式字符串,它指定了如何格式化后续参数。它遵循与 printf 函数相同的格式说明符。

使用示例:

char *sql;
int id = 10;
const char *name = "example";
sql = sqlite3_mprintf("SELECT * FROM table WHERE id=%d AND name='%q'", id, name);
  • 由于 sqlite3_mprintf 分配了内存,调用者有责任在不再需要时使用 sqlite3_free 来释放它。
  • 格式化选项 %q 是特殊的,在 SQLite 中用于确保字符串被正确地引用,避免 SQL 注入攻击。不过,需要注意的是,%q 并不是所有编译器都支持的。

2、编程实现

(1)打开数据库
#include <stdio.h> 
#include <sqlite3.h> int main(int argc, char *argv[]) // 主函数入口,argc 是参数个数,argv 是参数数组
{int ret; // 用于存储 SQLite 函数的返回值sqlite3 *db; // 用于存储数据库连接的指针// 检查命令行参数的数量是否正确(应提供一个数据库文件名)if(argc != 2){printf("Usage:%s xxx.db\n",argv[1]); // 如果参数数量不正确,打印用法信息return -1; }// 尝试打开数据库文件,argv[1] 是命令行提供的数据库文件名// sqlite3_open 函数尝试打开或创建一个数据库,并将数据库连接的指针存储在 db 指向的位置if((ret = sqlite3_open(argv[1],&db)) != SQLITE_OK){printf("error:%s,%d\n",sqlite3_errmsg(db),ret); //如果打开失败,打印错误信息和错误代码return -1;}else{printf("open %s success\n",argv[1]); //如果打开成功,打印成功信息}// 关闭数据库连接sqlite3_close(db); printf("done\n"); // 打印完成信息return 0; 
}

运行结果:成功打开数据库test3.db

在这里插入图片描述

(2)实现增删改查
1.向数据库中增加数据:创建一个表,并且插入三条数据
#include <stdio.h> 
#include <sqlite3.h> // 回调函数原型,由 sqlite3_exec 调用以处理查询结果
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{int i;printf("column_size = %d\n", column_size); // 打印结果集中的列数printf("arg = %s\n", (char *)arg); // 打印传递给回调函数的参数,这里通常是 NULLfor(i = 0; i < column_size; i++) {// 打印每一列的名称和值,如果值为 NULL,则打印 "NULL"printf("%s = %s\n", column_name[i], column_value[i] ? column_value[i] : "NULL");}printf("==================\n");return 0; // 回调函数返回 0 以继续执行
}int main(int argc, char *argv[]) 
{int ret; // 用于存储 SQLite 函数的返回状态char *errorMes = NULL; // 用于存储错误消息/* 定义 SQL 语句字符串*///创建一个名为Colors的表char *Sql_cretable = "create table Colors(num Integer, color char);";//Colors表中插入数据char *Sql_insert = "insert into Colors values(1,'black'),""(2,'pink'),""(3,'purple');";//查询Colors表中的所有数据char *Sql_select = "select * from Colors;";sqlite3 *db; // SQLite 数据库连接的指针// 检查命令行参数数量是否正确if(argc != 2){printf("Usage:%s xxx.db\n", argv[1]);return -1; // 参数数量不正确时,打印用法并退出}// 尝试打开数据库,如果失败打印错误消息并退出if((ret = sqlite3_open(argv[1], &db)) != SQLITE_OK){printf("error:%s\n", sqlite3_errmsg(db));return -1;}printf("open %s success\n", argv[1]); // 打开成功,打印消息// 执行创建表的 SQL 语句,如果失败打印错误if((ret = sqlite3_exec(db, Sql_cretable, NULL, NULL, &errorMes)) != SQLITE_OK){printf("error:%s\n", errorMes);}printf("create Colors success\n"); // 创建表成功,打印消息// 执行插入数据的 SQL 语句,如果失败打印错误if((ret = sqlite3_exec(db, Sql_insert, NULL, NULL, &errorMes)) != SQLITE_OK){printf("error:%s\n", errorMes);}printf("insert success\n"); // 插入数据成功,打印消息// 执行查询数据的 SQL 语句,并使用回调函数处理结果if((ret = sqlite3_exec(db, Sql_select, callback, NULL, &errorMes)) != SQLITE_OK){printf("error:%s\n", errorMes);}printf("select success\n"); // 查询成功,打印消息sqlite3_close(db);// 关闭数据库连接printf("done\n"); return 0;
}

运行结果:
在这里插入图片描述

2.更改数据库中的数据:将数据库中num = 1的color改成white
#include <stdio.h> 
#include <sqlite3.h> //回调函数,由 sqlite3_exec 调用以处理查询结果
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{int i;printf("column_size = %d\n", column_size); // 打印结果集中的列数printf("arg = %s\n", (char *)arg); // 打印传递给回调函数的参数,这里通常是 NULLfor(i = 0; i < column_size; i++) {// 打印每一列的名称和值,如果值为 NULL,则打印 "NULL"printf("%s = %s\n", column_name[i], column_value[i] ? column_value[i] : "NULL");}printf("==================\n");return 0; // 回调函数返回 0 以继续执行
}int main(int argc, char *argv[]) 
{int ret; // 用于存储 SQLite 函数的返回状态char *errorMes = NULL; // 用于存储错误消息/*定义 SQL 语句字符串*///更新表中num = 1的数据char *Sql_update = "update Colors set color = 'white' where num = 1;";// 查询 Colors 表中的所有数据char *Sql_select = "select * from Colors;"; sqlite3 *db; // SQLite 数据库连接的指针// 检查命令行参数数量是否正确if(argc != 2){printf("Usage:%s xxx.db\n", argv[1]);return -1; // 参数数量不正确时,打印用法并退出}// 尝试打开数据库,如果失败打印错误消息并退出if((ret = sqlite3_open(argv[1], &db)) != SQLITE_OK){printf("error:%s\n", sqlite3_errmsg(db));return -1;}printf("open %s success\n", argv[1]); // 打开成功,打印消息// 执行更新数据的 SQL 语句,并使用回调函数处理结果if((ret = sqlite3_exec(db, Sql_update, callback, NULL, &errorMes)) != SQLITE_OK){printf("error:%s\n", errorMes);}printf("update success\n"); // 更新成功,打印消息// 关闭数据库连接sqlite3_close(db);printf("done\n");return 0; 
}

运行结果:
在这里插入图片描述

3.删除num = 1 的数据
#include <stdio.h> 
#include <sqlite3.h> // 回调函数原型,由 sqlite3_exec 调用以处理查询结果
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{int i;printf("column_size = %d\n", column_size); // 打印结果集中的列数printf("arg = %s\n", (char *)arg); // 打印传递给回调函数的参数,这里通常是 NULLfor(i = 0; i < column_size; i++) {// 打印每一列的名称和值,如果值为 NULL,则打印 "NULL"printf("%s = %s\n", column_name[i], column_value[i] ? column_value[i] : "NULL");}printf("==================\n");return 0; // 回调函数返回 0 以继续执行
}int main(int argc, char *argv[]) 
{int ret; // 用于存储 SQLite 函数的返回状态char *errorMes = NULL; // 用于存储错误消息/* 定义 SQL 语句字符串*/// 删除 Colors 表中num = 1的数据char *Sql_delete = "delete from Colors where num = 1;";// 查询 Colors 表中的所有数据char *Sql_select = "select * from Colors;";sqlite3 *db; // SQLite 数据库连接的指针// 检查命令行参数数量是否正确if(argc != 2){printf("Usage:%s xxx.db\n", argv[1]);return -1; // 参数数量不正确时,打印用法并退出}// 尝试打开数据库,如果失败打印错误消息并退出if((ret = sqlite3_open(argv[1], &db)) != SQLITE_OK){printf("error:%s\n", sqlite3_errmsg(db));return -1;}printf("open %s success\n", argv[1]); // 打开成功,打印消息// 执行删除数据的 SQL 语句,如果失败打印错误if((ret = sqlite3_exec(db, Sql_delete, NULL, NULL, &errorMes)) != SQLITE_OK){printf("error:%s\n", errorMes);}printf("delete success\n"); // 删除成功,打印消息// 再次执行查询数据的 SQL 语句,验证删除操作的结果if((ret = sqlite3_exec(db, Sql_select, NULL, NULL, &errorMes)) != SQLITE_OK){printf("error:%s\n", errorMes);}printf("select success\n"); // 查询成功,打印消息// 关闭数据库连接sqlite3_close(db);printf("done\n"); return 0; 
}

运行结果:

在这里插入图片描述

(3)链表和SQLite数据转换
1.静态链表插入SQLite
#include <stdio.h>    // 包含标准输入输出库
#include <sqlite3.h> // 包含 SQLite 库的头文件struct Stu {int id;        // 学生IDint class;     // 班级char name[12]; // 学生姓名int scores;    // 分数struct Stu *next; // 指向下一个链表节点的指针
};// 回调函数原型,由 sqlite3_exec 调用以处理查询结果
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{int i;printf("column_size = %d\n",column_size);printf("arg = %s\n",(char *)arg);for(i=0; i<column_size;i++){printf("%s = %s\n",column_name[i],column_value[i]);}printf("==================\n");return 0;
}int main(int argc, char *argv[]) {int ret;              // 函数返回状态char *errorMes = NULL; // 错误信息// 定义 SQL 语句char *Sql_cretable = "create table Stu(id Integer,class Integer,name\ 									char,scores Integer);";char *Sql_select = "select * from Stu;";char *sql = NULL;     // 动态 SQL 语句字符串    sqlite3 *db;          // SQLite 数据库连接指针// 定义链表节点struct Stu stu1 = {1, 1801, "dafang", 99, NULL};struct Stu stu2 = {2, 1801, "xiaohong", 68, NULL};struct Stu stu3 = {3, 1801, "zhangsan", 88, NULL};// 初始化链表头指针并构建链表struct Stu *head = &stu1;head->next = &stu2;stu2.next = &stu3;// 检查命令行参数数量if (argc != 2) {printf("Usage:%s xxx.db\n", argv[1]);return -1;}// 打开 SQLite 数据库if ((ret = sqlite3_open(argv[1], &db)) != SQLITE_OK) {printf("error:%s,%d\n", sqlite3_errmsg(db), ret);return -1;} else {printf("open %s success\n", argv[1]);}// 创建表if ((ret = sqlite3_exec(db, Sql_cretable, NULL, NULL, &errorMes)) !=\ 					SQLITE_OK) {printf("error:%s\n", errorMes);}printf("create Stu table success\n");// 遍历链表并插入数据while (head != NULL) {// 构建 SQL 插入语句sql = sqlite3_mprintf("insert into Stu(id,class,name,scores)\ 											values(%d,%d,%Q,%d)",\head->id, head->class, head->name, head->scores);// 执行 SQL 插入语句if ((ret = sqlite3_exec(db, sql, NULL, NULL, &errorMes)) != SQLITE_OK) {printf("error:%s\n", errorMes);}// 释放动态分配的 SQL 语句内存sqlite3_free(sql);// 移动到链表的下一个节点head = head->next;}printf("insert success\n");// 执行查询并打印结果if ((ret = sqlite3_exec(db, Sql_select, callback, NULL, &errorMes)) != SQLITE_OK) {printf("error:%s\n", errorMes);}printf("select success\n");sqlite3_close(db); // 关闭数据库连接printf("done\n");return 0;
}

运行结果:

在这里插入图片描述

2.动态创建链表插入数据库
#include <stdio.h> 
#include <stdlib.h> 
#include <sqlite3.h> // 定义学生结构体
struct Stu {int id;         // 学生IDint class;      // 班级编号char name[12];  // 学生姓名,假设最大长度为12int scores;     // 分数struct Stu *next; // 指向下一个学生结构的指针,用于构建链表
};// 回调函数,用于 sqlite3_exec 函数查询操作
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{int i;printf("column_size = %d\n",column_size);printf("arg = %s\n",(char *)arg);for(i=0; i<column_size;i++){printf("%s = %s\n",column_name[i],column_value[i]);}printf("==================\n");return 0;
}/*提示用户输入学生信息,然后将这些信息插入到数据库中。使用 sqlite3_mprintf 来安全地格式化 SQL 插入命令,并使用 sqlite3_exec 来执行这些命令。*/
// 创建数据并插入到数据库的函数
int createData(sqlite3 *db)
{int ret; // 用于存储 sqlite3_exec 函数的返回值char *sql; // 用于存储构建的 SQL 语句char *errorMes = NULL; // 用于存储可能发生的错误信息struct Stu *new; // 指向新分配的 Stu 结构的指针;// 提示用户输入数据printf("Please input data:id Integer,class Integer,name char,scores Integer\n");printf("input 0 0 0 0 quit!\n");while(1){new = (struct Stu *)malloc(sizeof(struct Stu));		scanf("%d%d%s%d",&new->id,&new->class,new->name,&new->scores);new->next = NULL;printf("id=%d,class=%d,name=%s,scores=%d\n",\new->id,new->class,new->name,new->scores);if((new->id == 0) && (new->class == 0) && (new->scores == 0)){return 0;}sql = sqlite3_mprintf("insert into Stu(id,class,name,scores) \values(%d,%d,%Q,%d)",\new->id,new->class,new->name,new->scores);if((ret = sqlite3_exec(db,sql,NULL,NULL,&errorMes)) != SQLITE_OK){printf("error: %s\n",errorMes);}sqlite3_free(sql);}return 0;
}int main(int argc, char *argv[]) {// 检查命令行参数数量if (argc != 2) {printf("Usage: %s database_name.db\n", argv[0]);return -1;}// 打开 SQLite 数据库sqlite3 *db;if (sqlite3_open(argv[1], &db) != SQLITE_OK) {// 打印错误信息并退出printf("Cannot open database: %s\n", sqlite3_errmsg(db));return -1;}printf("Opened database successfully\n");// 创建学生表的 SQL 语句char *Sql_cretable = "CREATE TABLE IF NOT EXISTS Stu (id INTEGER, class INTEGER, name TEXT, scores INTEGER);";// 执行创建表的 SQL 语句char *errorMes;if (sqlite3_exec(db, Sql_cretable, NULL, NULL, &errorMes) != SQLITE_OK) {printf("Error creating table: %s\n", errorMes);}printf("Table created successfully\n");// 调用函数创建数据并插入数据库int ret = createData(db);// 执行查询并打印结果char *Sql_select = "SELECT * FROM Stu;";if (sqlite3_exec(db, Sql_select, callback, NULL, &errorMes) != SQLITE_OK) {printf("Error querying the database: %s\n", errorMes);}printf("Query executed successfully\n");// 关闭数据库连接sqlite3_close(db);printf("Database closed\n");return 0;
}

运行结果:

在这里插入图片描述

3.链表方式读取SQLite数据
#include <stdio.h>    
#include <stdlib.h>  
#include <sqlite3.h> struct Stu {        // 定义学生结构体int id;          // 学生IDint class;       // 班级char name[12];   // 学生姓名int scores;      // 分数struct Stu *next; // 指向下一个学生节点的指针
};// 回调函数,用于sqlite3_exec查询数据库内容
int callback(void *arg, int column_size, char *column_value[], char *column_name[]) {// ... 此处实现回调函数,用于打印查询结果 ...
}// 定义从数据库创建链表的函数
struct Stu *createListFromDB(sqlite3 *db) {sqlite3_stmt *stmt; // 存储编译后的SQL语句struct Stu *head = NULL; // 链表头初始化为NULLstruct Stu *node = NULL; // 链表的节点指针struct Stu *current = NULL; // 遍历链表的当前节点char *Sql_select = "select * from Stu;"; // 查询SQL语句// 准备SQL查询语句sqlite3_prepare_v2(db, Sql_select, -1, &stmt, NULL);while (sqlite3_step(stmt) == SQLITE_ROW) { // 遍历查询结果node = (struct Stu *)malloc(sizeof(struct Stu)); // 为新节点分配内存if (node == NULL) { // 检查内存分配是否成功fprintf(stderr, "malloc failed\n");break;}// 从数据库查询结果中获取数据并赋值给节点成员node->id = sqlite3_column_int(stmt, 0);node->class = sqlite3_column_int(stmt, 1);snprintf(node->name, sizeof(node->name), "%s", \(char *)sqlite3_column_text(stmt, 2));node->scores = sqlite3_column_int(stmt, 3);// 将新节点添加到链表if (head == NULL) {head = node; // 如果链表为空,则新节点是头节点} else {current->next = node; // 否则,将新节点链接到链表末尾}current = node; // 更新当前节点为新节点}sqlite3_finalize(stmt); // 最终化SQL语句return head; // 返回链表的头指针
}// 释放链表内存的函数
void freeList(struct Stu *head) {struct Stu *tmp;while (head != NULL) {tmp = head; // 暂存当前节点head = head->next; // 移动到下一个节点free(tmp); // 释放当前节点的内存}
}int main(int argc, char *argv[]) {int ret; // 用于存储函数返回值sqlite3 *db; // 用于存储数据库连接的指针// 检查命令行参数数量if (argc != 2) {printf("Usage:%s xxx.db\n", argv[1]);return -1;}// 打开SQLite数据库if ((ret = sqlite3_open(argv[1], &db)) != SQLITE_OK) {printf("error:%s,%d\n", sqlite3_errmsg(db), ret);return -1;} else {printf("open %s success\n", argv[1]);}// 使用createListFromDB函数从数据库创建链表struct Stu *stuList = createListFromDB(db);if (stuList != NULL) {// 遍历链表并打印学生信息struct Stu *ptr = stuList;while (ptr) {printf("ID: %d, Class: %d, Name: %s, Score: %d\n",\ptr->id, ptr->class, ptr->name, ptr->scores);ptr = ptr->next;}// 释放链表占用的内存freeList(stuList);}// 关闭数据库连接sqlite3_close(db);printf("done\n");return 0;
}

运行结果:

在这里插入图片描述

相关文章:

SQLite数据库(数据库和链表双向转换)

文章目录 SQLite数据库一、SQLite简介1、SQLite和MySQL2、基于嵌入式的数据库 二、SQLite数据库安装三、SQLite的常用命令四、SQLite的编程操作1、SQLite数据库相关API&#xff08;1&#xff09;头文件&#xff08;2&#xff09;sqlite3_open()&#xff08;3&#xff09;sqlite…...

React框架的来龙去脉,react的技术原理及技术难点和要点,小白的进阶之路

React 框架的来龙去脉&#xff1a;技术原理及技术难点和要点 1. React 的起源与发展 React 是由 Facebook 开发的一个用于构建用户界面的 JavaScript 库。它最初由 Jordan Walke 创建&#xff0c;并在 2013 年开源。React 的出现是为了解决在大型应用中管理复杂用户界面的问题…...

CPU飙升100%怎么办?字节跳动面试官告诉你答案!

小北说在前面 CPU占用率突然飙升是技术人员常遇到的一个棘手问题&#xff0c;它是一个与具体技术无关的普遍挑战。 这个问题可以很简单&#xff0c;也可以相当复杂。 有时候&#xff0c;只是一个死循环在作祟。 有时候&#xff0c;是死锁导致的。 有时候&#xff0c;代码中有…...

物理层(二)

2.2 传输介质 2.2.1 双绞线、同轴电缆、光纤和无线传输介质 传输介质也称传输媒体&#xff0c;是数据传输系统中发送器和接收器之间的物理通路。传输介质可分为:①导向传输介质&#xff0c;指铜线或光纤等&#xff0c;电磁波被导向为沿着固体介质传播:②)非导向传输介质&…...

C#——文件读取IO操作File类详情

文件读取操作 IO类 就是对应文件的操作的类I/O类 包含各种不同的类 用于执行各种文件操作&#xff0c;创建文件删除文件读写文件 常用的类: File处理文件操作的类 FilleStream用于文件当中任何位置的读写 File类 1.文件创建 File.Create() 在指定路径下创建…...

昨天gitee网站访问不了,开始以为电脑哪里有问题了

昨天gitee网站下午访问不了&#xff0c;开始以为是什么毛病。 结果同样的网络&#xff0c;手机是可以访问的。 当然就ping www.gitee.com 结果也下面那样是正常的 以为是好的&#xff0c;但就是访问www.gitee.com也是不行&#xff0c;后来用阿里云的服务器curl访问是下面情况&…...

深入理解适配器模式:Java实现与框架应用

适配器模式是一种结构型设计模式&#xff0c;它允许将一个类的接口转换成客户端希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的类可以协同工作。在本篇博客中&#xff0c;我们将详细介绍适配器模式&#xff0c;并演示如何在Java中实现它。最后&#xff0…...

跌倒识别:守护公共安全的AI技术应用场景-免费API调用

随着科技的不断进步&#xff0c;人工智能在各个领域的应用日益广泛&#xff0c;其中在公共安全领域&#xff0c;智能跌倒识别系统正逐渐成为守护人们安全的重要工具。本文将分享智能跌倒识别系统在不同场景下的应用及其重要性。 产品在线体验地址-API调用或本地化部署 AI算法模…...

算法:渐进记号的含义及时间复杂度计算

渐进记号及时间复杂度计算 渐近符号渐近记号 Ω \Omega Ω渐进记号 Θ \Theta Θ渐进记号小 ο \omicron ο渐进记号小 ω \omega ω渐进记号大 O \Omicron O常见的时间复杂度关系 时间复杂度计算&#xff1a;递归方程代入法迭代法套用公式法 渐近符号 渐近记号 Ω \Omega Ω …...

idea导入文件里面的子模块maven未识别处理解决办法

1、File → Project Structure → 点击“Modules” → 点击“” → “Import Model” 2、可以看到很多子模块&#xff0c;选择子模块下的 pom.xml 文件导入一个一个点累死了&#xff0c;父目录下也没有pom文件 解决办法&#xff1a;找到子模块中有一个pom.xml文件&#xff0c;…...

IOS Swift 从入门到精通:协议和扩展

文章目录 协议协议继承扩展协议扩展面向协议的编程总结&#xff1a; 今天你将学习一些真正的 Swifty 功能&#xff1a;协议和面向协议的编程&#xff08;POP&#xff09;。 POP 摒弃了庞大而复杂的继承层次结构&#xff0c;代之以更小、更简单、可以组合在一起的协议。这确实应…...

Vue插件开发:Vue.js的插件架构允许开发者扩展Vue的核心功能,我们可以探讨如何开发一个Vue插件并与社区分享

了解Vue插件 Vue插件的概念: Vue插件用于为Vue.js添加全局级别的功能。它提供了一种开箱即用的机制来应用全局性的功能扩展。这些插件通常用来将全局方法或属性,组件选项,Vue实例的方法,或者注入一些组件选项比如mixins和自定义方法添加至Vue.js。 Vue插件的使用场景:…...

学习面向对象前--Java基础练习题

前言 写给所有一起努力学习Java的朋友们&#xff0c;敲代码本身其实是我们梳理逻辑的一个过程。我们在学习Java代码的过程中&#xff0c;除了需要学习Java的一些基本操作及使用&#xff0c;更重要的是我们需要培养好的逻辑思维。逻辑梳理好之后&#xff0c;我们编写代码实现需要…...

用Python实现抖音新作品监控助手,实时获取博主动态

声明&#xff1a; 本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。包含关注&#xff0c;点赞等 该项目的主要功能是通过Python代码&…...

图像分隔和深度成像技术为什么受市场欢迎-数字孪生技术和物联网智能汽车技术的大爆发?分析一下图像技术的前生后世

图像分隔和深度成像是计算机视觉和图像处理领域的两项重要技术&#xff0c;它们各自有不同的技术基础和要点。 图像分隔技术基础&#xff1a; 机器学习和模式识别&#xff1a; 图像分隔通常依赖于机器学习算法&#xff0c;如支持向量机&#xff08;SVM&#xff09;、随机森林…...

Redis 内存策略

一、Redis 内存回收 Redis 之所以性能强&#xff0c;最主要的原因就是基于内存存储。然而单节点的 Redis 其内存大小不宜过大&#xff0c;会影响持久化或主从同步性能。 我们可以通过修改配置文件来设置 Redis 的最大内存&#xff1a; # 格式&#xff1a; # maxmemory <byt…...

Java小实验————斗地主

早期使用的JavaSE用到的技术栈有&#xff1a;Map集合,数组&#xff0c;set集合&#xff0c;只是简单实现了斗地主的模拟阶段&#xff0c;感兴趣的小伙伴可以调试增加功能 代码如下&#xff1a; import java.util.*;public class Poker {public static void main(String[] arg…...

【Oracle】Linux 卸载重装 oracle 教程(如何清理干净残留)系统 CentOS7.6

总览 1.停止监听 2.删除 Oracle 数据库实例 3.删除 Oracle 相关服务 4.删除 Oracle 服务脚本 5.清理 Oracle 软件和配置文件 6.强制卸载 Oracle 软件包 一、开始干活&#xff08;所有操作使用 root 权限&#xff0c;在 root 用户下执行&#xff09; 1.停止监听 lsnrctl sto…...

web中间件漏洞-Jenkins漏洞-弱口令、反弹shell

web中间件漏洞-Jenkins漏洞-弱口令、反弹shell Jenkins弱口令 默认用户一般为jenkins/jenkins 使用admin/admin123登陆成功 Jenkins反弹shell 格式为 println"命令".execute().text 在/tmp目录中生成shell.sh文件&#xff0c;并向其中写入反弹shell的语句 new…...

Linux开发讲课9--- Linux的IPC机制-内存映射(Memory Mapping)

Linux的IPC&#xff08;Inter-Process Communication&#xff0c;进程间通信&#xff09;机制是多个进程之间相互沟通的方法&#xff0c;它允许不同进程之间传播或交换信息。Linux支持多种IPC方式&#xff0c;包括但不限于&#xff1a; 管道&#xff08;Pipe&#xff09;&#…...

Java赋值运算符

Java赋值运算符分为以下&#xff1a; 符号 作用 说明 赋值 int a 10,把10赋值给变量a 加后赋值 ab,将ab的值赋值给变量a - 减后赋值 a-b,将a-b的值赋值给变量a* 乘后赋值 a*b,将a*b的值赋值给变量a / 除后赋值 a/b,将a/b的值赋值给变量a % 取余赋值 a%b,将a%b的值赋值给变量…...

Qt做群控系统

群控系统顾名思义&#xff0c;一台设备控制多台机器。首先我们来创造下界面。我们通过QT UI设计界面。设计界面如下&#xff1a; 登录界面&#xff1a; 登录界面分为两种角色&#xff0c;一种是管理员&#xff0c;另一种是超级管理员。两种用户的主界面是不同的。通过选中记住…...

【专业英语 复习】第10章 Information System

1. 单选题 (1分) An example of this type of report would be a sales report that shows that certain items are selling significantly above or below forecasts. () A. Inventory B. Demand C. Periodic D. Exception 正确答案&#xff1a; D 这种类型的报…...

09-axios在Vue中的导入与配置

09-axios 前言首先简单了解什么是Axios&#xff1f;以上完成后就可以使用了 前言 我们接着上一篇文章 08-路由地址的数据获取 来讲。 下一篇文章 10-vuex在Vue中的导入与配置 首先简单了解什么是Axios&#xff1f; Axios是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端…...

odoo17 小变更4

odoo17 小变更4 1、代码中去除了访问私人地址权限,但翻译中均还有,怪不 model:res.groups,name:base.group_private_addresses msgid "Access to Private Addresses" msgstr "" 代码也查看了,的确没有了此权限组 --><record model="res.g…...

Flink assignTimestampsAndWatermarks 深度解析:时间语义与水印生成

目录 概述 时间语义 时间戳分配 水印的作用 最佳实践 案例分析 注意事项 应用场景 概述 在Apache Flink中,assignTimestampsAndWatermarks是一个重要的方法,它允许数据流处理程序根据事件时间(event time)分配时间戳和生成水印(watermarks)。这个方法通常用于处理…...

C++排序算法——合并有序数组

合并有序数组 思路 我们可以设想一个排序的函数 这个函数里 我们有三个while while(第一次的执行条件) {先进行第一次的合并 } while(第二次的合并条件) { 把a数组在第一次没有排序上的给加进去 }while(第三次的合并条件) { 把b数组在第一次没有排序上的给加进去 }看完了这个…...

安装pytorch环境

安装&#xff1a;Anaconda3 通过命令行查显卡nvidia-smi 打开Anacanda prompt 新建 conda create -n pytorch python3.6 在Previous PyTorch Versions | PyTorch选择1.70&#xff0c;安装成功&#xff0c;但torch.cuda.is_available 返回false conda install pytorch1.7.0…...

内卷从古到今就一直存在,并不是近年的“新物”,破局在于你是否有意识地学习。

一.背景&#xff1a; 反思自己过去从学生时代到职场时代。“内卷”其实已经一直存在&#xff0c;从古到今都一直存在&#xff0c;也并不是近几年产出的“新物”。已经连续5年高考人数在1000万以上&#xff0c;而今年1300多万达到新高&#xff0c;对于竞争压力如此之大&#xf…...

跟《经济学人》学英文:2024年6月15日这期 The war for AI talent is heating up

The war for AI talent is heating up Big tech firms scramble to fill gaps as brain drain sets in 争夺人工智能人才的战争正在升温 随着人才流失的到来&#xff0c;大型科技公司争相填补空缺 brain drain&#xff1a;人才流失 scramble&#xff1a;争夺&#xff1b;争…...

港湾周评|高盛眼中的618增长

《港湾商业观察》李镭 年中最重要的购物节618终于尘埃落定了。2024年的618各大电商平台竞技情况如何&#xff1f;又有哪些新的亮点&#xff1f;都成为外界观察消费行为的参考指标。 根据京东618数据显示&#xff1a;累计成交额过10亿的品牌83个&#xff0c;超15万个中小商家销…...

SPSS知识

特点 SPSS的一些特点&#xff1a; 分析结果清晰、直观&#xff1a;SPSS提供了丰富的图表和表格&#xff0c;可以帮助用户直观地理解数据分析的结果。分析结果通常包含详细的统计量、图形和文本描述&#xff0c;使得分析结果易于解释。 易学易用&#xff1a;SPSS的用户界面设计…...

【网络安全的神秘世界】关于Linux中一些好玩的字符游戏

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 佛祖保佑 把 motd 通过xtp拖到Linux中 liyangUbuntu2204:~$ cp motd /etc/motd #一定要放在etc下 liyangUbuntu2204:~$ exi…...

【LeetCode】Hot100:验证二叉搜索树

给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树 只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。 英文题目 Given the root…...

[Qt] Qt Creator 编译输出乱码,问题页中的报错、警告内容,编译输出乱码

确保文件编码为"UTF-8"&#xff0c;"如果编码是UTF-8则添加"&#xff0c;如下图&#xff1a; 设置IDE环境语言跟随系统语言&#xff0c;Text codec for tools&#xff1a; "System" 瑞斯拜...

sed

1、sed的定义 sed是一种流编辑器&#xff0c;按行处理&#xff0c;一次处理一行内容 处理方式&#xff1a;如果只是展示&#xff0c;会放在缓冲区&#xff08;模式空间&#xff09;&#xff0c;展示结束后&#xff0c;会从模式空间把操作结果删除 一行一行处理&#xff0c;处…...

C++一文讲透thread中的detach和join的差别

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、thread详解二、线程何时运行三、线程启动方式1.join2.detach 总结 前言 无论哪种语言线程在绝大多数项目中都是会用到的&#xff0c;C也一样&#xff0c;C…...

当Windows台式电脑或笔记本电脑随机关机时,请先从这8个方面检查

序言 你的Windows笔记本电脑或PC是否意外关闭?笔记本电脑电池故障、电源线松动、过热、电源设置错误、驱动程序过时或电脑组件故障等问题都可能是罪魁祸首。如果你对这个问题感到沮丧,试试这些解决方案。 进行一些初步检查 与从电池中获取电力的笔记本电脑不同,台式电脑依…...

【凤凰房产-注册安全分析报告-缺少轨迹的滑动条】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…...

【建议收藏】逻辑回归面试题,机器学习干货、重点。

. . . . . . . . . . .纯 干 货 . . . . . . . . . . . .今天是机器学习面试题&#xff0c;16大块的内容&#xff0c;124个问题总结的第二期&#xff1a;逻辑回归面试题。 逻辑回归是一种用于解决分类问题的统计学习方法&#xff0c;尤其在二分类…...

C++使用教程

目录 一、软件使用 二、C基础规则补充 关键字 整型取值范围 浮点型取值范围 字符型使用规则 字符串型使用规则 布尔类型 常用的转义移字符 三、数组、函数、指针、结构体补充 1.数组 2.函数 声明&#xff1a; 分文件编写&#xff1a; 值传递&#xff1a; 3.指…...

k8s volcano + deepspeed多机训练 + RDMA ROCE+ 用户权限安全方案【建议收藏】

前提&#xff1a;nvidia、cuda、nvidia-fabricmanager等相关的组件已经在宿主机正确安装&#xff0c;如果没有安装可以参考我之前发的文章GPU A800 A100系列NVIDIA环境和PyTorch2.0基础环境配置【建议收藏】_a800多卡运行环境配置-CSDN博客文章浏览阅读1.1k次&#xff0c;点赞8…...

设计模式(七)创建者模式之建造者模式

这里写目录标题 概述需求需求类图BikeBuilderMobikeBuilderOfoBuilderDirectorClientClient优缺点使用场景 模式扩展ComputerClient创建者模式对比工厂方法模式VS建造者模式抽象工厂模式VS建造者模式 总结 概述 建造者模式又叫生成器模式&#xff0c;是一种对象构建模式。它可…...

# class中的__call__方法解析

class中的__call__方法解析 文章目录 class中的__call__方法解析1. 为什么要有call&#xff0c;什么情况下用call&#xff1f;1.1 为什么要有 __call__ 方法1.2 没有 __call__ 方法是否可以1.3 使用 __call__ 方法的典型场景1.3.1 示例1&#xff1a;简单函数对象1.3.2 示例2&am…...

React逻辑复用的方式都有哪些

在日常开发中&#xff0c;能够优雅的复用组件和逻辑&#xff0c;是优秀开发者的职责。在react中&#xff0c;复用逻辑的方式有很多&#xff0c;可以适用于不同的业务场景。今天说三个比较有代表性的&#xff0c;Render Props、HOC、Hooks Render Props 创建一个接受函数作为其…...

【LinuxC语言】线程重入

文章目录 前言线程重入是什么线程重入实现示例代码总结前言 在并发编程中,我们经常需要处理多个线程同时访问和修改共享资源的问题。这可能会导致数据竞争和状态不一致,从而使程序的行为变得不可预测。为了解决这个问题,我们引入了一种称为“线程重入”的机制。线程重入,或…...

【Streamlit学习笔记】Streamlit-ECharts箱型图添加均值和最值label

Streamlit-ECharts Streamlit-ECharts是一个Streamlit组件&#xff0c;用于在Python应用程序中展示ECharts图表。ECharts是一个由百度开发的JavaScript数据可视化库Apache ECharts 安装模块库 pip install streamlitpip install streamlit-echarts绘制箱型图展示 在基础箱型…...

Docker镜像仓库:存储与分发Docker镜像的中央仓库

探索Docker镜像仓库&#xff1a;存储与分发Docker镜像的中央仓库 如果你是Docker的新手&#xff0c;或者已经在使用Docker但还不太了解Docker镜像仓库&#xff0c;那么这篇博客将是你的最佳指南。我们将从基础概念开始&#xff0c;逐步深入&#xff0c;帮助你全面掌握Docker注…...

FreeRTOS必考面试题及参考答案

什么是RTOS?FreeRTOS是什么?它主要应用于哪些领域? RTOS,即实时操作系统(Real-Time Operating System),是一种专门为实时应用程序设计的操作系统,它强调的是对外部事件的快速响应和可预测性。实时系统通常要求在严格的时限内完成关键任务,因此RTOS具备优先级调度、确…...

面试题2:从浏览器输入一个URL,到最终展示前端页面这一过程,会发生什么?

这是一个高频的面试题目。 题目答案是开放性的&#xff0c;一般以后端开发的角度回答。 当地址栏输入一个 URL 后&#xff1a; 一、首先会进行 DNS 域名解析 DNS 域名解析&#xff1a;网络上的设备都是通过 IP 地址&#xff0c;作为身份标识的。但是由于点分十进制的 IP 地址 …...