当前位置: 首页 > 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;争…...

做网站虚拟主机哪家好/百度广告一天多少钱

我们在使用 vue element 写后台管理模板时&#xff0c;肯定逃不过左侧菜单也称侧边栏。举例&#xff1a;我们现在有一个 A 模块&#xff0c;A 模块中有详情页面和编辑页面【一共三个页面】&#xff0c;我们通常怎么考虑&#xff1f;将三个页面写在一个 vue 里&#xff0c;通过…...

德阳住房和城乡建设厅网站/qq群推广方法

IOS的逆向签名方法 1.将.ipa文件解压->Payload->右击.app文件&#xff0c;显示包内容->找到embedded.mobileprovision文件->将其拷贝出来&#xff0c;以便后面使用2.若没有安装homebrew,ruby,sign,则先依次安装3.homebrew的安装方式&#xff1a;curl -LsSf http://…...

h5建设网站教程/铜仁搜狗推广

一、前言 很多数据库系统性能不理想是因为系统没有经过整体优化&#xff0c;存在大量性能低下的SQL 语句。这类SQL语句性能不好的首要原因是缺乏高效的索引。没有索引除了导致语句本身运行速度慢外&#xff0c;更是导致大量的磁盘读写操作&#xff0c;使得整个系统性能都受之影…...

怎么样在网站上做跳转/海南百度推广总代理

用<c:choose> <c:when> <c:otherwise>即可。 refurl:http://bluexp29.blog.163.com/blog/static/3385814820101535831912/ http://tianhandigeng.iteye.com/blog/938253...

做推广网站的去哪能买到有效资料/深圳优化网站方法

RedisInsight 是一个直观高效的 Redis GUI 管理工具&#xff0c;它可以对 Redis 的内存、连接数、命中率以及正常运行时间进行监控&#xff0c;并且可以在界面上使用 CLI 和连接的 Redis 进行交互&#xff08;RedisInsight 内置对 Redis 模块支持&#xff09;&#xff1a; http…...

长沙网站建设推广服务/百度营销

本文讲的是卖白菜赚金融的钱万达送你网络金融小店,炙手可热的万达集团刚刚宣布网络金融公司的成立&#xff0c;瞬间就推出重拳&#xff1a;网络金融小店&#xff0c;并且以全免费、零门槛的方式砸向市场。这让小企业、小店主卖着白菜躺着赚金融的钱成为可能。 网络金融小店是个…...