C Strings

Nome de cliente, item da lista de compras, mensagem na tela: quase todo programa trabalha com texto. Em programação, um texto se chama string (em inglês, "fio", "cordão": um cordão de letras). Muitas linguagens têm um tipo pronto para texto. O C não tem: em C, uma string é só um array de char com uma marca de fim, o caractere '\0'. Parece pouco, e é. Por isso esta aula é tão importante: quase todos os erros com texto em C nascem de esquecer como essa marca funciona.

Você vai aprender
  • O que é uma string em C: um array de char terminado em '\0'.
  • Por que char nome[] = "Ana"; ocupa 4 bytes, e como é o desenho dela na memória.
  • Como mostrar uma string com %s, percorrer letra por letra e cortar o texto com um '\0'.
  • As formas de criar uma string, e o aviso novo do gcc 15 quando falta espaço para o '\0'.
  • O que acontece quando o '\0' falta (o programa mostra o que não devia).
  • Três erros clássicos: comparar com ==, atribuir com = e alterar um literal.

Todos os programas desta aula foram compilados com o gcc 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/c, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -o programa (cada opção é explicada em Compilar com gcc). Antes desta aula, é bom ter visto Caracteres (char) e Arrays: uma string junta as duas coisas.


A ideia: uma fila de cadeiras com a placa "FIM"

Imagine uma fileira de cadeiras numeradas num auditório: cadeira 0, 1, 2, 3… Em cada cadeira senta uma letra. Quem chega para ler o nome não sabe quantas letras são; ele vai lendo cadeira por cadeira até encontrar uma cadeira com a placa "FIM".

Uma string em C é exatamente isso:

  • as cadeiras são os elementos de um array de char (cada um guarda um caractere, 1 byte);
  • a placa "FIM" é o caractere '\0', chamado caractere nulo (em inglês, null character ou NUL). Ele é o número 0 guardado num char.

O array não guarda o tamanho do texto em lugar nenhum. Toda função que trabalha com strings (o printf com %s, o strlen, o strcpy…) faz o que o leitor da fileira faz: anda até achar o '\0'. Se a placa não estiver lá, ela continua andando, para dentro de cadeiras que não são suas.


1. A primeira string

#include <stdio.h>

int main(void) {
    char nome[] = "Ana";
    printf("Olá, %s!\n", nome);
    printf("O array nome ocupa %zu bytes.\n", sizeof nome);
    return 0;
}
char
O tipo de cada elemento: um caractere (1 byte).
nome[]
Um array chamado nome. Os colchetes vazios pedem ao compilador: "conte você quantos elementos são necessários".
= "Ana"
Um texto entre aspas duplas é um literal de string (o texto escrito "literalmente" no código). Ele copia as letras A, n, a para dentro do array e coloca um '\0' no fim, sozinho.
%s
O formato do printf para strings (s de string). O printf mostra os caracteres a partir do começo do array até achar o '\0'; o '\0' não é mostrado.
printf("…", nome)
Repare: sem & e sem colchetes. Passa-se o array inteiro, pelo nome (o motivo está em Ponteiros e Arrays).
sizeof nome
Quantos bytes o array ocupa (aula Tamanho dos Tipos). O %zu é o formato do resultado de sizeof.
$ gcc -std=c23 -Wall -Wextra nome.c -o nome
$ ./nome
Olá, Ana!
O array nome ocupa 4 bytes.     « 3 letras + o '\0'

"Ana" tem três letras, mas o array tem quatro bytes. O quarto é a placa de fim. Guarde esta regra, que vale para toda string em C: espaço necessário = número de caracteres + 1.


2. O desenho da memória

Vamos olhar cada cadeira da fileira. Como uma string é um array, cada caractere tem um índice, começando em 0. O formato %c mostra o caractere e o %d mostra o número que o computador guarda de verdade (o código da tabela ASCII, visto em Caracteres):

#include <stdio.h>

