如何将printf存储到变量中?
我想使用类似于C中printf所做的事情来存储格式化的字符串。
char *tmp = (char *)sqlite3_column_text(selectstmt, 2); const char *sqlAnswers = printf("select key from answer WHERE key = %s LIMIT 5;", tmp);
后者显然是一个错误。
你可以用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 key where??limit 5;”,然后使用参数tmp
执行它。 SQL引擎放入字符串并消除了确保首先正确转义的需要。
你想要sprintf()
。
char *sqlAnswers = malloc(SIZE_TO_HOLD_FINAL_STRING); sprintf(sqlAnswers, "select key from answer WHERE key = %s LIMIT 5;", tmp);
如果你正在使用gnu或BSD libc,你可以使用asprintf
,它会自动分配一个正确大小的缓冲区。
#define _GNU_SOURCE #include // ... char *sqlAnswers = NULL; int length = asprintf(&sqlAnswers,"select key from answer WHERE key = %s LIMIT 5;", tmp); free(sqlAnswers);
我实际上使用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);
在Windows上你可以使用sprintf_s,它增加了像Michael E所说的缓冲区溢出保护。
http://msdn.microsoft.com/en-us/library/ce3zzk1k(VS.80).aspx
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。 它使用内存而不删除它,因此您需要在使用后删除它。