'\ 0' e printf () em C

21

Em um curso introdutório de C, aprendi que, ao armazenar, as seqüências de caracteres são armazenadas com caractere nulo \0no final. Mas e se eu quisesse imprimir uma string, digamos, printf("hello")embora tenha descoberto que isso não termina com a \0seguinte declaração

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

Output: 5

mas isso parece ser inconsistente, até onde eu sei que variáveis ​​como seqüências de caracteres são armazenadas na memória principal e, ao imprimir algo, elas também podem ser armazenadas na memória principal, então por que a diferença?

Ajay Mishra
fonte
11
Além do fato de seu código faltar, pelo menos );, o que você pretende mostrar com esse código? Como você provou que não termina com a \0?
glglgl
E o que a memória está armazenada tem a ver com isso?
Tsakiroglou Fotis 07/02
Em C, todas as cadeias literais são realmente matrizes de caracteres, que incluem o terminador nulo.
Algum programador
@glglgl Acho que printf () retorna o número de caracteres que ele deve imprimir na tela.
Ajay Mishra
4
@AjayMishra Sim, e de fato deveria ter impresso 5 caracteres. O byte final de 0 bytes não é impresso na tela.
glglgl

Respostas:

13

O byte nulo marca o final de uma sequência. Não é contado no comprimento da sequência e não é impresso quando uma sequência é impressa printf. Basicamente, o byte nulo informa às funções que manipulam as strings quando parar.

Onde você verá uma diferença é se você criar uma charmatriz inicializada com uma string. O uso do sizeofoperador refletirá o tamanho da matriz, incluindo o byte nulo. Por exemplo:

char str[] = "hello";
printf("len=%zu\n", strlen(str));     // prints 5
printf("size=%zu\n", sizeof(str));    // prints 6
dbush
fonte
Eu pensei que a história seria diferente printf(). TBH Eu não tenho idéia de como printf()funciona.
Ajay Mishra
8

printfretorna o número de caracteres impressos. '\0'não é impresso - apenas sinaliza que não há mais caracteres nessa string. Também não é contado no comprimento da corda

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__
fonte
6

Sua suposição está errada. Sua string realmente termina com um\0 .

Ele contém de 5 caracteres h, e, l,l , oe 0 caráter.

O que a print()chamada "interna" gera é o número de caracteres que foram impressos, e são 5.

glglgl
fonte
6

Em C, todas as cadeias literais são realmente matrizes de caracteres, que incluem o terminador nulo.

No entanto, o terminador nulo não é contado no comprimento de uma sequência (literal ou não) e não é impresso. A impressão para quando o terminador nulo é encontrado.

Algum cara programador
fonte
Existe alguma maneira de verificar isso sem armazenar a seqüência de caracteres em uma matriz?
Ajay Mishra
11
@AjayMishra Bem, a string já está em uma matriz (como mencionado) ... Mas se não houvesse um terminador nulo, printfela sairia dos limites da string e imprimiria caracteres "aleatórios" ou "lixo" e retornaria um número diferente do comprimento da string. Se você já conhece o comprimento da string, também pode verificar se o caractere nesse índice é '\0', o que funcionará, mas é um comportamento tecnicamente indefinido se o tamanho da matriz não incluir o terminador (como em char arr[5] = "hello";, que não adicionará o terminador para a matriz).
Algum programador
@AjayMishra Sim Por exemplo, você pode fazer char * p = "Hello"; int i = 0; while (p[i] != '\0') { printf("%d: %c", i, p[i]); i++; }e ver como é executado: mostra linhas com índices e o conteúdo nessa linha. Após o índice 4, ele encontra o caractere 0 e interrompe o loop while. Lá você vê que existe um caractere 0.
glglgl
6

Todas as respostas são realmente boas, mas eu gostaria de adicionar outro exemplo para concluir todas essas

#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 aqueles que não querem tentar isso no gdb online, a saída é:

Olá Mundo

Inferno

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

Isso é útil para entender o que o terminador de escape faz? Não é um limite para uma matriz de caracteres ou uma string. É o personagem que dirá ao cara que analisa -STOP, (print) analisa até aqui.

PS: E se você analisar e imprimi-lo como uma matriz de caracteres

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

você obtém:

Mundo infernal

onde, o espaço em branco após o dobro l, é o terminador nulo, no entanto, ao analisar uma matriz de caracteres, será apenas o valor de caracteres de cada byte. Se você fizer outra análise e imprimir o valor int de cada byte ("% d%, char_array [i]), verá que (você obtém a representação ASCII code-int) o espaço em branco tem um valor 0.

Tsakiroglou Fotis
fonte
4

A Cfunção In printf()retorna o número de caracteres impressos, \0é um nullterminador usado para indicar o final da string no idioma c e não existe um stringtipo incorporado a partir de c++, no entanto, o tamanho da sua matriz precisa ser pelo menos maior do que o número chardesejado armazenar.

Aqui está o ref: cpp ref printf ()

algum usuário
fonte
3

Mas e se eu quisesse imprimir uma string, diga printf ("olá"), embora eu descubra que ela não termina com \ 0 seguindo a instrução

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

Output: 5

Você está errado. Esta instrução não confirma que a literal da cadeia de caracteres "hello"não termina com o caractere zero final '\0'. Esta declaração confirmou que a função printfgera elementos de uma sequência até que o caractere zero final seja encontrado.

Quando você está usando uma literal de cadeia de caracteres, como na instrução acima, o compilador cria uma matriz de caracteres com a duração do armazenamento estático que contém elementos da literal de cadeia de caracteres.

Então, de fato, essa expressão

printf("hello")

é processado pelo compilador, algo como o seguinte

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

A ação da função printf nisto você pode imaginar da seguinte maneira

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

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

    return result;
}

Para obter o número de caracteres armazenados na string literal "olá", você pode executar o seguinte 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;
}

A saída do programa é

The size of the literal "hello" is 6
Vlad de Moscou
fonte
0

Você precisa limpar seu conceito primeiro. Como será limpo quando você lida com a matriz, o comando de impressão que você está usando apenas conta os caracteres que são colocados dentro da parêntese. É necessário na string de matriz que termine com \ 0

Muhammad Kashif
fonte
0

Uma string é um vetor de caracteres. Contém a sequência de caracteres que formam a sequência, seguida pela sequência final de caracteres especial: '\ 0'

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

Exemplo: o seguinte vetor de caracteres não é uma sequência porque não termina com '\ 0'

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

Nicola Brogelli
fonte
Não há vetores em C, eu acho.
Ajay Mishra