我正在制作一个sqlite-.dll用于教育目的。我试图在我的二维数组中动态添加一行,每次回调函数都用数据库中的新行调用。(例如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;
}
在向数据库插入数据时,一切正常。但是当我试图检索数据时,我遇到了读访问冲突。现在我的问题是,我的方法是正确的还是我错过了一些重要的要求?
在您的sql_execQuery()
中,您将a
声明为char **
,并将其地址 &a
传递为sqlite3_exec()
的第四个参数。因此,该实参的类型为char ***
,它指向程序堆栈中的某个位置。这本身并没有什么错。
但是我们到了callback()
,它有严重的问题,其中主要是:
- 它将
data
指针视为char **
类型,而不是正确的char ***
类型。如果这是你唯一的问题,你可以这样修复它:
char **old = *(char ***)data;
// ...
*(char ***)data = old;
它试图通过
sizeof
运算符计算分配空间的维度,如果old
实际上是一个2D数组,这是合理的,但是它根本不是数组。它是一个指向char
的指针,所以sizeof(old)
是指向char
的指针的大小,sizeof(old[0])
是指向char
的指针的大小,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;
}