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

day40 SQLite3单词查询程序设计与实现

day40 SQLite3单词查询程序设计与实现

核心知识点

  • SQLite3 C接口应用:使用sqlite3_opensqlite3_exec等函数操作数据库
  • 回调函数机制:通过回调函数处理查询结果集
  • SQL语句构建:动态生成SELECTINSERT等SQL语句
  • 事务处理:使用BEGIN TRANSACTIONCOMMIT提高批量插入效率
  • 结果集处理:理解result数组与查询列的对应关系
  • 用户交互设计:实现连续查询和退出机制

完整代码实现(带详细注释)

#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// SQLite查询结果回调函数:用于处理查询到的结果
// 参数说明:
//   arg:传递给回调的用户数据指针(此处用于传递"是否找到"的标志)
//   col:查询结果的列数(本例中固定为1列)
//   result:查询结果数据数组(每行结果的值)
//   title:查询结果的列名数组(本例中为["dict_mean"])
int find(void* arg, int col, char** result, char** title)
{// 将找到结果的标志设为1(表示已找到匹配数据)*(int*)arg = 1;// 打印查询到的单词释义(result[0]对应SELECT指定的dict_mean列)printf("mean:%s\n", result[0]);return 0; // 回调函数返回0表示继续处理其他结果
}int main(int argc, char** argv)
{sqlite3* db = NULL;         // SQLite数据库连接句柄char* errmsg = NULL;        // 用于存储SQL操作错误信息int ret = 0;                // 用于存储函数调用返回值// 打开指定的SQLite数据库(如果不存在则创建)ret = sqlite3_open("./aaa.db", &db);if (SQLITE_OK != ret){// 打开数据库失败,打印错误信息fprintf(stderr, " sqlite3_open %s\n", sqlite3_errstr(ret));sqlite3_close(db);      // 关闭数据库连接return 1;               // 程序异常退出}char sql_cmd[1024] = {0};   // 用于存储SQL命令字符串// 尝试删除已存在的dict表(如果存在) - 清理旧数据strcpy(sql_cmd, "drop table dict");sqlite3_exec(db, sql_cmd, NULL, NULL, &errmsg);// 注意:删除失败可能是表不存在,属于正常情况// 创建新的dict表,包含id(序号)、word(单词)、dict_mean(释义)三个字段bzero(sql_cmd, sizeof(sql_cmd));  // 清空SQL命令缓冲区strcpy(sql_cmd, "create table dict(id int ,word char ,dict_mean text);");ret = sqlite3_exec(db, sql_cmd, NULL, NULL, &errmsg);if (SQLITE_OK != ret){// 创建表失败,打印错误信息fprintf(stderr, " sqlite3_exec sql_cmd:[%s] %s\n", sql_cmd, errmsg);sqlite3_free(errmsg);   // 释放错误信息内存sqlite3_close(db);      // 关闭数据库连接return 1;               // 程序异常退出}// 打开单词词典文件(路径为/home/linux/dict.txt)FILE* fp = fopen("/home/linux/dict.txt", "r");if (NULL == fp){perror("fopen");        // 打开文件失败,打印错误信息return 1;               // 程序异常退出}int num = 1;                // 用于记录单词的序号(id字段)// 开始数据库事务(批量插入时使用事务可提高效率)bzero(sql_cmd, sizeof(sql_cmd));strcpy(sql_cmd, "begin transaction;");sqlite3_exec(db, sql_cmd, NULL, NULL, &errmsg);// 循环读取词典文件内容并插入到数据库中while (1){char linebuf[1024] = {0};   // 用于存储读取到的一行数据// 读取文件中的一行数据,如果读取失败(到文件末尾)则退出循环if (NULL == fgets(linebuf, sizeof(linebuf), fp)){break;}// 解析行数据:以空格分割单词和释义char* word = strtok(linebuf, " ");    // 获取单词部分char* mean = strtok(NULL, "\r");      // 获取释义部分(去除回车符)// 构造插入数据的SQL命令bzero(sql_cmd, sizeof(sql_cmd));sprintf(sql_cmd, "insert into dict values(%d,\"%s\",\"%s\");", num++, word, mean);// 执行插入操作ret = sqlite3_exec(db, sql_cmd, NULL, NULL, &errmsg);if (SQLITE_OK != ret){// 插入失败,打印错误信息fprintf(stderr, " sqlite3_exec sql_cmd:[%s] %s\n", sql_cmd, errmsg);sqlite3_free(errmsg);   // 释放错误信息内存sqlite3_close(db);      // 关闭数据库连接return 1;               // 程序异常退出}}// 提交事务(将之前的批量插入操作真正写入数据库)bzero(sql_cmd, sizeof(sql_cmd));strcpy(sql_cmd, "commit;");sqlite3_exec(db, sql_cmd, NULL, NULL, &errmsg);// 循环接收用户输入,查询单词释义while (1){char want_word[1024] = {0};    // 用于存储用户要查询的单词printf("input word:");         // 提示用户输入单词fgets(want_word, sizeof(want_word), stdin);  // 读取用户输入want_word[strlen(want_word) - 1] = '\0';     // 去除输入中的换行符// 如果用户输入#quit,则退出查询循环if (0 == strcmp(want_word, "#quit")){break;}// 构造查询单词释义的SQL命令(仅选择dict_mean列)bzero(sql_cmd, sizeof(sql_cmd));sprintf(sql_cmd, "select dict_mean from dict where word like  \"%s\"", want_word);int flag = 0;  // 用于标记是否查询到结果(0:未找到,1:找到)// 执行查询操作,使用find函数作为结果回调函数ret = sqlite3_exec(db, sql_cmd, find, &flag, &errmsg);if (SQLITE_OK != ret){// 查询失败,打印错误信息fprintf(stderr, " sqlite3_exec sql_cmd:[%s] %s\n", sql_cmd, errmsg);sqlite3_free(errmsg);   // 释放错误信息内存sqlite3_close(db);      // 关闭数据库连接return 1;               // 程序异常退出}// 如果未找到匹配的单词,提示用户if (0 == flag){printf("cant find %s\n", want_word);}}// 关闭数据库连接sqlite3_close(db);return 0;   // 程序正常退出
}

