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



我正在制作一个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;
}

相关内容

  • 没有找到相关文章

最新更新