【问题标题】:SQLite in C/C++. sqlite3_exec: parameter set in callback function is pointing to an empty stringC/C++ 中的 SQLite。 sqlite3_exec:回调函数中设置的参数指向一个空字符串
【发布时间】:2012-10-20 00:45:57
【问题描述】:

我正在尝试一些非常基本的东西 - 使用 C/C++ interface for SQLite 返回 SELECT 语句的结果。我的数据表只有两个字段 - 键(varchar)和值(文本)。

给定键,我的目标是通过查询 SQLite 数据库返回值。我传递给 *sqlite3_exec* - *select_callback* 函数以及 param (char *)。 param 已成功设置为 *select_callback* 中的正确值。但是,在调用 *sqlite3_exec* 之后,参数指向一个空字符串(尽管指向相同的内存)。

知道出了什么问题以及如何解决这个问题吗? *sqlite3_exec* 是​​否在幕后为 param 释放内存?

提前谢谢你!

// given the key tid returns the value
void getTypeByID(sqlite3 * db, string tid)
{
    string sql_exp_base = "select value from Data where key=''";
    int len = (int)sql_exp_base.size() + (int)tid.size() + 10;
    char * sql_exp = new char[len];
    sprintf(sql_exp, "select value from Data where key='%s'", tid.data());
    sql_exec(db, sql_exp);
}

// This is the callback function to set the param to the value
static int select_callback(void * param, int argc, char **argv, char **azColName)
{
    if(argc == 0) return 0;
    char * res = (char *)param;
    res = (char *) realloc(res, sizeof(*res));
    res = (char *) malloc(strlen(argv[0]) + 1);
    strcpy(res, argv[0]);
    printf("%s\n", res); // {"name": "Instagram Photo", url: "http://instagram.com"}
    return 0;
}

// execute the SQL statement specified by sql_statement
void sql_exec(sqlite3 * db, const char * sql_statement)
{
    char * zErrMsg = 0;
    char * param = (char *)calloc(1, sizeof(*param));
    int rc = sqlite3_exec(db, sql_statement, select_callback, param, &zErrMsg);
     printf("%s\n", param);

参数应该是 {"name": "Instagram Photo", url: "http://instagram.com"},但由于某种原因它是空字符串!

    if(rc != SQLITE_OK)
    {
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }
}

【问题讨论】:

  • sizeof(*res) 是什么意思?!这是一个编译时求值的表达式,等于 1。
  • 我假设您使用的是 C。因此,我删除了 C++ 标签,这不是您使用的语言。

标签: c sqlite pointers void-pointers


【解决方案1】:

您正在将指向新分配内存的指针写入res,但该变量是select_callback 内部的局部变量,因此sql_exec 不会知道它。 param 参数也是如此:它只是 sqlite3_exec 的第四个参数的副本。

为了确保看到您对字符串的更改,您必须传递一个指向字符串本身的指针(它是 C 中的指针,或者可能是 C++ 中的 string 对象),类似于错误消息。 对于 C:

char *result_str = ...;
rc = sqlite3_exec(..., &result_str, ...);
...
int callback(void *param, ...)
{
    char **result_str = (char **)param;
    *result_str = (char *)realloc(*result_str, ...);
    strcpy(*result_str, ...);
}

注意:tid 字符串包含引号或其他控制字符,或者当您尝试搜索Bobby Tables 时,您会遇到问题。 使用sqlite3_mprintf来格式化和分配SQL字符串,或者更好的使用parameters

【讨论】:

    【解决方案2】:

    我尝试了最后一个答案,它对我有用: 我创建了一个指向指针的指针作为 char 值,并从 void 变量中插入指针的指针

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sqlite3.h>
    
    
    int callback(void *data,int argc,char *argv[],char **azcolname) {
    int i=0;
    
    char **result_str = (char **)data;
    *result_str = (char *)calloc(strlen(argv[0]),sizeof(char));
    strcpy(*result_str,argv[0]);
    return 0;
    }
    
        int main(int argc,char *argv[]) {
    
    sqlite3 *conn;
    int c=0;
    char *ofile=NULL;
    char *tsql_stmt=NULL;
    int res=0;
    char *zErrMsg = 0;
    char *data=NULL;
    
    
    while((c = getopt(argc , argv ,"f:")) != -1) 
    {
        switch (c) {
    
            case 'f':
                ofile = optarg;
            break;
    
            default:
                fprintf(stderr,"worng argument provided\n");
            break;
    
        }
    }
    
    if (!ofile) {
        fprintf(stderr,"no output file (-f) given\n");
        exit(1);
    }
    sqlite3_open(ofile,&conn);
    tsql_stmt = calloc(80,sizeof(char));
    strcpy(tsql_stmt,"SELECT count(*) FROM sqlite_master WHERE type='table' AND name='");
        strcat(tsql_stmt,"mytest");
        strcat(tsql_stmt,"\'");
    
        //running the query
    //printf("%s\n",tsql_stmt);
    res = sqlite3_exec(conn,tsql_stmt,callback,&data, &zErrMsg);
    
    if ( res != SQLITE_OK ) {
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }
    else{
        if ( atoi(data) != 1)
            fprintf(stderr, "unable to find the requested table\n");
        else
            printf("the Operation found the requested table in the database\n");
    }
    
    free(data);
    sqlite3_close(conn);
    return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-08
      • 1970-01-01
      • 1970-01-01
      • 2013-03-31
      • 2018-03-14
      相关资源
      最近更新 更多