在sqlite的回调函数中动态重新分配2个dim数组

我正在研究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; } 

将数据插入数据库时​​,一切正常。 但是当我尝试检索数据时,我得到了读取访问权限。 现在我的问题是,我采用我的方法是正确的方式还是我错过了一些重要的要求?

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]) sizeof(old[0])的大小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; }