Как хранить printf в переменной?

Я хочу сохранить форматированную строку, используя что-то похожее на то, что printf делает в C.

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

Последнее, очевидно, является ошибкой.

Ответы

Ответ 1

Вы можете сделать это с помощью 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 помещает в строку и устраняет необходимость убедиться, что он сначала экранирован.

Ответ 2

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

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

Ответ 3

Если вы используете 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);

Ответ 4

Я фактически использую 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);

Ответ 6

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