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.
- O que é uma string em C: um array de
charterminado 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 numchar.
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,apara dentro do array e coloca um'\0'no fim, sozinho. - %s
- O formato do
printfpara strings (s de string). Oprintfmostra 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 desizeof.
$ 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 guardado | 65 | 110 | 97 | 0 |
'\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]noprintfsó 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
| Forma | Quando 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
inã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: oscanfvai 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
scanfdevolve 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#0a#2são de dentro doprintf. - [48, 51) 'nome' … overflows this variable
- O array
nomeocupa os bytes 48, 49 e 50 (3 bytes, sem'\0'). O acesso no byte 51 "transbordou esta variável".
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.
'\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";. Oconst("constante") faz o compilador recusar a linhanome[0] = 'E';antes de o programa rodar, comerror: assignment of read-only location ‘*nome’("atribuição a um local só de leitura"). Veja a aula const e Ponteiros.
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.
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
| Escrita | O 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 s | Tamanho 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:
2. Quantos bytes?
Quantos bytes ocupa char cidade[] = "Natal";? Escreva só o número.
3. O formato
Complete para mostrar a string 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
charterminado 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.%smostra até o'\0';scanf("%19s", s)lê uma palavra com limite. Cada letra é acessada coms[i], e um'\0'no meio corta o texto.sizeofmede o array, não o texto. Para contar as letras, ande até o'\0'(ou usestrlen).- 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=addresspega na hora de rodar. ==compara endereços (usestrcmp);=não troca o texto de um array (usesnprintf/strcpy); um literal apontado porchar *não pode ser alterado (useconst char *, ou um array se for mudar).