代码之家  ›  专栏  ›  技术社区  ›  Frank

如何将printf存储到变量中?

  •  17
  • Frank  · 技术社区  · 15 年前

    我想使用类似printf在c中所做的操作来存储格式化字符串。

    char *tmp = (char *)sqlite3_column_text(selectstmt, 2);
    const char *sqlAnswers = printf("select key from answer WHERE key = %s LIMIT 5;", tmp);
    

    后者显然是一个错误。

    6 回复  |  直到 7 年前
        1
  •  36
  •   Rodrigo    11 年前

    你可以用 sprintf 但不是孤军奋战。在健全的系统上,使用 snprintf 两次,一次找出要使用的尺寸,第二次实际使用。这取决于 SNPrTNF 返回空间不足时所需的字符数。Linux、BSD和C99兼容系统可以做到这一点;Windows通常不会。在后一种情况下,如果 SNPrTNF 失败(在循环中直到 SNPrTNF 成功了。但在C99上,以下功能将起作用:

    char *buf;
    size_t sz;
    sz = snprintf(NULL, 0, "select key from answer WHERE key = %s LIMIT 5;", tmp);
    buf = (char *)malloc(sz + 1); /* make sure you check for != NULL in real code */
    snprintf(buf, sz+1, "select key from answer WHERE key = %s LIMIT 5;", tmp);
    

    然而 ,对于构建SQL,最好使用 prepared statements . 它们避免了SQL注入漏洞(并且经常需要 把格式数据写成串 )使用它们,您将准备语句“select key from answer where key=?限制5;“,然后用参数执行 tmp . SQL引擎放入字符串,并消除了首先确保正确转义字符串的需要。

        2
  •  8
  •   Carl Norum    15 年前

    你想要 sprintf() .

    char *sqlAnswers = malloc(SIZE_TO_HOLD_FINAL_STRING);
    sprintf(sqlAnswers, "select key from answer WHERE key = %s LIMIT 5;", tmp);
    
        3
  •  7
  •   Scott Wales    15 年前

    如果您使用的是GNU或BSD libc,则可以使用 asprintf 自动分配正确大小的缓冲区。

    #define _GNU_SOURCE
    #include <stdio.h>
    // ...
    char *sqlAnswers = NULL;
    int length = asprintf(&sqlAnswers,"select key from answer WHERE key = %s LIMIT 5;", tmp);
    free(sqlAnswers);
    
        4
  •  1
  •   Frank    15 年前

    实际上,我使用sqlite3_bind_文本输入通配符,而不是通过sprintf生成:

    const char *sql1 = "select id, repA, key from iphone_reponse WHERE question_id = ?;";
    sqlite3_stmt *selectstmt1;
    if(sqlite3_prepare_v2(database, sql1, -1, &selectstmt1, NULL) == SQLITE_OK) {
        sqlite3_bind_text(selectstmt1, 1, [questionObj.key UTF8String], -1, SQLITE_TRANSIENT);
    
        5
  •  0
  •   rerun    15 年前

    在Windows上,您可以使用sprintf_,它添加了像michael e所说的缓冲区溢出保护。

    http://msdn.microsoft.com/en-us/library/ce3zzk1k(VS.80).aspx

        6
  •  0
  •   Rodrigo    11 年前

    这个 迈克尔·埃克斯特 代码很好,但您需要多次复制和粘贴它。我在一个函数中使用此代码

    char *storePrintf (const char *fmt, ...)
    {
        va_list arg;
        va_start(arg, fmt);
        size_t sz = snprintf(NULL, 0, fmt, arg);
        char *buf = (char *)malloc(sz + 1);
        vsprintf(buf, fmt, arg);
        va_end (arg);
        return buf;
    }
    

    缓冲区溢出有问题吗?到现在为止我对它没有意见。

    编辑。

    好吧,我有个问题,因为我在和阿杜尼奥一起工作。它使用的是内存,而不是丢弃它,所以在使用后需要删除它。