2010-04-20 2 views
46

У меня серьезная проблема с sprintf.Как добавить строки, используя sprintf?

Пусть мой фрагмент кода:

sprintf(Buffer,"Hello World"); 
sprintf(Buffer,"Good Morning"); 
sprintf(Buffer,"Good Afternoon"); 
. 
. 
. 

Некоторые сто Спринт ....

Если я, как это, его перезаписываются.

Как избежать перезаписи с помощью sprintf. Если я дам printf в конце, я хочу увидеть все строки.

+9

Я не буду использовать Sprintf но snprintf, я не буду использовать Е (НТР), но Е («% S», ул) –

ответ

75

Понадобится:

sprintf(Buffer,"Hello World"); 
sprintf(Buffer + strlen(Buffer),"Good Morning"); 
sprintf(Buffer + strlen(Buffer),"Good Afternoon"); 

и, конечно, вам нужен буфер, чтобы быть достаточно большим.

+0

буфер с достаточно большой ... я попробую. .. – user46646

+2

+1 хотя мне нравится решение Aeth немного лучше, кажется немного более эффективным, чем пересчет длины строки каждый раз. – extraneon

+5

Трюк, который я видел по этим строкам, это «#define eos (s) ((s) + strlen (s))» или объявить функцию, если хотите. Затем вы можете использовать 'sprintf (eos (Buffer),« Stuff »)' – msandiford

55
int length = 0; 
length += sprintf(Buffer+length, "Hello World"); 
length += sprintf(Buffer+length, "Good Morning"); 
length += sprintf(Buffer+length, "Good Afternoon"); 

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

int bytes_added(int result_of_sprintf) 
{ 
    return (result_of_sprintf > 0) ? result_of_sprintf : 0; 
} 

int length = 0; 
length += bytes_added(sprintf(Buffer+length, "Hello World")); 
length += bytes_added(sprintf(Buffer+length, "Good Morning")); 
length += bytes_added(sprintf(Buffer+length, "Good Afternoon")); 
+0

Но что произойдет, если sprintf испытает неудачу преобразования? – 2010-04-20 10:52:19

+2

Тогда у вас плохие вещи, которые происходят. Я пропустил проверку ошибок для краткости. –

+0

+1 - Дополнительная проверка ошибок должна быть упражнением для читателя в любом случае. В конце концов, его _their_ код :) –

7

Почему вы хотите использовать sprintf для конкатенации, когда существуют методы предназначены специально для того, что вам нужно, такие как strcat и strncat?

+11

Может быть, что примером был тривиальный случай, когда добавляются только строки. Проблема может быть расширена, чтобы включить случаи, когда вы добавляете другие типы форматированных данных, для которых 'strcat' не применяется. –

-4

насчет:

char s[100] = ""; 

sprintf(s, "%s%s", s, "s1"); 

sprintf(s, "%s%s", s, "s2"); 

sprintf(s, "%s%s", s, "s3"); 

printf("%s", s); 

Но принимать во внимание возможные ovewflows буфера!

+0

его не добавление .... – user46646

+3

Вероятно, это не безопасный способ использовать 's' в качестве источника для чтения, а также для адресата, для которого нужно записать. Я бы упомянул его на вызов 'strcpy (s, s)'. –

26

Для безопасности (переполнение буфера) Я рекомендую использовать snprintf()

 
const int MAX_BUF = 1000; 
char* Buffer = malloc(MAX_BUF); 

int length = 0; 
length += snprintf(Buffer+length, MAX_BUF-length, "Hello World"); 
length += snprintf(Buffer+length, MAX_BUF-length, "Good Morning"); 
length += snprintf(Buffer+length, MAX_BUF-length, "Good Afternoon"); 
+4

Второй аргумент snprintf является unsigned (size_t), это означает, что если length> MAX_BUF, то длина MAX_BUF будет underflow и snprintf будет радостно писать вне буфера, создавая переполнение буфера. Обратите внимание, что возврат snprintf равен числу байтов, которые были бы написаны, если бы было достаточно свободного места, а НЕ количество написанных байтов. –

3

Вы просто добавляя строковые литералы? Или вы собираетесь добавлять различные типы данных (ints, float и т. Д.)?

Это может быть проще абстрагироваться на это в свою собственную функцию (следующее предполагает C99):

#include <stdio.h> 
#include <stdarg.h> 
#include <string.h> 

int appendToStr(char *target, size_t targetSize, const char * restrict format, ...) 
{ 
    va_list args; 
    char temp[targetSize]; 
    int result; 

    va_start(args, format); 
    result = vsnprintf(temp, targetSize, format, args); 
    if (result != EOF) 
    { 
    if (strlen(temp) + strlen(target) > targetSize) 
    { 
     fprintf(stderr, "appendToStr: target buffer not large enough to hold additional string"); 
     return 0; 
    } 
    strcat(target, temp); 
    } 
    va_end(args); 
    return result; 
} 

И вы бы использовать его так:

