Dynamically realloc 2 dim array in callback function of sqlite

邮差的信 提交于 2019-12-24 08:31:58

问题


I am working on a sqlite-.dll for educational purpose. I am trying to dynamically add a row in my 2 dimensional array for each time the callback function is called with a new row from the database. (e.g. SELECT * FROM CUSTOMER). The data stored in this array should then be returned as a C-Interface.

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;
}

With the callback function:

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;
}

When inserting data to the database, everything works fine. But when I try to retrieve data, I get read access violation. Now my question, am I on the right way with my approach or do I miss some important requirements for my intention?


回答1:


In your sql_execQuery(), you declare a as a char **, and you pass its address, &a, as the fourth argument of sqlite3_exec(). That argument therefore has type char ***, and it points to a location somewhere in the program's stack. There's nothing inherently wrong with that.

But then we get to callback(), which has serious problems, principal among them:

  • It treats the data pointer as if it were of type char **, instead of the correct type, char ***. If that were your only problem, you could fix it like this:
char **old = *(char ***)data;

// ...

*(char ***)data = old;
  • It tries to compute the dimensions of the allocated space via the sizeof operator, as would be reasonable if old were, in fact, a 2D array, but it is not an array at all. It is a pointer to pointer to char, so sizeof(old) is the size of a pointer (to pointer to char), sizeof(old[0]) is the size of a pointer (to char) and sizeof(old[0][0]) is the size of a char. This does not tell you anything about how much space has been allocated.

  • After allocating memory for old, it dereferences the parts of the allocated memory without initializing them, by passing them to realloc(). Generally, all but one of these will have been initialized, but the one uninitialized one causes realloc() to exhibit undefined behavior.

  • You fail to check for allocation errors.

It looks like you need a more complex data structure to be passed through to your callback, so that you can track the allocated dimensions. Something like this, for example:

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;
}


来源:https://stackoverflow.com/questions/40096266/dynamically-realloc-2-dim-array-in-callback-function-of-sqlite

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!