C Caracteres (char)
Uma opção de menu ('s' ou 'n'), a inicial de um nome, uma tecla apertada, um algarismo lido do teclado: tudo isso é um caractere. Em C, um caractere mora no tipo char. E aqui vem a grande revelação desta aula: para o computador, um char é só um número pequeno. Entender isso explica por que dá para somar letras, transformar '7' em 7 e por que o ç dá trabalho.
- Como criar um
chare mostrar com%c(a letra) ou%d(o número). - A tabela ASCII: o número de cada letra, algarismo e símbolo.
- Contas com caracteres:
'A' + 1,'z' - 'a', maiúscula e minúscula. - A diferença entre aspas simples (
'A') e duplas ("A"). - Como transformar o algarismo
'7'no número7. - Por que
'ç'não cabe numchar. - Uma prévia de
getchareputchar, que leem e escrevem um caractere.
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.
A ideia: o código secreto combinado
Quando crianças, muita gente brincou de código secreto: A = 1, B = 2, C = 3… Para mandar "OI", você escrevia "15 9", e o amigo, que conhecia a tabela, traduzia de volta.
O computador só guarda números. Para guardar letras, os computadores combinaram uma tabela parecida, a ASCII (American Standard Code for Information Interchange, "Código Padrão Americano para Troca de Informações", de 1963). Nela, 'A' é 65, 'B' é 66, 'a' é 97, o algarismo '0' é 48 e o espaço é 32. Um char guarda o número; quem decide mostrar como letra é o printf, quando você pede %c.
1. Criar um char
#include <stdio.h>
int main(void) {
char letra = 'A';
printf("Como letra: %c\n", letra);
printf("Como número: %d\n", letra);
return 0;
}
$ gcc -std=c23 -Wall -Wextra letra.c -o letra $ ./letra Como letra: A Como número: 65
- char
- De character, "caractere". Ocupa 1 byte: guarda números de -128 a 127 no gcc do laboratório e no editor.
- 'A'
- Um caractere vai entre aspas simples, e só cabe um. O compilador troca
'A'pelo número 65. - %c
- "Mostre este número como caractere": procura o 65 na tabela e desenha um
A. - %d
- "Mostre este número como número":
65. É a mesma caixa, com o mesmo conteúdo; só muda o jeito de mostrar.
Missão: o programa mostra A = A. Faça ele mostrar a letra minúscula a e o seu número na tabela: a = 97. Você precisa mudar o valor de letra e uma das letras do printf.
#include <stdio.h>
int main(void) {
char letra = 'A';
printf("%c = %c\n", letra, letra);
return 0;
}
#include <stdio.h>
int main(void) {
char letra = 'a';
printf("%c = %d\n", letra, letra);
return 0;
}
2. Aspas simples × aspas duplas
Em C, as aspas não são enfeite: cada tipo faz uma coisa diferente.
| Escrita | O que é | Tipo | Mostra com |
|---|---|---|---|
'A' | Um caractere: o número 65 | int (cabe num char) | %c |
"A" | Um texto de uma letra: o A e um '\0' invisível que marca o fim | array de char | %s |
(Sim: em C, o literal 'A' é do tipo int, e sizeof('A') dá 4, como você viu em Tipos de Dados. Na prática, não faz diferença: ele cabe num char sem nenhum aviso.)
Trocar uma pela outra é erro:
#include <stdio.h>
int main(void) {
char a = 'A';
char b = "A";
printf("%c %c\n", a, b);
return 0;
}
$ gcc -std=c23 -Wall -Wextra aspas.c -o aspas
aspas.c: In function ‘main’:
aspas.c:5:14: error: initialization of ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
5 | char b = "A";
| ^~~
"Inicialização de char a partir de char *". O "A" é um texto, e o C o entrega como o endereço onde as letras estão guardadas (um char *, aula Ponteiros e Strings). Endereço não cabe numa caixa de caractere. No editor, o Clang diz incompatible pointer to integer conversion initializing 'char' with an expression of type 'char[2]': o char[2] são as duas posições, 'A' e '\0'.
Duas letras em aspas simples
E o contrário, duas letras entre aspas simples? O gcc avisa, mas compila:
$ cat duas.c
#include <stdio.h>
int main(void) {
char iniciais = 'AN';
printf("%c\n", iniciais);
return 0;
}
$ gcc -std=c23 -Wall -Wextra duas.c -o duas
duas.c: In function ‘main’:
duas.c:4:21: warning: multi-character character constant [-Wmultichar]
4 | char iniciais = 'AN';
| ^~~~
duas.c:4:21: warning: overflow in conversion from ‘int’ to ‘char’ changes value from ‘16718’ to ‘78’ [-Woverflow]
$ ./duas
N « o A sumiu
Multi-character character constant = "constante de caractere com vários caracteres". O gcc juntou os dois números num só (65 × 256 + 78 = 16718), que não cabe num char; sobrou o 78, o N. Para guardar "AN", use um texto: char iniciais[] = "AN"; (aula Strings).
3. Um pedaço da tabela ASCII
Este programa mostra os caracteres visíveis da tabela, do 32 (o espaço) ao 126. (Ele usa um for e um if para montar as colunas; por enquanto, olhe só a saída.)
#include <stdio.h>
int main(void) {
for (int codigo = 32; codigo < 127; codigo++) {
printf("%3d %c ", codigo, codigo);
if ((codigo - 31) % 6 == 0) {
printf("\n");
}
}
printf("\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra tabela.c -o tabela
$ ./tabela
32 33 ! 34 " 35 # 36 $ 37 %
38 & 39 ' 40 ( 41 ) 42 * 43 +
44 , 45 - 46 . 47 / 48 0 49 1
50 2 51 3 52 4 53 5 54 6 55 7
56 8 57 9 58 : 59 ; 60 < 61 =
62 > 63 ? 64 @ 65 A 66 B 67 C
68 D 69 E 70 F 71 G 72 H 73 I
74 J 75 K 76 L 77 M 78 N 79 O
80 P 81 Q 82 R 83 S 84 T 85 U
86 V 87 W 88 X 89 Y 90 Z 91 [
92 \ 93 ] 94 ^ 95 _ 96 ` 97 a
98 b 99 c 100 d 101 e 102 f 103 g
104 h 105 i 106 j 107 k 108 l 109 m
110 n 111 o 112 p 113 q 114 r 115 s
116 t 117 u 118 v 119 w 120 x 121 y
122 z 123 { 124 | 125 } 126 ~
Três coisas para guardar:
- Os algarismos vêm em ordem e juntos:
'0'= 48,'1'= 49 …'9'= 57. - As maiúsculas também:
'A'= 65 …'Z'= 90. - E as minúsculas:
'a'= 97 …'z'= 122. Cada minúscula fica exatamente 32 depois da sua maiúscula.
Ninguém decora a tabela inteira. O importante é saber que ela existe, que é ordenada e que você pode consultá-la (ou rodar este programa) quando precisar.
Os caracteres invisíveis
Os códigos de 0 a 31 (e o 127) não desenham nada: são comandos, como "pule uma linha". Você já conhece alguns, escritos com a barra invertida (aula Novas Linhas e Escapes):
#include <stdio.h>
int main(void) {
printf("'\\n' = %d\n", '\n');
printf("'\\t' = %d\n", '\t');
printf("'\\0' = %d\n", '\0');
printf("' ' = %d\n", ' ');
printf("'\\'' = %d\n", '\'');
return 0;
}
Dentro do texto do printf, \\ mostra uma barra invertida; por isso "'\\n'" aparece como '\n' na tela.
$ gcc -std=c23 -Wall -Wextra invisiveis.c -o invisiveis $ ./invisiveis '\n' = 10 « nova linha '\t' = 9 « tabulação '\0' = 0 « o caractere nulo, que marca o fim dos textos ' ' = 32 « o espaço ocupa lugar, mas não tem desenho '\'' = 39 « aspas simples dentro de aspas simples: com barra
4. Contas com char
Se um char é um número, dá para fazer contas com ele:
#include <stdio.h>
int main(void) {
char letra = 'A';
char proxima = letra + 1;
printf("%c %c\n", letra, proxima);
printf("%c\n", 'a' + 2);
printf("%c\n", 66);
printf("%d\n", 'z' - 'a');
return 0;
}
$ gcc -std=c23 -Wall -Wextra soma.c -o soma $ ./soma A B c B 25
- letra + 1
- 65 + 1 = 66, que na tabela é o
B. A letra seguinte. - 'a' + 2
- 97 + 2 = 99, o
c. - printf("%c", 66)
- O
%caceita qualquer número da tabela, mesmo sem variávelchar: 66 éB. - 'z' - 'a'
- 122 - 97 = 25: a distância entre as letras. O
zé a 26ª letra, 25 posições depois doa.
Maiúscula e minúscula
Como cada minúscula está 32 posições depois da maiúscula, subtrair 32 transforma 'g' em 'G':
$ cat maiuscula.c
#include <stdio.h>
int main(void) {
char minuscula = 'g';
char maiuscula = minuscula - 32;
printf("%c -> %c\n", minuscula, maiuscula);
printf("%d %d\n", 'a' - 'A', 'g' - 'G');
return 0;
}
$ gcc -std=c23 -Wall -Wextra maiuscula.c -o maiuscula
$ ./maiuscula
g -> G
32 32
Funciona, mas só para letras de a a z (tente com '!' e veja o que sai). Na vida real, use as funções prontas toupper e tolower ("para maiúscula", "para minúscula"), que conferem se o caractere é mesmo uma letra. Elas e as perguntas do tipo "é algarismo?", "é letra?" estão em Classificar Caracteres (ctype.h). Escrever 'a' - 'A' no lugar do 32 também deixa o código mais claro do que o número solto.
Missão: complete o printf para mostrar a letra guardada em letra e as três seguintes, separadas por espaço, usando letra + 1, letra + 2 e letra + 3. Com 'D', a saída deve ser D E F G.
#include <stdio.h>
int main(void) {
char letra = 'D';
printf("%c\n", letra);
return 0;
}
#include <stdio.h>
int main(void) {
char letra = 'D';
printf("%c %c %c %c\n", letra, letra + 1, letra + 2, letra + 3);
return 0;
}
Troque 'D' por 'X' e rode de novo: depois do Z vêm [ e \, porque a tabela continua. Fazer a conta "dar a volta" para o A é o segredo da cifra de César, um código secreto de verdade, que você vai conseguir escrever depois de Operadores Aritméticos.
O algarismo '7' não é o número 7
Quando o programa lê o que a pessoa digitou, os algarismos chegam como caracteres. E o caractere '7' vale 55 na tabela, não 7:
#include <stdio.h>
int main(void) {
char c = '7';
printf("%c vale %d na tabela\n", c, c);
int numero = c - '0';
printf("como número: %d\n", numero);
printf("dobro: %d\n", numero * 2);
return 0;
}
$ gcc -std=c23 -Wall -Wextra digito.c -o digito $ ./digito 7 vale 55 na tabela como número: 7 dobro: 14
O truque é c - '0': como os algarismos estão em ordem a partir do 48, subtrair '0' (48) dá a posição do algarismo: 55 - 48 = 7. Esse truque é garantido pela norma do C para os algarismos de '0' a '9', em qualquer computador. Para textos inteiros, como "2024", existe strtol (aula Texto ↔ Número).
5. Por que 'ç' não cabe num char
A tabela ASCII tem só 128 posições, e nenhuma delas é ç, ã ou é. Os arquivos de hoje usam a codificação UTF-8, em que cada letra acentuada ocupa 2 bytes (aula Acentos e UTF-8). Dois bytes não cabem numa caixa de um:
#include <stdio.h>
int main(void) {
char c = 'ç';
printf("%c\n", c);
return 0;
}
$ gcc -std=c23 -Wall -Wextra acento.c -o acento
acento.c: In function ‘main’:
acento.c:4:14: warning: multi-character character constant [-Wmultichar]
4 | char c = 'ç';
| ^~~
acento.c:4:14: warning: overflow in conversion from ‘int’ to ‘char’ changes value from ‘50087’ to ‘-89’ [-Woverflow]
$ ./acento
� « meio ç: um byte sozinho, que o terminal não sabe desenhar
O gcc viu dois bytes entre as aspas (é o mesmo aviso de 'AN'), guardou só o segundo e o terminal mostrou um losango com interrogação. No editor, o Clang é mais rígido e nem compila: error: character too large for enclosing character literal type ("caractere grande demais para o tipo do literal").
Dentro de textos entre aspas duplas, acentos funcionam normalmente: printf("Atenção!\n"); mostra Atenção!, porque os bytes do ç passam juntos até o terminal. O problema é só guardar uma letra acentuada sozinha num char.
6. Prévia: ler e escrever um caractere
A biblioteca tem duas funções pequenas para um caractere de cada vez: getchar ("pegue um caractere", do teclado) e putchar ("ponha um caractere", na tela).
#include <stdio.h>
int main(void) {
int c = getchar();
printf("Você digitou '%c', código %d\n", c, c);
putchar(c);
putchar('\n');
return 0;
}
$ gcc -std=c23 -Wall -Wextra eco.c -o eco $ echo Ana | ./eco Você digitou 'A', código 65 A
- int c = getchar();
- Lê um caractere da entrada. Repare que a caixa é
int, e nãochar: quando a entrada acaba, ogetchardevolve um valor especial,EOF(end of file, "fim do arquivo", que vale -1), que precisa caber junto com todos os 256 bytes possíveis. As aulas while e stdin, stdout e stderr usam isso. - echo Ana | ./eco
- O
echo Ana |manda o texto "Ana" para o programa como se alguém tivesse digitado. Ogetcharpegou só oA; o "na" ficou esperando e foi ignorado. - putchar(c)
- Escreve o caractere na tela, sem pular linha. Por isso o segundo
putchar('\n').
Missão: o programa pergunta se a Ana quer sacola e lê a resposta com getchar (a caixa já vem com a resposta s digitada). Mas mostra Você respondeu: 115 (código 115). Troque uma letra do printf para mostrar o caractere na primeira posição: Você respondeu: s (código 115).
#include <stdio.h>
int main(void) {
printf("Quer sacola? (s/n) ");
int resposta = getchar();
printf("Você respondeu: %d (código %d)\n", resposta, resposta);
return 0;
}
#include <stdio.h>
int main(void) {
printf("Quer sacola? (s/n) ");
int resposta = getchar();
printf("Você respondeu: %c (código %d)\n", resposta, resposta);
return 0;
}
Formas diferentes: qual usar
O mesmo A pode ser escrito de três jeitos, e a mesma maiúscula pode ser obtida de três jeitos:
$ cat formas.c
#include <stdio.h>
int main(void) {
char a = 'A';
char b = 65;
char c = '\x41';
printf("%c %c %c\n", a, b, c);
return 0;
}
$ gcc -std=c23 -Wall -Wextra formas.c -o formas
$ ./formas
A A A
| Forma | Exemplo | Quando usar |
|---|---|---|
| Aspas simples | 'A' | Sempre que possível. Quem lê entende na hora. |
| Número da tabela | 65 | Quase nunca: quem lê tem de consultar a tabela. |
| Escape em hexadecimal | '\x41' | Para caracteres sem desenho (códigos de controle); raramente para letras. |
| Somar ou subtrair 32 | c - 32 | Evite: o 32 solto não explica nada. |
| Distância entre as letras | c - 'a' + 'A' | Para entender a tabela (e em exercícios). |
| Função pronta | toupper(c) | No dia a dia. Confere se é letra (aula ctype.h). |
Quando dá errado
error: initialization of ‘char’ from ‘char *’ makes integer from pointer without a cast
O que significa: você usou aspas duplas ("A") para um char. Aspas duplas fazem um texto.
Como consertar: char letra = 'A';, com aspas simples. Se você quer mesmo um texto, use char nome[] = "Ana";.
warning: multi-character character constant [-Wmultichar]
O que significa: há mais de um caractere entre aspas simples: 'AN', ou uma letra acentuada como 'ç', que em UTF-8 são dois bytes. Só um deles fica na caixa. No editor, o caso do 'ç' é erro: character too large for enclosing character literal type.
Como consertar: um caractere por char; para mais de um, ou para acentos, use um texto entre aspas duplas.
65 em vez de A (ou A em vez de 65)
O que significa: a letra do printf decide: %c mostra o caractere, %d mostra o número. O -Wall não avisa, porque as duas formas são válidas.
Como consertar: escolha a letra pelo que você quer ver.
'7' + '5' = 108)
O que significa: você somou os códigos da tabela (55 + 53), e não os algarismos.
Como consertar: converta cada um com - '0': ('7' - '0') + ('5' - '0') = 12.
Referência rápida
| Escrita | O que faz |
|---|---|
char c = 'A'; | Guarda o caractere A (o número 65) |
printf("%c", c) | Mostra como caractere: A |
printf("%d", c) | Mostra o código: 65 |
c + 1 | O caractere seguinte na tabela |
c - '0' | Algarismo para número: '7' - '0' = 7 |
c - 'a' + 'A' | Minúscula para maiúscula (só de a a z; prefira toupper) |
'\n', '\t', '\0', '\'' | Nova linha (10), tabulação (9), nulo (0), aspas simples |
int c = getchar(); | Lê um caractere (ou EOF, no fim da entrada) |
putchar(c); | Escreve um caractere |
Códigos: '0' = 48, 'A' = 65, 'a' = 97, espaço = 32, '\n' = 10 | |
Exercícios
1. Código da letra
Na tabela ASCII, 'A' é 65. Qual é o código de 'C'?
2. Algarismo para número
Complete para transformar o caractere c (um algarismo) no número correspondente:
3. O que printf("%c", 'a' + 1); mostra?
4. Qual é a diferença entre 'A' e "A"?
5. Por que char c = 'ç'; dá problema?
6. Por que a variável que recebe getchar() deve ser int?
Missão final: somar algarismos
Missão: a Ana digitou os algarismos 7 e 5, que chegaram ao programa como caracteres. O programa soma os dois e mostra Soma: 108, porque somou os códigos da tabela (55 + 53). Use o truque do - '0' em cada um para mostrar Soma: 12.
#include <stdio.h>
int main(void) {
char a = '7';
char b = '5';
int soma = a + b;
printf("Soma: %d\n", soma);
return 0;
}
#include <stdio.h>
int main(void) {
char a = '7';
char b = '5';
int soma = (a - '0') + (b - '0');
printf("Soma: %d\n", soma);
return 0;
}
Resumo
- Um
chartem 1 byte e guarda um número pequeno; a tabela ASCII diz qual caractere cada número representa ('A'= 65,'a'= 97,'0'= 48). %cmostra o caractere;%dmostra o número. É a mesma caixa.- Aspas simples: um caractere (
'A'). Aspas duplas: um texto ("A", com'\0'no fim). Trocar dá erro ou aviso. - Dá para fazer contas:
'A' + 1é'B'; minúscula = maiúscula + 32;c - '0'transforma um algarismo em número. - Letras acentuadas ocupam 2 bytes em UTF-8 e não cabem num
char; em textos entre aspas duplas, funcionam. getcharlê um caractere (guarde numint, por causa doEOF);putcharescreve um.