You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32操作SQLite调用sqlite3_column_text提取文本乱码如何解决

问题根因

乱码和文本前置长度字段无关,核心错误是资源释放顺序错误:

  • sqlite3_column_text返回的字符串指针生命周期完全绑定在对应的预编译语句(即代码中的res)上,调用sqlite3_finalize释放语句、sqlite3_close关闭数据库后,该指针指向的内存会被SQLite回收,成为野指针。
  • 现有代码先保存字符串指针,立刻释放语句、关闭数据库,后续response->printf读取的是已经被回收覆写的无效内存,因此开头出现随机乱码,未被覆写的后半段文本会正常显示。
修复方法

调整操作顺序:所有对查询结果列的读取、输出、拷贝操作,必须放在sqlite3_finalize和sqlite3_close调用之前完成。

修正后的基础实现代码:

if (sqlite3_step(res) == SQLITE_ROW) {
  // 预编译语句未释放时,返回的指针有效
  const unsigned char * Auth = sqlite3_column_text(res, 0);
  const unsigned char * Cite = sqlite3_column_text(res, 1);
  
  // 直接在资源释放前完成输出,无需额外处理
  response->printf("%s\n%s",Auth,Cite);

  // 所有结果读取完成后再释放资源
  sqlite3_finalize(res);
  sqlite3_close(db);
}

如果需要在释放数据库资源后继续使用查询到的字符串,需要自行拷贝文本到独立管理的内存中,这时候才需要用到sqlite3_column_bytes获取文本准确长度:

if (sqlite3_step(res) == SQLITE_ROW) {
  const unsigned char * Auth = sqlite3_column_text(res, 0);
  const unsigned char * Cite = sqlite3_column_text(res, 1);
  // 获取文本字节长度(不含C字符串末尾的\0终止符)
  int authLen = sqlite3_column_bytes(res, 0);
  int citeLen = sqlite3_column_bytes(res, 1);
  // 分配独立缓冲区拷贝内容
  char *authBuf = (char*)malloc(authLen + 1);
  char *citeBuf = (char*)malloc(citeLen + 1);
  memcpy(authBuf, Auth, authLen);
  authBuf[authLen] = '\0';
  memcpy(citeBuf, Cite, citeLen);
  citeBuf[citeLen] = '\0';

  // 拷贝完成后再释放数据库资源
  sqlite3_finalize(res);
  sqlite3_close(db);

  // 后续可以独立使用拷贝后的缓冲区,用完记得释放内存
  response->printf("%s\n%s",authBuf,citeBuf);
  free(authBuf);
  free(citeBuf);
}
sqlite3_column_bytes使用说明
  • 该接口返回对应列内容的实际字节长度,对于TEXT类型列,返回值不包含C字符串要求的末尾\0终止符,仅作为内存拷贝的长度参数使用。
  • 该接口同样需要在预编译语句释放前调用,否则返回值无效。
  • sqlite3_column_text返回的本身就是标准的以\0结尾的C字符串,不存在前置长度字段,只要指针指向的内存未被回收,直接用%s格式化输出不会出现问题。

内容的提问来源于stack exchange,提问作者Rossati

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 04:55:18