如何将printf存储到变量中?

时间:2009-11-17 00:07:03

标签: c string string-formatting

我想使用类似于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 个答案:

答案 0 :(得分:36)

您可以使用sprintf,但不能单独(安全)。在一个理智的系统上,使用snprintf两次,一次找出要使用的大小,第二次实际执行。这取决于snprintf返回空间不足时所需的字符数。 Linux,BSD和C99兼容系统可以做到这一点; Windows通常不会。在后一种情况下,如果snprintf失败(在snprintf成功之前的循环中),您将需要分配一个初始缓冲区并分配一个更大的缓冲区。但在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注入漏洞(并且经常需要sprintf)。使用它们,您将准备语句“select key from key where??limit 5;”,然后使用参数tmp执行它。 SQL引擎放入字符串并删除了确保首先正确转义的需要。

答案 1 :(得分:8)

您想要sprintf()

char *sqlAnswers = malloc(SIZE_TO_HOLD_FINAL_STRING);
sprintf(sqlAnswers, "select key from answer WHERE key = %s LIMIT 5;", tmp);

答案 2 :(得分:7)

如果你正在使用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);

答案 3 :(得分:1)

我实际上是使用sqlite3_bind_text来输入我的通配符而不是通过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);

答案 4 :(得分:0)

在Windows上,您可以使用sprintf_s,它可以像Michael E所说的那样增加缓冲区溢出保护。

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

答案 5 :(得分:0)

Michael Ekstrand 代码很好,但您需要多次复制和粘贴它。我在一个函数中使用此代码

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

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

编辑。

好的,我有一个问题,因为我正在使用Arduino。它使用内存而不删除它,因此您需要在使用后删除它。