char target[100] = {0}; 
... 
appendToStr(target, sizeof target, "%s %d %f\n", "This is a test", 42, 3.14159); 
appendToStr(target, sizeof target, "blah blah blah"); 

т.д.

Функция возвращает значение от vsprintf, которое в большинстве реализаций представляет собой количество байтов, записанных в пункт назначения. В этой реализации есть несколько явлений, но это должно дать вам некоторые идеи.

+0

Почему вы не помещаете цель sizeof внутри функции? Зачем вам это нужно в параметрах? –

+0

@hellomyfriends: поскольку функция 'target' является указателем на' char', а не массивом 'char', а' sizeof' будет возвращать только размер указателя, а не размер массива, который он указывает к. –

12

snprintfcat() обертка для snprintf():

size_t 
snprintfcat(
    char* buf, 
    size_t bufSize, 
    char const* fmt, 
    ...) 
{ 
    size_t result; 
    va_list args; 
    size_t len = strnlen(buf, bufSize); 

    va_start(args, fmt); 
    result = vsnprintf(buf + len, bufSize - len, fmt, args); 
    va_end(args); 

    return result + len; 
} 
4

Я нахожу следующий метод хорошо работает.

sprintf(Buffer,"Hello World"); 
sprintf(&Buffer[strlen[Buffer]],"Good Morning"); 
sprintf(&Buffer[strlen[Buffer]],"Good Afternoon"); 
+6

'[...]' around 'strlen'? Должно ли быть '(...)'? – CodyChan

+0

too much python: D – Niko

1

Вы можете использовать простую линию, показанную ниже, чтобы добавить строки в один буфер:

sprintf(Buffer,"%s %s %s","Hello World","Good Morning","Good Afternoon"); 
3

Я думаю, что вы ищете fmemopen(3):

#include <assert.h> 
#include <stdio.h> 

int main(void) 
{ 
    char buf[128] = { 0 }; 
    FILE *fp = fmemopen(buf, sizeof(buf), "w"); 

    assert(fp); 

    fprintf(fp, "Hello World!\n"); 
    fprintf(fp, "%s also work, of course.\n", "Format specifiers"); 
    fclose(fp); 

    puts(buf); 
    return 0; 
} 

Если динамическая память больше подходит для вас используется случай, вы можете следовать отличному предложению Лиама об использовании open_memstream(3):

#include <assert.h> 
#include <stdio.h> 
#include <stdlib.h> 

int main(void) 
{ 
    char *buf; 
    size_t size; 
    FILE *fp = open_memstream(&buf, &size); 

    assert(fp); 

    fprintf(fp, "Hello World!\n"); 
    fprintf(fp, "%s also work, of course.\n", "Format specifiers"); 
    fclose(fp); 

    puts(buf); 
    free(buf); 
    return 0; 
} 
+1

Это именно то, что я искал. По предложению человека fmemopen я нашел open_memstream немного более подходящим для моего приложения. См. [Руководство GNU] (https://www.gnu.org/software/libc/manual/html_node/String-Streams.html) для примера. – Liam

+0

@ Liam awesome, спасибо за отзыв о 'open_memstream'. Я также добавил пример. – wkz

+0

Фантастический, кроме как 'fmemopen' и' open_memstream' доступны в Windows. – 7vujy0f0hy

3

Используйте возвращаемое значение из sprintf()

Buffer += sprintf(Buffer,"Hello World"); 
Buffer += sprintf(Buffer,"Good Morning"); 
Buffer += sprintf(Buffer,"Good Afternoon"); 
-2

Использование strcat (buffer, "Your new string...here"), в качестве опции.

+0

Это дублирует более полный существующий ответ http://stackoverflow.com/a/40316229/874188 – tripleee

0

Я пишу функцию поддержки динамической переменной string append, например PHP str append: str. str. ... и т.д.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <stdarg.h> 

int str_append(char **json, const char *format, ...) 
{ 
    char *str = NULL; 
    char *old_json = NULL, *new_json = NULL; 

    va_list arg_ptr; 
    va_start(arg_ptr, format); 
    vasprintf(&str, format, arg_ptr); 

    // save old json 
    asprintf(&old_json, "%s", (*json == NULL ? "" : *json)); 

    // calloc new json memory 
    new_json = (char *)calloc(strlen(old_json) + strlen(str) + 1, sizeof(char)); 

    strcat(new_json, old_json); 
    strcat(new_json, str); 

    if (*json) free(*json); 
    *json = new_json; 

    free(old_json); 
    free(str); 

    return 0; 
} 

int main(int argc, char *argv[]) 
{ 
    char *json = NULL; 

    /* 
    str_append(&json, "name: %d, %d, %d", 1, 2, 3); 
    str_append(&json, "sex: %s", "male"); 
    str_append(&json, "end"); 
    str_append(&json, ""); 
    str_append(&json, "{\"ret\":true}"); 
    */ 

    int i; 
    for (i = 0; i < 100; i++) { 
     str_append(&json, "id-%d", i); 
    } 

    printf("%s\n", json); 

    if (json) free(json); 

    return 0; 
} 
Смежные вопросы