【问题标题】:Dynamically realloc 2 dim array in callback function of sqlite在 sqlite 的回调函数中动态重新分配 2 暗淡数组
【发布时间】:2017-02-27 00:29:24
【问题描述】:

我正在开发一个用于教育目的的 sqlite-.dll。 每次使用数据库中的新行调用回调函数时,我都尝试在二维数组中动态添加一行。 (例如,从客户那里选择 *)。 然后应将存储在此数组中的数据作为 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;
}

将数据插入数据库时​​,一切正常。但是当我尝试检索数据时,我会遇到读取访问冲突。 现在我的问题是,我的方法是否正确,还是我错过了一些重要的意图要求?

【问题讨论】:

  • 你为什么要使用sqlite3_exec()而不是光标界面?
  • @CL。由于sqlite3_exec() 是一个包装函数,我认为我会比实现每个步骤获得更好更快的编码结果。

标签: c arrays sqlite multidimensional-array realloc


【解决方案1】:

在您的sql_execQuery() 中,您将a 声明为char **,并将其地址 &amp;a 作为sqlite3_exec() 的第四个参数传递。因此,该参数的类型为char ***,它指向程序堆栈中某处的位置。这本身并没有错。

然后我们到达callback(),它有严重的问题,其中主要是:

  • 它将data 指针视为char ** 类型,而不是正确的类型char ***。如果这是您唯一的问题,您可以这样解决:
char **old = *(char ***)data;

// ...

*(char ***)data = old;
  • 它尝试通过sizeof 运算符计算分配空间的尺寸,如果old 实际上是一个二维数组,这将是合理的,但它不是一个数组。它是指向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;
}

【讨论】:

  • 感谢您的回答。在您的帮助下,我获得了每列的第一个字符。我试图从char** argv 数组中获取完整的char* 字符串。我需要一个 3d 数组,比如char ***temp 吗?
  • @Strizzi,根据您修改后的代码,这听起来像是一个单独的问题。
  • 我创建了一个new question
猜你喜欢
  • 1970-01-01
  • 2012-12-15
  • 1970-01-01
  • 1970-01-01
  • 2015-11-07
  • 1970-01-01
  • 2020-12-29
  • 2011-05-31
  • 2019-05-02
相关资源
最近更新 更多