我正在研究sqlite-.dll用于教育目的。 我试图在每次使用数据库中的新行调用回调函数时动态地在我的2维数组中添加一行。 (例如SELECT * FROM CUSTOMER)。 然后,应将此数组中存储的数据作为C接口返回。
SQLCONTROL_API char** sql_execQuery(char *dbName, char *sqlStatement)
{
char **a = 0;
/*Some sqlite stuff*/
int rc = sqlite3_exec(db, sqlStatement, callback, &a, &zErrMsg);
return a;
}
使用回调函数:
static int callback(void *data, int argc, char **argv, char **azColName)
{
char **old = (char **)data;
int num_rows = sizeof(old) / sizeof(old[0]);
int num_cols = sizeof(old[0]) / sizeof(old[0][0]);
old = (char **)realloc(old, (num_rows + 1) * sizeof(char *));
for (int i = 0; i < (num_rows + 1); i++)
old[i] = (char *)realloc(old[i], argc * sizeof(char *));
/*I am trying to create a 2 dim array that looks like a table,
so the column names are in the first row,
then the data from the table is stored in each row*/
for (int i = 0; i < argc; i++)
{
if (num_rows == 1)
old[0][i] = *azColName[i];
old[num_rows][i] = *argv[i];
}
data = old;
return 0;
}
将数据插入数据库时,一切正常。但是当我尝试检索数据时,我得到了读取访问权限。 现在我的问题是,我采用我的方法是正确的,还是我错过了一些重要的要求?
答案 0 :(得分:0)
在sql_execQuery()
中,您将a
声明为char **
,并将其地址,&a
作为第四个参数传递给sqlite3_exec()
char ***
。因此,该参数具有类型callback()
,并且它指向程序堆栈中的某个位置。这没有什么本质上的错误。
然后我们到了data
,其中存在严重的问题,主要是:
char **
指针视为char ***
类型,而不是正确的类型char **old = *(char ***)data;
// ...
*(char ***)data = old;
。如果这是你唯一的问题,你可以这样解决:sizeof
它试图通过old
运算符计算分配空间的维数,如果char
实际上是一个2D数组,那么这是合理的,但 它根本不是一个数组 。它是指向sizeof(old)
的指针,因此char
是指针的大小(指向sizeof(old[0])
的指针),char
是指针的大小({ {1}})和sizeof(old[0][0])
是char
的大小。这并没有告诉您有关已分配多少空间的任何信息。
在为old
分配内存后,它会将已分配内存的各部分取消引用而不进行初始化,方法是将它们传递给realloc()
。通常,除了其中一个之外的所有部分都已初始化,但未初始化的部分会导致realloc()
表现出未定义的行为。
您未能检查分配错误。
看起来您需要将更复杂的数据结构传递给回调,以便您可以跟踪分配的维度。像这样的东西,例如:
struct mytable {
char **data;
size_t dim;
};
SQLCONTROL_API char** sql_execQuery(char *dbName, char *sqlStatement)
{
struct mytable a = { NULL, 0 };
// ...
int rc = sqlite3_exec(db, sqlStatement, callback, &a, &zErrMsg);
return a.data;
}
static int callback(void *data, int argc, char **argv, char **azColName)
{
struct mytable *old = data;
char **temp;
old->dim++;
temp = realloc(old->data, old->dim * sizeof(*old->data));
if (temp) {
old->data = temp;
old->data[old->dim - 1] = NULL;
} else {
// handle allocation error ...
}
for (int i = 0; i < old->dim; i++) {
char *temp2 = realloc(old->data[i], argc * sizeof(*old->data[i]));
if (temp2) {
old->data[i] = temp2;
old->data[i][argc - 1] = NULL;
} else {
// handle allocation error ...
}
}
// ... other stuff ...
// no need for anything like data = old
return 0;
}