关键机制解析:result[0]为何精确对应单词释义

1. SQL查询语句的精准投影

sprintf(sql_cmd, "select dict_mean from dict where word like  \"%s\"", want_word);
  • select dict_mean:这是关键的"投影"操作,明确指定只返回dict_mean这一列
  • 结果集结构:当查询命中时,返回的结果集每行只有1列数据
  • 数组索引关系:在回调函数中,result[0]自然对应这唯一一列(即单词释义)

2. 数据存储结构的一致性

sprintf(sql_cmd, "insert into dict values(%d,\"%s\",\"%s\");", num++, word, mean);
  • 插入顺序固定:第二列存储单词(word),第三列存储释义(dict_mean)
  • 查询匹配:当where word like "%s"条件满足时,返回的正是第三列存储的释义数据

3. 回调函数执行机制

查询结果情况回调函数调用result数组内容flag
找到1个匹配结果调用1次result[0] = 释义1
找到N个匹配结果调用N次每次result[0]不同1
无匹配结果不调用-0

重要特性:当查询无结果时,回调函数不会被调用,因此需通过flag标志判断是否找到

代码执行流程与理想结果

初始化阶段(首次运行)

$ gcc word_query.c -lsqlite3 -o word_query
$ ./word_query

理想输出:

input word:hello
mean:你好
input word:world
mean:世界
input word:apple
mean:苹果
input word:banana
mean:香蕉
input word:#quit

查询场景模拟

场景1:成功查询单词
input word:computer
mean:计算机
  • 执行过程
    1. 构造SQL:select dict_mean from dict where word like "computer"
    2. 数据库返回匹配行
    3. 触发回调函数:find()设置flag=1并打印释义
