как сохранить 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);

последнего-явная ошибка.

6 ответов


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


вы хотите 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 <stdio.h>
// ...
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, который добавляет защиту от переполнения буфера, как говорил Майкл Е.

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


на Майкл Экстранд код хорош, но вам нужно будет скопировать и вставить его в разное время. Я использую этот код в одной функции

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