我想使用类似于printf在C中执行的操作来存储格式化字符串。
char *tmp = (char *)sqlite3_column_text(selectstmt, 2);
const char *sqlAnswers = printf("select key from answer WHERE key = %s LIMIT 5;", tmp);
后者显然是一个错误。
答案 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。它使用内存而不删除它,因此您需要在使用后删除它。