¿Cómo agregar cadenas usando sprintf?

5 minutos de lectura

avatar de usuario
usuario46646

Estoy enfrentando un problema serio con sprintf.

Supongamos que mi fragmento de código es:

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

Unos cien sprints….

Si me gusta esto, se sobrescribe.

¿Cómo puedo evitar sobrescribir usando sprintf? si doy un printf al final quiero ver todas las líneas.

  • No usaré sprintf sino snprintf, no usaré printf(str) sino printf(“%s”, str)

    – pa.

    20 de abril de 2010 a las 12:59

Necesitas:

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

y, por supuesto, necesita que su búfer sea lo suficientemente grande.

  • +1 aunque me gusta un poco más la solución de Aeth, parece un poco más eficiente que volver a calcular la longitud de la cadena cada vez.

    – extraneón

    20 de abril de 2010 a las 10:47

  • Un truco que he visto en este sentido es #define eos(s) ((s)+strlen(s)), o declarar una función si lo prefiere. Entonces puedes usar sprintf(eos(Buffer), "Stuff")

    – clstrfsck

    20 de abril de 2010 a las 10:47

  • Aún más simple, puedes usar sprintf(strchr(s, '\0'), "...").

    – Arto Bendiken

    29 de marzo de 2014 a las 12:48

  • ¿Para qué se agrega + strlen (Buffer) al Buffer real?

    – bretcj7

    17 de septiembre de 2016 a las 3:43

  • Esto es aritmética de punteros. Es como agregar la longitud actual de la cadena a la dirección de inicio del ‘Búfer’. Esta operación no es segura para mbs y cadenas Unicode. Como, por ejemplo, obtener la longitud de la cadena Unicode “Hola” devolvería 5, pero en realidad Búfer + 5 * tamaño de (wchar_t) se requiere en este caso

    – AB

    17 de febrero de 2017 a las 7:11

avatar de usuario
Mateo T. Staebler

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

Aquí hay una versión con cierta resistencia a los errores. Es útil si no le importa cuándo ocurren los errores, siempre y cuando pueda continuar felizmente cuando ocurran.

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"));

  • Pero, ¿qué sucede si sprintf experimenta un error de conversión?

    luego

    20 de abril de 2010 a las 10:52

  • Entonces tienes cosas malas que pasan. Omití la comprobación de errores en aras de la brevedad.

    –Matthew T. Staebler

    20 de abril de 2010 a las 11:21

  • +1: la verificación de errores adicional debería ser un ejercicio para el lector de todos modos. Después de todo, es sus código 🙂

    – Tim Publicar

    20 de abril de 2010 a las 12:28

  • Supongo que tiene sentido informar error y errono en caso de resultado negativo de sprintf.

    – Boris Ivánov

    23/10/2014 a las 14:32

avatar de usuario
Oleg Razgulyaev

Por seguridad (desbordamiento de búfer) recomiendo usar 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");

  • El segundo argumento de snprintf no está firmado (tamaño_t), lo que significa que si longitud > MAX_BUF, entonces MAX_BUF-longitud se desbordará y snprintf felizmente escribirá fuera del búfer creando un desbordamiento de búfer. Tenga en cuenta que el retorno de snprintf es igual a la cantidad de bytes que se habrían escrito si hubiera habido suficiente espacio disponible y NO la cantidad de bytes realmente escritos.

    – leszek.hanusz

    14 de diciembre de 2016 a las 17:18

A snprintfcat() envoltorio para 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;
}

Utilice el valor de retorno de sprintf()

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

  • Esta es la mejor solución, no hay necesidad de strlen

    – tttony

    1 de septiembre de 2018 a las 14:59

  • Tenga en cuenta que también debe guardar la dirección de inicio del búfer para futuras referencias.

    – bersanri

    30 de noviembre de 2018 a las 12:05

avatar de usuario
SergGr

¿Por qué quieres usar sprintf para la concatenación de cadenas cuando hay métodos destinados específicamente a lo que necesita, como strcat y strncat?

  • Esta es la mejor solución, no hay necesidad de strlen

    – tttony

    1 de septiembre de 2018 a las 14:59

  • Tenga en cuenta que también debe guardar la dirección de inicio del búfer para futuras referencias.

    – bersanri

    30 de noviembre de 2018 a las 12:05

creo que estas buscando 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;
}

Si el almacenamiento dinámico es más adecuado para su caso de uso, puede seguir la excelente sugerencia de Liam sobre el uso 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;
}

  • Esto es justo lo que estaba buscando. A sugerencia de man fmemopen, encontré que open_memstream era un poco más adecuado para mi aplicación. Ver el Manual de GNU para un ejemplo.

    – Liam

    1 de febrero de 2017 a las 3:59


  • @Liam increíble, gracias por el consejo sobre open_memstream. Agregué un ejemplo para eso también.

    – wkz

    1 de febrero de 2017 a las 17:22

  • Fantástico, excepto que tampoco fmemopen ni open_memstream están disponibles en Windows.

    – 7vujy0f0hy

    7 oct 2017 a las 13:10

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad