printf con %s para incluir caracteres nulos

5 minutos de lectura

Necesito concatenar algunas cadenas y necesito incluir bytes NULL. No quiero tratar un ‘\ 0’ como un byte de terminación. ¡Quiero guardar mis valiosos bytes NULL!

En un ejemplo de código, si

    char *a = "\0hey\0\0";

Necesito imprimir en un formato que genere “\0hey\0\0”.

-AUstin

  • ¿Cómo vas a calcular cuánto mide la cuerda?

    usuario2100815

    23 de mayo de 2011 a las 6:40

  • está predeterminado. He asignado espacio, digamos 8 bytes. quiero juntar algunas cadenas de varios tamaños dados, usando un printf(%s%s%s…)

    – austin

    23 de mayo de 2011 a las 6:44

  • Si la matriz tiene valores nulos incrustados, no es una cadena. No lo llames una cadena. Llámelo una matriz de caracteres (sin firmar) (con valores nulos incrustados). Como no es una cadena, no puede usar de manera confiable ninguna función de cadena en ese objeto: no "%s" conversión a printf (o scanf), no fputsno fgetsno strcpyno strcat

    – pmg

    23 de mayo de 2011 a las 11:05

Qué tal si:

int i;
for(i = 0; i < 4; i++)
    printf("%c", a[i]);

Si desea que una función ‘similar a printf’ use esto cuando especifique %s en una cadena de formato, podría incluir el código anterior en su propia función. Pero como mencionó @Neil, tendrá dificultades para encontrar una alternativa a la búsqueda de bytes nulos para determinar la longitud de las cadenas. Para eso, supongo que podrías usar algún tipo de personaje de escape.

  • ¿Por qué tomaría mucho código? ¿Es un bucle for trivial? Es difícil ver una alternativa a esto.

    –David Heffernan

    23 de mayo de 2011 a las 6:55

  • Digo mucho código porque hacer esto para 10 cadenas significa 10 bucles for. no es el fin del mundo, por supuesto. simplemente parece menos ideal, sin embargo, admito que no estoy trabajando con la situación más ideal

    – austin

    23 de mayo de 2011 a las 7:25

  • @austin – ¿No significa una función y diez llamadas?

    – Bo Person

    23 de mayo de 2011 a las 16:37

  • Recomiendo usar putchar() en lugar de printf() para esto. No es necesario formatear los caracteres, por lo que putchar() es mucho más eficiente.

    – Búho

    25 de agosto de 2016 a las 0:47

  • o que tal fwrite(a, 1, 4, stdout);. Eso es incluso mejor que putchar; no es necesario recorrer los bytes de uno en uno.

    – Peter Cordes

    3 de enero de 2019 a las 16:29

Avatar de usuario de Matty K
mateo k

El problema aquí es que la longitud de la cadena a no se puede determinar fácilmente. Por ejemplo, su código ..

char *a = "\0hey\0\0";

.. asigna siete bytes a la cadena, siendo el último el terminador NULL. Usando una función como strlen devolvería 0.

Si conoce la longitud precisa de la cadena, puede escribir o iterar sobre los bytes de la siguiente manera:

#ifdef ESCAPE_NULLS
    int i;
    for (i = 0; i <= 6; i++)
        if (a[i] == 0)
            printf("\\0");
        else
            printf("%c", a[i]);
#else
    write(1, a, 6);
#endif

Pero tienes que saber sobre el 6.

La alternativa es no usar cadenas terminadas en NULL y, en su lugar, implementar un mecanismo de almacenamiento alternativo para sus bytes; por ejemplo, una matriz codificada por longitud.

#include <stdio.h>

typedef struct {
    int length;
    char *bytes;
} bytearr;

void my_printf(bytearr *arr)
{
    #ifdef ESCAPE_NULLS
        int i;
        for (i = 0; i <= arr->length; i++)
            if (arr->bytes[i] == 0)
                printf("\\0");
            else
                printf("%c", arr->bytes[i]);
    #else
        write(1, arr->bytes, arr->length);
    #endif
}

void main(void)
{
    bytearr foo = {
        6, "\0hey\0\0"
    };
    my_printf(&foo);
}

Sin gracia, pero espero que entiendas la idea.

Editar: 2011-05-31

Al volver a leer la pregunta, acabo de notar la palabra “concatenar”. Si los caracteres NULL se van a copiar fielmente de un lugar de la memoria a otro (sin barra invertida de escape), y sabe el número total de bytes en cada matriz de antemano, simplemente puede usar memcpy.

#include <string.h>
char *a = "\0hey\0\0";   /*  6 */
char *b = "word\0up yo"; /* 10 */
char *c = "\0\0\0\0";    /*  4 */
void main(void)
{
    char z[20];
    char *zp = z;
    zp = memcpy(zp, a, 6);
    zp = memcpy(zp, b, 10);
    zp = memcpy(zp, c, 4);
    /* now z contains all 20 bytes, including 8 NULLs */
}

  • tiene una declaración if/else en la primera parte de su respuesta. ¿Esto implica que un printf(“%c”) en un byte NULL no funcionará?

    – austin

    23 de mayo de 2011 a las 7:28

  • Depende de si desea pasar fielmente el byte nulo a STDOUT, o si desea escapar de él (que fue como leí la pregunta original).

    – Matty K.

    26 mayo 2011 a las 14:40

  • @MattyK: No deberíawrite(1, a, 6);serwrite(1, a, sizeof(char)*6);?

    – usuario2284570

    21/10/2015 a las 13:00

  • Claro, si está escribiendo un código portátil adecuado. Es fácil ser perezoso y asumir sizeof(char)==1

    – Matty K.

    22 de octubre de 2015 a las 6:48

  • No mezcle POSIX write() con stdio printf. Utilizar fwrite. y no uses printf("%c" para bytes individuales, use putchar! O mejor, busca el siguiente 0 y use fwrite para todos los bytes distintos de cero con una llamada de función. O copiar y escapar en un búfer local y escribir eso. Y por cierto, memcpy no es strcat: memcpy devuelve su primer argumento sin modificar, no el fin de donde escribió. Entonces su actualización sobrescribe repetidamente el comienzo de z. Pero sí, memcpy es la herramienta adecuada para el trabajo, si usa el puntero de destino correcto.

    – Peter Cordes

    3 de enero de 2019 a las 16:27

char *a="\0hey\0\0";
int alen = 7;

char buf[20] = {0};
int bufSize = 20;

int i=0;
int j=0;
while( i<bufSize && j<alen )
{
    if(a[j]=='\0') {
        buf[i++]='\\';
        buf[i++]='0';
        j++;
    }
    else {
        buf[i++] = a[j++];
    }
}

printf(buf);

¿Ha sido útil esta solución?