как сохранить printf в переменную? - PullRequest
17 голосов
/ 17 ноября 2009

Я хочу сохранить отформатированную строку, используя нечто похожее на то, что 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 ]

36 голосов
/ 17 ноября 2009

Вы можете сделать это с 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). С их помощью вы подготовите оператор «выберите ключ из ответа, где ключ =? Limit 5;», а затем выполните его с параметром tmp. Механизм SQL вставляет строку и избавляет от необходимости сначала проверять ее правильность.

8 голосов
/ 17 ноября 2009

Вы хотите sprintf().

char *sqlAnswers = malloc(SIZE_TO_HOLD_FINAL_STRING);
sprintf(sqlAnswers, "select key from answer WHERE key = %s LIMIT 5;", tmp);
7 голосов
/ 17 ноября 2009

Если вы используете 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);
1 голос
/ 09 декабря 2009

Я на самом деле использую 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);
0 голосов
/ 20 сентября 2013

Код 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. Он использует память и не удаляет ее, поэтому вам нужно удалить ее после использования.

0 голосов
/ 17 ноября 2009

В Windows вы можете использовать sprintf_s, который добавляет защиту от переполнения буфера, как говорил Майкл Е.

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

...