int main(void) {
    char nome[] = "Ana";
    for (int i = 0; i < 4; i++) {
        printf("nome[%d] = '%c'  código %d\n", i, nome[i], nome[i]);
    }
    return 0;
}
$ gcc -std=c23 -Wall -Wextra bytes.c -o bytes
$ ./bytes
nome[0] = 'A'  código 65
nome[1] = 'n'  código 110
nome[2] = 'a'  código 97
nome[3] = ''  código 0     « o '\0' não tem desenho: o terminal não mostra nada

Desenhando a memória do array nome, byte por byte:

Índice[0][1][2][3]
Caractere'A''n''a''\0'
Número guardado65110970
'\0' não é '0'

A barra invertida muda tudo. '\0' é o caractere de código 0, a placa de fim. Já '0' (sem barra) é o dígito zero, que aparece na tela, e tem código 48. A string "10" guarda os números 49, 48 e 0. A barra invertida é a mesma das sequências de escape como \n (aula Novas Linhas e Escapes).

Experimente: troque "Ana" pelo seu nome sem acentos (por exemplo "Bruno"). Mude também o 4 do for para o número de letras + 1 e veja o sizeof mudar junto. (Nomes com acento ocupam mais bytes do que letras: isso é assunto de Acentos e UTF-8.)

#include <stdio.h>

int main(void) {
    char nome[] = "Ana";
    printf("%s ocupa %zu bytes\n", nome, sizeof nome);
    for (int i = 0; i < 4; i++) {
        printf("nome[%d] = código %d\n", i, nome[i]);
    }
    return 0;
}

3. Formas de criar uma string

Há várias escritas. Todas abaixo criam arrays de char com um '\0' no fim:

#include <stdio.h>

