'\ 0' y printf () en C

21

En un curso introductorio de C, aprendí que mientras se almacenan las cadenas se almacenan con caracteres nulos \0al final. Pero, ¿y si quisiera imprimir una cadena? Digamos printf("hello")que he descubierto que no termina con la \0siguiente declaración

printf("%d", printf("hello"));

Output: 5

pero esto parece ser inconsistente, hasta donde sé que variables como cadenas se almacenan en la memoria principal y supongo que al imprimir algo también podría almacenarse en la memoria principal, entonces ¿por qué la diferencia?

Ajay Mishra
fuente
1
Además del hecho de que su código falla al menos );, ¿qué piensa mostrar con ese código? ¿Cómo has demostrado que no termina con un \0?
glglgl
¿Y qué tiene que ver la memoria en la que está almacenado?
Tsakiroglou Fotis
En C, todas las cadenas literales son realmente matrices de caracteres, que incluyen el terminador nulo.
Algún tipo programador
@glglgl Creo que printf () devuelve el número de caracteres que se supone que imprime en la pantalla.
Ajay Mishra
44
@AjayMishra Sí, y de hecho debería haber impreso 5 caracteres. El 0 byte final no se imprime en la pantalla.
glglgl

Respuestas:

13

El byte nulo marca el final de una cadena. No se cuenta en la longitud de la cadena y no se imprime cuando se imprime una cadena printf. Básicamente, el byte nulo le dice a las funciones que realizan la manipulación de cadenas cuándo detenerse.

Donde verá una diferencia es si crea una charmatriz inicializada con una cadena. El uso del sizeofoperador reflejará el tamaño de la matriz, incluido el byte nulo. Por ejemplo:

char str[] = "hello";
printf("len=%zu\n", strlen(str));     // prints 5
printf("size=%zu\n", sizeof(str));    // prints 6
dbush
fuente
Pensé que la historia sería diferente con printf(). TBH No tengo idea de cómo printf()funciona.
Ajay Mishra
8

printfDevuelve el número de caracteres impresos. '\0'no se imprime, solo indica que no hay más caracteres en esta cadena. Tampoco se cuenta hacia la longitud de la cuerda

int main()
{
    char string[] = "hello";

    printf("szieof(string) = %zu, strlen(string) = %zu\n", sizeof(string), strlen(string));
}

https://godbolt.org/z/wYn33e

sizeof(string) = 6, strlen(string) = 5
P__J__
fuente
6

Tu suposición es incorrecta. Su cadena de hecho termina con a \0.

Contiene de 5 caracteres h, e, l, l, oy el carácter 0.

Lo que print()genera la llamada "interna" es el número de caracteres que se imprimieron, y eso es 5.

glglgl
fuente
6

En C, todas las cadenas literales son realmente matrices de caracteres, que incluyen el terminador nulo.

Sin embargo, el terminador nulo no se cuenta en la longitud de una cadena (literal o no), y no se imprime. La impresión se detiene cuando se encuentra el terminador nulo.

Algún tipo programador
fuente
¿Hay alguna forma de verificar esto sin almacenar la cadena en una matriz?
Ajay Mishra
1
@AjayMishra Bueno, la cadena ya está en una matriz (como se mencionó) ... Pero si no hubiera un terminador nulo, printfsaldría de los límites de la cadena e imprimiría caracteres "aleatorios" o "basura", y devolvería un número diferente de la longitud de la cadena. Si ya conoce la longitud de la cadena, también puede verificar si el carácter en ese índice es '\0', lo que funcionará pero es un comportamiento técnicamente indefinido si el tamaño de la matriz no incluye el terminador (como en char arr[5] = "hello";, que no agregará el terminador de la matriz).
Algún tipo programador
@AjayMishra Sí E. g., Puede hacer char * p = "Hello"; int i = 0; while (p[i] != '\0') { printf("%d: %c", i, p[i]); i++; }y ver cómo se ejecuta: muestra líneas con índices y el contenido en esa línea. Después del índice 4, encuentra el carácter 0 y rompe el bucle while. Ahí ves que hay un carácter 0.
glglgl
6

