22

我想使用类似于 printf 在 C 中所做的事情来存储格式化的字符串。

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

后者显然是一个错误。

4

6 回答 6

41

你可以用 来做 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,使用准备好的语句要好得多。它们避免了 SQL 注入漏洞(并且经常需要sprintf. 使用它们,您将准备语句“select key from answer where key = ? limit 5;”,然后使用参数执行它tmp。SQL 引擎放入字符串并消除了确保首先正确转义它的需要。

于 2009-11-17T00:13:51.673 回答
9

你想要sprintf()

char *sqlAnswers = malloc(SIZE_TO_HOLD_FINAL_STRING);
sprintf(sqlAnswers, "select key from answer WHERE key = %s LIMIT 5;", tmp);
于 2009-11-17T00:07:57.330 回答
8

如果您使用的是 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);
于 2009-11-17T00:36:31.260 回答
2

我实际上是使用 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);
于 2009-12-09T20:14:49.070 回答
2

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。它使用内存并且不会丢弃它,因此您需要在使用后将其删除。

于 2013-09-20T04:53:20.497 回答
0

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

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

于 2009-11-17T01:33:32.293 回答