int main(void) {
    char a[] = "Ana";
    char b[10] = "Ana";
    char c[] = {'A', 'n', 'a', '\0'};
    char d[] = "";
    printf("a = %s, %zu bytes\n", a, sizeof a);
    printf("b = %s, %zu bytes\n", b, sizeof b);
    printf("c = %s, %zu bytes\n", c, sizeof c);
    printf("d = [%s], %zu byte\n", d, sizeof d);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra formas.c -o formas
$ ./formas
a = Ana, 4 bytes
b = Ana, 10 bytes
c = Ana, 4 bytes
d = [], 1 byte
char a[] = "Ana";
O compilador conta: 3 letras + '\0' = 4 bytes. É a forma mais comum quando o texto não vai crescer.
char b[10] = "Ana";
Você escolhe o tamanho: 10 bytes. O texto ocupa os 4 primeiros e o resto é preenchido com zeros. Use quando o texto pode mudar depois e precisar de mais espaço (um nome que o usuário vai digitar, por exemplo).
char c[] = {'A', 'n', 'a', '\0'};
Caractere por caractere, como qualquer array. Aqui o '\0' não é automático: você tem de escrevê-lo. Ninguém escreve strings assim no dia a dia; serve para mostrar o que as aspas fazem por você.
char d[] = "";
A string vazia: nenhuma letra, mas 1 byte, o '\0'. Os colchetes [%s] no printf só servem para ver que não há nada entre eles.

Para confirmar que o resto do b é zero, veja todos os bytes de um array de 8:

$ cat resto.c
#include <stdio.h>

int main(void) {
    char b[8] = "Ana";
    for (int i = 0; i < 8; i++) {
        printf("%d ", b[i]);
    }
    printf("\n");
    return 0;
}
$ gcc -std=c23 -Wall -Wextra resto.c -o resto
$ ./resto
65 110 97 0 0 0 0 0      « A, n, a e cinco zeros

Faltou espaço para o '\0': o aviso novo do gcc 15

Se você escolhe um tamanho que só cabe as letras, o C aceita: ele copia as letras e simplesmente não coloca o '\0'. O resultado não é uma string, e sim só um array de letras sem placa de fim. Desde a versão 15, o gcc avisa (com -Wextra):

#include <stdio.h>

int main(void) {
    char nome[3] = "Ana";
    printf("%s\n", nome);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra curto.c -o curto
curto.c: In function ‘main’:
curto.c:4:20: warning: initializer-string for array of ‘char’ truncates NUL terminator but destination lacks ‘nonstring’ attribute (4 chars into 3 available) [-Wunterminated-string-initialization]
    4 |     char nome[3] = "Ana";
      |                    ^~~~~
$ ./curto
Ana                      « saiu certo por sorte (veja a seção 7)
initializer-string for array of ‘char’
"O texto que inicializa o array de char…"
truncates NUL terminator
"…corta o terminador NUL": o '\0' ficou de fora.
(4 chars into 3 available)
"4 caracteres em 3 lugares disponíveis": o texto precisa de 4 bytes (contando o '\0') e o array tem 3.
destination lacks ‘nonstring’ attribute
"O destino não tem o atributo nonstring". Esse atributo existe para o raro caso em que você quer um array de letras sem '\0'. Para você, a mensagem quer dizer: "aumente o array".

Versões antigas do gcc não avisavam nada, e muito código antigo tem esse defeito escondido. O conserto: char nome[4] ou, melhor, char nome[] (deixe o compilador contar). O Clang do editor avisa a mesma coisa com outras palavras: initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character).

Qual usar

FormaQuando usar
char s[] = "texto";Texto fixo, que você só vai ler ou mudar letra por letra sem aumentar.
char s[50] = "texto";Texto que pode ser trocado por outro maior depois (até 49 letras + '\0').
char s[50] = "";Espaço vazio e limpo para receber um texto depois (do teclado, de um arquivo).
char s[] = {'o', 'i', '\0'};Quase nunca. Só para entender a memória.
char s[3] = "Ana";Nunca: falta o '\0'.

4. Percorrer até o '\0'

Se a string não sabe o próprio tamanho, como contar as letras? Fazendo o que o printf faz: andar pelo array até achar o '\0'.

#include <stdio.h>

int main(void) {
    char nome[] = "Mariana";
    int i = 0;
    while (nome[i] != '\0') {
        printf("%c-", nome[i]);
        i++;
    }
    printf("\n%s tem %d letras.\n", nome, i);
    return 0;
}
int i = 0;
Começa na cadeira 0.
while (nome[i] != '\0')
"Enquanto o caractere da posição i não for a placa de fim…" (aula while). Muita gente escreve só while (nome[i]): como o '\0' vale 0, e 0 é "falso" em C, dá no mesmo.
printf("%c-", nome[i]);
Mostra uma letra e um tracinho.
i++;
Vai para a próxima cadeira. Quando o laço termina, i é a posição do '\0', que é igual ao número de letras.
$ gcc -std=c23 -Wall -Wextra percorre.c -o percorre
$ ./percorre
M-a-r-i-a-n-a-
Mariana tem 7 letras.

Contar letras é tão comum que já existe uma função pronta, a strlen, que faz exatamente esse laço. Ela é a primeira da próxima aula, Funções de String. Mas agora você sabe o que ela faz por dentro, e por que ela fica mais lenta quanto maior o texto: ela precisa andar até o fim toda vez.

Mudar uma letra

Como a string é um array, cada letra pode ser trocada pelo índice, com um char entre aspas simples:

Missão: sem criar outro array, troque as letras de nome, uma por uma, para o programa mostrar Agora: Bia. Dica: nome[0] = 'B'; troca a primeira. Quais posições ainda precisam mudar?

#include <stdio.h>

int main(void) {
    char nome[] = "Ana";
    printf("Antes: %s\n", nome);
    // troque as letras aqui

    printf("Agora: %s\n", nome);
    return 0;
}
#include <stdio.h>

int main(void) {
    char nome[] = "Ana";
    printf("Antes: %s\n", nome);
    nome[0] = 'B';
    nome[1] = 'i';
    nome[2] = 'a';
    printf("Agora: %s\n", nome);
    return 0;
}

"Ana" e "Bia" têm o mesmo tamanho, então coube. Para trocar por um nome maior, o array precisa ter espaço sobrando (como o char b[10] da seção 3) e o jeito prático é uma função de cópia, vista em Funções de String.


5. Cortar uma string com um '\0'

Já que as funções param no primeiro '\0', colocar um '\0' no meio encurta o texto. As letras de depois continuam na memória, mas ninguém mais as lê:

#include <stdio.h>

int main(void) {
    char nome[] = "Ana Maria";
    printf("Antes: %s\n", nome);
    nome[3] = '\0';
    printf("Depois: %s\n", nome);
    printf("O array continua com %zu bytes.\n", sizeof nome);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra cortar.c -o cortar
$ ./cortar
Antes: Ana Maria
Depois: Ana
O array continua com 10 bytes.

A posição 3 era o espaço entre "Ana" e "Maria". Agora o array guarda A n a \0 M a r i a \0: duas placas de fim, e a primeira é a que vale. O sizeof não mudou, porque ele mede o array (o tamanho da fileira), não o texto (até a placa). Essa diferença entre "tamanho do array" e "tamanho do texto" vai aparecer o tempo todo. Você vai usar esse truque, por exemplo, para tirar o \n que vem no fim de uma linha lida com fgets.


6. Ler uma palavra do teclado

O scanf (aula Entrada com scanf) também lê strings com %s. Ele precisa de um array com espaço suficiente, e você deve dizer o limite:

#include <stdio.h>

int main(void) {
    char nome[20];
    printf("Seu nome: ");
    if (scanf("%19s", nome) != 1) {
        return 1;
    }
    printf("Olá, %s!\n", nome);
    return 0;
}
char nome[20];
Espaço para até 19 letras + o '\0'. Não precisa de valor inicial: o scanf vai escrever o texto e o '\0'.
%19s
"Leia uma palavra de no máximo 19 caracteres". O número é sempre o tamanho do array menos 1, para sobrar lugar para o '\0'. Sem ele, um texto comprido escreveria além do fim do array.
nome (sem &)
Diferente do scanf("%d", &idade), a string vai sem &: o nome do array já diz onde ele está na memória.
!= 1
O scanf devolve quantos itens leu. Se não leu nenhum (a entrada acabou), o programa para.
$ gcc -std=c23 -Wall -Wextra palavra.c -o palavra
$ echo "Ana Maria" | ./palavra
Seu nome: Olá, Ana!                 « %s para no primeiro espaço
$ echo "Maximiliano_de_Albuquerque" | ./palavra
Seu nome: Olá, Maximiliano_de_Albu!  « o %19s cortou em 19 letras

O echo … | manda o texto como se fosse digitado (por isso a resposta aparece na mesma linha da pergunta). O %s lê só uma palavra: para no primeiro espaço. Para ler uma linha inteira, com espaços, o jeito certo é o fgets, aula Ler uma Linha.


7. Quando o '\0' falta

Agora o erro mais perigoso das strings em C. Aqui o array nome foi criado letra por letra e sem '\0'. Logo ao lado, na memória, está a senha do sistema:

#include <stdio.h>

int main(void) {
    char senha[] = "segredo123";
    char nome[] = {'A', 'n', 'a'};
    printf("Nome: %s\n", nome);
    printf("(a senha é %s)\n", senha);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra semzero.c -o semzero     « nenhum aviso!
$ ./semzero
Nome: Anasegredo123
(a senha é segredo123)

O printf mostrou "Ana", não achou a placa de fim e continuou andando pela memória. A cadeira seguinte, por acaso, era o começo de senha; ele mostrou a senha inteira e só parou no '\0' dela. Num programa de verdade, isso vaza dados que ninguém deveria ver. E o compilador não avisou: para ele, {'A', 'n', 'a'} é um array de char perfeitamente válido. Só o %s é que espera uma string.

Ler além do fim de um array é um comportamento indefinido (aula Comportamento Indefinido): o resultado depende do que estiver na memória. Pode sair lixo, pode sair a senha, pode até parecer certo. Para pegar o erro com certeza, compile com o AddressSanitizer (-fsanitize=address, "higienizador de endereços", aula Sanitizers), que vigia cada acesso à memória:

$ gcc -std=c23 -Wall -Wextra -g -fsanitize=address semzero.c -o semzero
$ ./semzero
=================================================================
==26329==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x6db5ff9f0033 at pc 0x71b601ed0cae bp 0x7ffc27f9b930 sp 0x7ffc27f9b0a8
READ of size 4 at 0x6db5ff9f0033 thread T0
    #0 0x71b601ed0cad in printf_common ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc:567
    #1 0x71b601ef18d3 in vprintf ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1731
    #2 0x71b601ef3aa4 in printf ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1791
    #3 0x5d52da0023ca in main /home/ana/c/semzero.c:6
…
  This frame has 2 object(s):
    [48, 51) 'nome' (line 5) <== Memory access at offset 51 overflows this variable
    [64, 75) 'senha' (line 4)
…
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/ana/c/semzero.c:6 in main
…                                     « mais linhas com o mapa da memória
==26329==ABORTING
stack-buffer-overflow
"Estouro de buffer na pilha": um acesso passou do fim de um array local (buffer é um pedaço de memória usado para guardar dados; a pilha é onde moram as variáveis do main, aula Pilha e Heap).
READ of size 4
Foi uma leitura, feita dentro do printf.
#3 … in main /home/ana/c/semzero.c:6
A linha do seu código que causou a leitura: o printf("Nome: %s\n", nome). As linhas #0 a #2 são de dentro do printf.
[48, 51) 'nome' … overflows this variable
O array nome ocupa os bytes 48, 49 e 50 (3 bytes, sem '\0'). O acesso no byte 51 "transbordou esta variável".
No editor do guia

No editor (WebAssembly), este programa mostrou Nome: Ana: por acaso, o byte seguinte na memória era um zero. É o comportamento indefinido em ação: o mesmo erro, dois resultados diferentes, e um deles parece certo. O AddressSanitizer não existe no editor; ele só roda no gcc ou no Clang instalados no computador.

Regra do guia: todo array de texto tem lugar para o '\0'

Crie strings com aspas ("Ana"), que põem o '\0' sozinhas. Ao escolher um tamanho, conte sempre letras + 1. E sempre que montar uma string letra por letra, termine com '\0'.


8. Comparar strings com == está errado

Para números, == compara valores. Com strings, parece funcionar, mas não funciona:

#include <stdio.h>

int main(void) {
    char nome[] = "Ana";
    if (nome == "Ana") {
        printf("Oi, Ana!\n");
    } else {
        printf("Não te conheço.\n");
    }
    return 0;
}
$ gcc -std=c23 -Wall -Wextra compara.c -o compara
compara.c: In function ‘main’:
compara.c:5:14: warning: comparison with string literal results in unspecified behavior [-Waddress]
    5 |     if (nome == "Ana") {
      |              ^~
$ ./compara
Não te conheço.          « o nome é Ana, mas o == disse que não

Comparison with string literal results in unspecified behavior = "comparar com um literal de string tem resultado não especificado". O que acontece: quando você usa o nome de um array numa conta, o C usa o endereço dele na memória, o lugar onde a fileira começa (aula Ponteiros e Arrays). O == perguntou "estas duas fileiras começam no mesmo lugar?", e não "têm as mesmas letras?". São duas fileiras diferentes (o array nome e o literal "Ana"), então a resposta foi "não".

Para comparar as letras, use a função strcmp ("string compare"), que devolve 0 quando os textos são iguais: if (strcmp(nome, "Ana") == 0). Ela é explicada em Funções de String. O Clang do editor avisa com outras palavras: result of comparison against a string literal is unspecified (use an explicit string comparison function instead), "use uma função de comparação de strings".


9. Trocar o texto com = não compila

Outra surpresa para quem vem de outras linguagens: um array não pode receber outro texto inteiro com =, nem tendo espaço de sobra.

#include <stdio.h>

int main(void) {
    char nome[10] = "Ana";
    nome = "Bia";
    printf("%s\n", nome);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra atribui.c -o atribui
atribui.c: In function ‘main’:
atribui.c:5:10: error: assignment to expression with array type
    5 |     nome = "Bia";
      |          ^

Assignment to expression with array type = "atribuição a uma expressão do tipo array". Em C, arrays não podem ser atribuídos de uma vez, nenhum array, não só os de texto. O = com aspas só funciona na criação (char nome[10] = "Ana";), que é uma inicialização, não uma atribuição. O Clang diz array type 'char[10]' is not assignable ("o tipo array não pode receber atribuição").

Para trocar o texto depois, copie as letras para dentro do array: letra por letra (como na missão da seção 4) ou com uma função que faz a cópia e põe o '\0', como snprintf(nome, sizeof nome, "Bia"); ou strcpy. As duas estão em Funções de String.


10. Um literal não pode ser alterado

Em código de C você vai ver strings criadas com um asterisco: char *nome = "Ana";. Isso não é um array com uma cópia do texto. É um ponteiro (aula Ponteiros e Strings, no Nível 2) que aponta para o próprio literal "Ana", guardado numa área da memória que é só de leitura. Ler funciona; mudar uma letra derruba o programa:

#include <stdio.h>

int main(void) {
    char *nome = "Ana";
    printf("Antes: %s\n", nome);
    nome[0] = 'E';
    printf("Depois: %s\n", nome);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra literal.c -o literal     « nenhum aviso
$ ./literal
Antes: Ana
Falha de segmentação     (imagem do núcleo gravada) ./literal
$ echo $?
139

O gcc compilou sem reclamar, mas o sistema barrou a escrita na área só de leitura e encerrou o programa com falha de segmentação (segmentation fault, código de saída 139). Alterar um literal é comportamento indefinido: no Linux ele quase sempre termina assim.

Duas lições:

  • Se o texto vai ser alterado, crie um array: char nome[] = "Ana"; faz uma cópia que é sua.
  • Se é um ponteiro para literal, escreva const char *nome = "Ana";. O const ("constante") faz o compilador recusar a linha nome[0] = 'E'; antes de o programa rodar, com error: assignment of read-only location ‘*nome’ ("atribuição a um local só de leitura"). Veja a aula const e Ponteiros.
No editor do guia

No editor, o literal.c mostra Depois: Ena e termina normalmente: no WebAssembly não existe memória "só de leitura" para o programa. Não conclua que está certo: num computador de verdade, o mesmo código cai.


Quando dá errado

error: initialization of ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]

O que significa: você escreveu char letra = "A";. Aspas duplas criam uma string (um array); um char guarda um caractere, que se escreve com aspas simples. No gcc 15 isso é erro.

Como consertar: char letra = 'A'; para um caractere, ou char letra[] = "A"; se você queria mesmo uma string.

warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]

O que significa: o %s recebeu um caractere sozinho (printf("%s\n", letra), com char letra = 'A';) em vez de uma string. No laboratório, o programa compilou com esse aviso e, ao rodar, caiu com Falha de segmentação.

Como consertar: para um char, use %c. O próprio gcc sugere outro formato na última linha da mensagem; leia o tipo que ele mostra.

warning: initializer-string for array of ‘char’ truncates NUL terminator …

O que significa: o array não tem lugar para o '\0' (por exemplo char s[3] = "Ana";).

Como consertar: aumente o array para letras + 1, ou use char s[] = "Ana"; e deixe o compilador contar.

A string sai com letras a mais ou lixo no fim (como o Anasegredo123 da seção 7)

O que significa: falta o '\0'. O printf continuou lendo a memória depois do array.

Como consertar: confira como a string foi montada. Se foi letra por letra, coloque '\0' no fim; se foi copiada, confira se o destino tem espaço. Compile com -g -fsanitize=address para o programa apontar a linha.

warning: comparison with string literal results in unspecified behavior [-Waddress]

O que significa: você comparou strings com ==, que compara endereços, não letras.

Como consertar: strcmp(a, b) == 0 (aula Funções de String).

error: assignment to expression with array type

O que significa: você tentou trocar o texto de um array com = depois de criado.

Como consertar: copie com snprintf(destino, sizeof destino, "%s", origem); ou strcpy (aula Funções de String).

Falha de segmentação ao mudar uma letra

O que significa: a variável é um char * apontando para um literal, que fica em memória só de leitura.

Como consertar: declare como array (char s[] = "…";) se for alterar; se não for, use const char *.


Referência rápida

EscritaO que faz
char s[] = "Ana";Array de 4 bytes: 'A' 'n' 'a' '\0'
char s[20] = "Ana";Array de 20 bytes; o texto ocupa 4, o resto é zero
char s[20] = "";String vazia com espaço para 19 letras
'\0'Caractere nulo (código 0): marca o fim da string
'0'O dígito zero (código 48): não marca nada
printf("%s", s);Mostra os caracteres até o '\0'
scanf("%19s", s);Lê uma palavra de até 19 letras (array de 20)
s[0] = 'B';Troca uma letra (aspas simples)
s[3] = '\0';Corta o texto na posição 3
while (s[i] != '\0') i++;Conta as letras (é o que strlen faz)
sizeof sTamanho do array em bytes (não do texto)
const char *p = "Ana";Ponteiro para um literal: só leitura
s == "Ana" / s = "Bia";Errados: use strcmp e snprintf/strcpy

Exercícios

1. A placa de fim

Complete com o caractere que marca o fim de toda string em C:

char c[] = {'o', 'i', };

2. Quantos bytes?

Quantos bytes ocupa char cidade[] = "Natal";? Escreva só o número.

sizeof cidade ==

3. O formato

Complete para mostrar a string produto:

printf("Produto: \n", produto);

4. O que char s[] = ""; guarda?

5. Depois de char s[] = "Lojinha"; s[4] = '\0';, o que printf("%s", s) mostra?

6. Por que if (nome == "Ana") não funciona?

7. Qual destas linhas cria um texto que pode ser alterado depois, letra por letra?

Missão final: o crachá da Ana

Missão: a Ana vai imprimir um crachá. Primeiro, conte os caracteres de nome com um laço que anda até o '\0' (sem strlen: ela é da próxima aula) e guarde em tamanho. Depois, corte a string no espaço, colocando um '\0' no lugar dele, para mostrar só o primeiro nome. Sem avisos.

Ana Maria tem 9 caracteres
Primeiro nome: Ana
#include <stdio.h>

int main(void) {
    char nome[] = "Ana Maria";
    int tamanho = 0;
    // 1. conte os caracteres até o fim da string

    printf("%s tem %d caracteres\n", nome, tamanho);
    // 2. troque o espaço por uma placa de fim

    printf("Primeiro nome: %s\n", nome);
    return 0;
}
#include <stdio.h>

int main(void) {
    char nome[] = "Ana Maria";
    int tamanho = 0;
    while (nome[tamanho] != '\0') {
        tamanho++;
    }
    printf("%s tem %d caracteres\n", nome, tamanho);
    for (int i = 0; i < tamanho; i++) {
        if (nome[i] == ' ') {
            nome[i] = '\0';
            break;
        }
    }
    printf("Primeiro nome: %s\n", nome);
    return 0;
}

A solução procura o espaço com um laço em vez de usar nome[3] direto: assim ela funciona com qualquer nome. O espaço conta como caractere, por isso são 9. Na próxima aula, Funções de String, as duas tarefas viram uma linha cada: strlen conta e strchr acha o espaço.


Resumo

  • Em C, uma string é um array de char terminado pelo caractere nulo '\0' (código 0). Não existe tipo "string".
  • char nome[] = "Ana"; ocupa 4 bytes: as aspas põem o '\0' sozinhas. Espaço necessário = letras + 1.
  • %s mostra até o '\0'; scanf("%19s", s) lê uma palavra com limite. Cada letra é acessada com s[i], e um '\0' no meio corta o texto.
  • sizeof mede o array, não o texto. Para contar as letras, ande até o '\0' (ou use strlen).
  • Sem '\0', as funções leem além do array: lixo ou dados de outras variáveis. O gcc 15 avisa com -Wunterminated-string-initialization; o -fsanitize=address pega na hora de rodar.
  • == compara endereços (use strcmp); = não troca o texto de um array (use snprintf/strcpy); um literal apontado por char * não pode ser alterado (use const char *, ou um array se for mudar).