场景2:未找到单词
input word:zxy123
cant find zxy123
  • 执行过程
    1. 构造SQL:select dict_mean from dict where word like "zxy123"
    2. 数据库无匹配结果
    3. 不触发回调函数
    4. 检测flag=0,输出"cant find"提示
场景3:退出程序
input word:#quit
  • 执行过程
    1. 检测到输入#quit
    2. 跳出查询循环
    3. 执行sqlite3_close(db)关闭数据库
    4. 程序正常退出(返回0)

核心结论

result[0]能精确获取单词释义,是由双重保障决定的:

  1. SQL投影约束SELECT dict_mean确保结果集仅包含释义列
  2. 数据存储一致性:插入时严格保证第三列存储释义数据

这种设计使回调函数能直接通过result[0]获取目标数据,无需处理列索引映射问题,是SQLite C接口应用的典型最佳实践。


文章转载自:

http://qSmaLFa1.snmsq.cn
http://alPGyRt4.snmsq.cn
http://iwn7lJio.snmsq.cn
http://GnLAfdQY.snmsq.cn
http://Fg4TDytR.snmsq.cn
http://S787iSJF.snmsq.cn
http://1FIy9y4S.snmsq.cn
http://ILcLWRTw.snmsq.cn
http://HbzOXvLd.snmsq.cn
http://KUvmUSxj.snmsq.cn
http://arwaszqX.snmsq.cn
http://lznFD14y.snmsq.cn
http://x8OodxPV.snmsq.cn
http://3TiMdxBi.snmsq.cn
http://hM2Pbxoy.snmsq.cn
http://4XIAcPd9.snmsq.cn
http://Uox7PGoG.snmsq.cn
http://SPh9gCfS.snmsq.cn
http://TdVkwrRx.snmsq.cn
http://WnMwO9bS.snmsq.cn
http://8x02Atal.snmsq.cn
http://OpYS5AjU.snmsq.cn
http://1ztzbvln.snmsq.cn
http://zyIIe2k7.snmsq.cn
http://ucn0Dy8c.snmsq.cn
http://aEcow0T9.snmsq.cn
http://evuPTvSA.snmsq.cn
http://4whNpdQ3.snmsq.cn
http://a9zaUVup.snmsq.cn
http://9aAIGHZA.snmsq.cn
http://www.dtcms.com/a/377017.html

相关文章:

  • 华为FreeBuds 7i其他手机能用空间音频吗?如何开启?
  • Java — Lambda 表达式与函数式接口解析
  • Apache Commons Math3 使用指南:强大的Java数学库
  • 数据结构中的 二叉树
  • SoC分区
  • 先买实现烦过
  • Qt C++ 图形绘制完全指南:从基础到进阶实战
  • 我在嘉顺达蓝海的安全坚守
  • fastadmin安装后后台提示putenv()报错,不显示验证码
  • macOS苹果电脑运行向日葵远程控制软件闪退
  • 平衡车 -- 倒立摆
  • 利用OpenCV实现模板与多个对象匹配
  • 机器学习的发展与应用:从理论到现实
  • 软考系统架构设计师之软件系统建模
  • leedcode 算法刷题第三十一天
  • IDEA下载安装图文教程(非常详细,适合新手)
  • Spark 性能优化全攻略:内存管理、shuffle 优化与参数调优
  • 老味道私房菜订餐系统的设计与实现(代码+数据库+LW)
  • 古董装载优化:30秒破解重量限制
  • Vue2手录02-指令
  • 爬虫逆向之瑞数6案例(深圳大学某某附属医院)
  • AWK工具使用与技巧指南
  • Java程序员职业发展路径与转型选择分析报告(2025年)
  • 资产管理软件哪家口碑好
  • 【实战中提升自己完结篇】分支篇之分支之无线、内网安全与QOS部署(完结)
  • 【Qt】PyQt、原生QT、PySide6三者的多方面比较
  • 多级缓存架构
  • 多模态对齐与多模态融合
  • 【MySQL】常用SQL语句
  • 教师节组诗-我不少年师已老,无报师恩仅遥忆