我有以下代码:
sqlite *sql = new sqlite; // create a new sqlite object.
const char *dbFile = "database.db"; // sqlite database file.
sql->open(dbFile); // open the connection.
sql->query("SELECT * FROM categories"); // make a query.
int numRows = sql->numRows(); // get the number of rows.
const unsigned char *result[numRows]; // an array to store data that will be brought in from the database.
int index = 0; // counter
while(sql->fetch() != SQLITE_DONE){
// store the data into an array
result[index] = sql->getValue("name");
index++;
// print the data directly without storing in an array
cout << sql->getValue("name") << endl;
}
sql->close();
// print the content of the `result` array.
for(int i=0;i<numRows;i++){
cout << result[i] << endl;
}
结果:
注意:
方法sql->getValue("name");
返回const unsigned char*
数据。
正如您在结果图中看到的那样,为什么在直接打印数据时出现没有问题,而在打印时不会出现存储在数组中的相同数据?
首先:感谢所有帮助我(通过评论或回答)帮助我找到问题解决方案的人。 他们的答案确实应该得到最好的答案。
sqlite *sql = new sqlite;
const char *dbFile = "database.db";
sql->open(dbFile);
sql->query("SELECT * FROM categories");
int numRows = sql->numRows();
char **result = (char**)malloc(sizeof(char*) * numRows);
int index = 0;
while(sql->fetch() != SQLITE_DONE){
result[index] = (char*)malloc(sizeof(char*) * CHAR_MAX);
strcpy(result[index], reinterpret_cast<const char*> (sql->getValue("name")));
index++;
cout << sql->getValue("name") << endl;
}
cout << "\n\n" << endl;
sql->close();
for(int i=0;i<numRows;i++){
cout << *(result+i) << endl;
}
结果:
答案 0 :(得分:1)
好的,请替换此原始代码:
const unsigned char *result[numRows]; // an array to store data that will be brought in from the database.
int index = 0; // counter
while(sql->fetch() != SQLITE_DONE){
// store the data into an array
result[index] = sql->getValue("name");
index++;
}
用这个:
#include <string>
#include <vector>
using std::string; using std::vector;
⋮
vector<string> result;
while( sql->fetch() != SQLITE_DONE )
{
result.emplace_back( reinterpret_cast<const char*>(
sql->getValue("name")
) );
}
并将printf
替换为cout <<
,或者printf
调用替换result[i]
替换为result[i].c_str()
。
所有假设原始代码都有效。
免责声明:编译器未触及的代码。
<强>附录:强>
你最近的代码 - 没有编译,
const unsigned char **result = (const unsigned char**)malloc(sizeof(const unsigned char*) * numRows);
int index = 0;
while(sql->fetch() != SQLITE_DONE){
result[index] = (const unsigned char*)malloc(sizeof(const unsigned char*) * CHAR_MAX);
strcpy(result[index], sql->getValue("name"));
index++;
cout << sql->getValue("name") << endl;
}
...可以用C风格的C ++表示为
char** result = new char*[numRows]();
int index = 0;
while( sql->fetch() != SQLITE_DONE )
{
assert( index < numRows );
char const* const s = reinterpret_cast<char*>( sql->getValue( "name" ) );
result[index] = new char[1 + strlen( s )];
strcpy( result[index], s );
cout << s << endl;
++index;
}
再次假设原始代码有效。
免责声明:同样,编译器未触及代码。此外,读者应该注意,直接使用new
,虽然使用malloc
进行了改进,但这是不正确的做法。好的做法是使用std::vector
和std::string
,正如我先建议的那样。
答案 1 :(得分:1)
我最近开始自己开始查看Sqlite,所以我碰巧遇到了一些我已经解压缩的代码,作为一个例子。为了完成工作,这不应该特别高性能。
它还包括使SQL REGEXP
函数正常工作的代码。
我们的想法是在select callback
期间向数据结构中添加元素。数据结构是std::vector
的{{1}}。 std::map
是从列名称映射的表的列数据和包含列行的std::map
:
std::vector
注意:我刚看到您不打算使用#include <map>
#include <regex>
#include <string>
#include <vector>
#include <iterator>
#include <iostream>
#include <sqlite3.h>
typedef std::map<std::string, std::string> result;
typedef std::vector<result> result_vec;
#define log(msg) std::cout << msg << std::endl
static int select_callback(void* user, int argc, char** argv, char** azColName)
{
result_vec& v = *static_cast<result_vec*>(user);
result r;
for(int i = 0; i < argc; ++i)
if(argv[i])
r.emplace(azColName[i], argv[i]);
v.emplace_back(std::move(r));
return 0;
}
static void regexp_callback(sqlite3_context* context, int argc,
sqlite3_value** argv)
{
unsigned count = 0;
if(argc == 2)
{
const char* pattern = (const char*) sqlite3_value_text(argv[0]);
const char* value = (const char*) sqlite3_value_text(argv[1]);
if(pattern && value)
{
std::string s = value;
std::regex r(pattern, std::regex::icase);
std::smatch m;
if(std::regex_search(s, m, r))
count = m.size();
}
}
sqlite3_result_int(context, (int) count);
}
sqlite3* open(const std::string& name)
{
sqlite3* db;
if(sqlite3_open(name.c_str(), &db) != SQLITE_OK)
{
log("ERROR: opening db: " << name);
log("ERROR: " << sqlite3_errmsg(db));
return nullptr;
}
sqlite3_create_function_v2(db, "REGEXP", 2, SQLITE_ANY, 0, regexp_callback, NULL, NULL, NULL);
return db;
}
bool select(sqlite3* db, const std::string& sql, result_vec& v)
{
char* error = 0;
if(sqlite3_exec(db, sql.c_str(), select_callback, &v, &error) != SQLITE_OK)
{
log("ERROR: " << error);
log("ERROR: " << sqlite3_errmsg(db));
log(" SQL: " << sql);
sqlite3_free(error);
return false;
}
return true;
}
int main()
{
sqlite3* db = open("mydatabase.db");
if(db)
{
result_vec results;
if(!select(db, "select * from mytable", results))
return 1;
for(auto&& row: results)
for(auto&& col: row)
std::cout << col.first << ": " << col.second << '\n';
}
}
或 C ++ 11 功能,所以这个答案不是您要找的(虽然它可能对你有用)。但是我会留给那些可能谷歌这个问题的人。
答案 2 :(得分:1)
您的问题是您正在分配指针而不是复制字符串。这是一个重要的区别。
指定指针不会存储数据&#34;正如你的评论所暗示的,它只是复制指针。 SQLite在完成记录后丢弃数据,因此其缓冲区可以与其他记录一起使用。当你打印出字符串时,指针不再有效。
为了保留字符串以便以后打印,您需要将字符串复制到您自己的缓冲区。
这意味着您需要为字符串分配缓冲区空间,复制字符串,然后在完成后释放空间。
听起来您希望避免使用C ++功能,因此您需要查看malloc()
,free()
和strncpy()
来完成您的任务。否则,如果你想使用C ++ STL String
类,这将很好地解决你的问题。