Todas las respuestas son realmente buenas, pero me gustaría agregar otro ejemplo para completar todas estas

#include <stdio.h>

int main()
{
    char a_char_array[12] = "Hello world";

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

    a_char_array[4] = 0; //0 is ASCII for null terminator

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

    return 0;
}

Para aquellos que no quieren probar esto en gdb en línea, el resultado es:

Hola Mundo

Infierno

https://linux.die.net/man/3/printf

¿Es útil entender qué hace el terminador de escape? No es un límite para una matriz de caracteres o una cadena. Es el personaje que le dirá al tipo que analiza -STOP, (imprimir) analizar hasta aquí.

PD: Y si lo analizas e imprimes como una matriz de caracteres

for(i=0; i<12; i++)
{
    printf("%c", a_char_array[i]);
}
printf("\n");

usted obtiene:

Inframundo

donde, el espacio en blanco después del doble l, es el terminador nulo, sin embargo, al analizar una matriz de caracteres, solo se mostrará el valor de caracteres de cada byte. Si realiza otro análisis e imprime el valor int de cada byte ("% d%, char_array [i]), verá que (obtiene la representación ASCII code-int) el espacio en blanco tiene un valor de 0.

Tsakiroglou Fotis
fuente
4

En la Cfunción printf()devuelve el número de caracteres impresos, \0es un nullterminador que se usa para indicar el final de la cadena en lenguaje c y no hay ningún stringtipo incorporado a partir de c++, sin embargo, el tamaño de su matriz debe ser al menos mayor que el número charque desea Almacenar.

Aquí está la referencia: cpp ref printf ()

algun usuario
fuente
3

Pero, ¿y si quisiera imprimir una cadena? Diga printf ("hola") aunque he descubierto que no termina con \ 0 siguiendo la siguiente instrucción

printf("%d", printf("hello"));

Output: 5

Está usted equivocado. Esta declaración no confirma que el literal de cadena "hello"no termine con el carácter de terminación cero '\0'. Esta declaración confirmó que la función printfgenera elementos de una cadena hasta que se encuentra el carácter cero final.

Cuando usa un literal de cadena como en la declaración anterior, el compilador crea una matriz de caracteres con la duración del almacenamiento estático que contiene elementos del literal de cadena.

De hecho, esta expresión

printf("hello")

es procesado por el compilador algo como lo siguiente

static char string_literal_hello[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
printf( string_literal_hello );

La acción de la función printf en esto se puede imaginar de la siguiente manera

int printf( const char *string_literal )
{
    int result = 0;

    for ( ; *string_literal != '\0'; ++string_literal )
    {    
        putchar( *string_literal );
        ++result;
    }

    return result;
}

Para obtener el número de caracteres almacenados en la cadena literal "hola", puede ejecutar el siguiente programa

#include <stdio.h>

int main(void) 
{
    char literal[] = "hello";

    printf( "The size of the literal \"%s\" is %zu\n", literal, sizeof( literal ) );

    return 0;
}

La salida del programa es

The size of the literal "hello" is 6
Vlad de Moscú
fuente
0

Primero debe borrar su concepto. Como se borrará cuando trabaje con la matriz, el comando de impresión que está usando solo cuenta los caracteres que se colocan dentro de la parálisis. Es necesario en la cadena de matriz que terminará con \ 0

Muhammad Kashif
fuente
0

Una cadena es un vector de caracteres. Contiene la secuencia de caracteres que forman la cadena, seguida de la cadena especial de caracteres finales: '\ 0'

Ejemplo: char str [10] = {'H', 'e', ​​'l', 'l', 'o', '\ 0'};

Ejemplo: el siguiente vector de caracteres no es una cadena porque no termina con '\ 0'

char str [2] = {'h', 'e'};

Nicola Brogelli
fuente
No hay vectores en C, supongo.
Ajay Mishra