C++ Caracteres (char)
Uma letra, um algarismo, um sinal de pontuação: cada um é um caractere, e em C++ um caractere sozinho cabe no tipo char (de character, "caractere"). O segredo desta aula é que, para o computador, um char é um número: a letra A é guardada como 65. Entender isso explica por que dá para "somar" letras, por que std::toupper às vezes mostra um número e por que o ç não cabe num char.
- Como criar um
chare a diferença entre aspas simples ('A') e duplas ("A"). - Que todo caractere tem um código:
static_cast<int>('A')mostra 65. - Um pedaço da tabela ASCII e os padrões que ela esconde.
- Contas com caracteres:
'a' + 1,'7' - '0'. - As funções de
<cctype>:std::toupper,std::tolower,std::isdigite companhia. - Por que
'ç'dá o avisomulti-character character constant.
Todos os programas desta aula foram compilados com o g++ 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/cpp, com o comando padrão do guia: g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa.
A ideia: o código secreto combinado
Imagine duas crianças que combinam um código: 1 = A, 2 = B, 3 = C… Para mandar "CAB", uma escreve 3 1 2 no bilhete, e a outra traduz de volta. O bilhete só tem números; as letras existem no combinado.
O computador faz igual. A memória só guarda números. Para guardar letras, todo mundo segue uma tabela combinada, chamada ASCII (sigla em inglês de "Código Padrão Americano para Troca de Informações", criado nos anos 1960). Nela, A é 65, B é 66, o espaço é 32. Um char guarda o número; quem mostra a letra é o std::cout, que consulta a tabela.
1. Criar um char
#include <iostream>
int main() {
char letra = 'A';
std::cout << "letra: " << letra << "\n";
std::cout << "código: " << static_cast<int>(letra) << "\n";
char outra = 66;
std::cout << "outra: " << outra << "\n";
}
- char letra = 'A';
- Um caractere vai entre aspas simples. Por dentro, a variável guarda 65.
- std::cout << letra
- O
coutvê que o tipo échare mostra a letra. - static_cast<int>(letra)
- "Converta para
int". O valor é o mesmo 65, mas agora ocoutvê um número e mostra o número.static_cast("conversão estática", feita na compilação) é o jeito moderno de converter tipos; ele tem aula própria em Conversão de Tipos. - char outra = 66;
- O caminho inverso: guardamos o número 66, e o
coutmostra a letra que tem esse código.
$ g++ -std=c++23 -Wall -Wextra letra.cpp -o letra $ ./letra letra: A código: 65 outra: B
Um char ocupa 1 byte e guarda números de -128 a 127 no Linux da Ana (aula Tipos de Dados). Existem também unsigned char (0 a 255) e signed char; para guardar letras, o char simples é o que você usa.
Missão: o programa mostra o código da letra A. Acrescente duas linhas iguais para descobrir o código da letra Z e do caractere 0 (o algarismo zero, entre aspas simples). A saída deve ter Z = 90 e 0 = 48.
#include <iostream>
int main() {
std::cout << 'A' << " = " << static_cast<int>('A') << "\n";
}
#include <iostream>
int main() {
std::cout << 'A' << " = " << static_cast<int>('A') << "\n";
std::cout << 'Z' << " = " << static_cast<int>('Z') << "\n";
std::cout << '0' << " = " << static_cast<int>('0') << "\n";
}
Repare: o caractere '0' vale 48, e não 0. O algarismo que aparece na tela e o número zero são coisas diferentes. Isso vai ser útil na seção 4.
2. Aspas simples × aspas duplas
Esta é a confusão número 1 com char:
| Escrita | O que é | Tipo |
|---|---|---|
'A' | Um caractere | char |
"A" | Um texto que, por acaso, tem uma letra só | texto (vira std::string quando guardado num) |
"Ana" | Um texto com três letras | texto |
'Ana' | Um engano (veja abaixo) | — |
Trocar uma pela outra dá erro. Texto entre aspas duplas num char:
$ cat aspas.cpp
#include <iostream>
int main() {
char inicial = "A";
std::cout << inicial << "\n";
}
$ g++ -std=c++23 -Wall -Wextra aspas.cpp -o aspas
aspas.cpp: In function ‘int main()’:
aspas.cpp:4:20: error: invalid conversion from ‘const char*’ to ‘char’ [-fpermissive]
4 | char inicial = "A";
| ^~~
| |
| const char*
Invalid conversion from ‘const char*’ to ‘char’: o "A" é um texto (tipo const char*, explicado em auto), e não cabe numa caixa de um caractere só.
E um caractere num std::string:
$ cat aspas2.cpp
#include <iostream>
#include <string>
int main() {
std::string nome = 'A';
std::cout << nome << "\n";
}
$ g++ -std=c++23 -Wall -Wextra aspas2.cpp -o aspas2
aspas2.cpp: In function ‘int main()’:
aspas2.cpp:5:24: error: conversion from ‘char’ to non-scalar type ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’} requested
Conversion from ‘char’ to non-scalar type ‘std::string’ requested = "pediu-se uma conversão de char para o tipo std::string" (que o C++ não faz sozinho com =). O trecho entre chaves ({aka ‘std::__cxx11::basic_string<char>’}, "também conhecido como") é o nome completo do std::string dentro da biblioteca; pode ignorar. Conserto: std::string nome = "A";.
E várias letras entre aspas simples? O g++ aceita, com dois avisos, e guarda só a última:
$ cat aspas3.cpp
#include <iostream>
int main() {
char inicial = 'Ana';
std::cout << inicial << "\n";
}
$ g++ -std=c++23 -Wall -Wextra aspas3.cpp -o aspas3
aspas3.cpp:4:20: warning: multi-character character constant [-Wmultichar]
4 | char inicial = 'Ana';
| ^~~~~
aspas3.cpp: In function ‘int main()’:
aspas3.cpp:4:20: warning: overflow in conversion from ‘int’ to ‘char’ changes value from ‘4288097’ to ‘97’ [-Woverflow]
$ ./aspas3
a « sobrou só o último "a" (código 97)
Multi-character character constant = "constante de caractere com vários caracteres". O compilador juntou os códigos das três letras num número só (4288097) e, ao guardar num char, sobrou apenas o pedaço do último a, que vale 97. Guarde este aviso: ele volta na seção 6, com o ç.
3. Um pedaço da tabela ASCII
Este programa mostra o código de alguns caracteres. Ele usa uma lista e um laço que repete o cout para cada item (Arrays e for de intervalo, aulas futuras); aqui, só a saída importa:
#include <iostream>
int main() {
const char exemplos[] = {' ', '!', '0', '1', '9', 'A', 'B', 'Z', 'a', 'b', 'z', '~'};
for (char c : exemplos) {
std::cout << "'" << c << "' = " << static_cast<int>(c) << "\n";
}
}
$ g++ -std=c++23 -Wall -Wextra tabela.cpp -o tabela $ ./tabela ' ' = 32 '!' = 33 '0' = 48 '1' = 49 '9' = 57 'A' = 65 'B' = 66 'Z' = 90 'a' = 97 'b' = 98 'z' = 122 '~' = 126
| Faixa | Caracteres | Códigos |
|---|---|---|
| Controle | Invisíveis: '\n' (nova linha) = 10, '\t' (tabulação) = 9… | 0 a 31 |
| Espaço e pontuação | ' ' = 32, ! " # $ %… | 32 a 47 |
| Algarismos | '0' a '9' | 48 a 57 |
| Maiúsculas | 'A' a 'Z' | 65 a 90 |
| Minúsculas | 'a' a 'z' | 97 a 122 |
| Último | '~' = 126 (127 é um controle, "apagar") | até 127 |
Três padrões que valem ouro:
- As letras estão em ordem:
'B'é'A' + 1,'C'é'A' + 2… - Minúscula = maiúscula + 32:
'a'(97) −'A'(65) = 32. - Os algarismos também estão em ordem:
'7'−'0'= 55 − 48 = 7.
A tabela ASCII só tem as letras do inglês: nada de á, ç, ã. Eles vêm de uma tabela maior, o Unicode (seção 6).
4. Contas com char
Como char é número, dá para fazer contas. Mas cuidado com o tipo do resultado:
#include <iostream>
int main() {
char letra = 'a';
std::cout << letra + 1 << "\n";
char proxima = letra + 1;
std::cout << proxima << "\n";
std::cout << static_cast<char>('A' + 2) << "\n";
std::cout << static_cast<char>('a' - 32) << "\n";
char digito = '7';
int valor = digito - '0';
std::cout << "valor: " << valor << "\n";
letra++;
std::cout << letra << "\n";
}
$ g++ -std=c++23 -Wall -Wextra conta.cpp -o conta $ ./conta 98 « 'a' + 1 virou número! b C A valor: 7 b
| Linha | Saída | Por quê |
|---|---|---|
letra + 1 | 98 | Numa conta, o C++ promove o char para int (97 + 1 = 98, um int). O cout recebe um int e mostra número. |
char proxima = letra + 1; | b | O 98 foi guardado numa caixa char; o cout mostra a letra. |
static_cast<char>('A' + 2) | C | Mesmo efeito, sem variável: converter o resultado de volta para char. |
'a' - 32 | A | Minúscula menos 32 = maiúscula. |
digito - '0' | 7 | O truque clássico: transforma o caractere '7' no número 7. |
letra++ | b | O ++ soma 1 e a variável continua char (aula ++ e --). |
Conta com letra funciona, mas o código fica difícil de ler (o que é esse 32?). Para trocar maiúsculas e minúsculas, prefira as funções da próxima seção.
5. As funções de <cctype>
O cabeçalho <cctype> ("c" de herdado do C, "ctype" de character type, tipo de caractere) tem funções prontas para perguntar e transformar caracteres:
#include <cctype>
#include <iostream>
int main() {
char c = 'a';
std::cout << std::toupper(c) << "\n";
std::cout << static_cast<char>(std::toupper(c)) << "\n";
std::cout << static_cast<char>(std::tolower('Q')) << "\n";
std::cout << "isdigit('7'): " << std::isdigit('7') << "\n";
std::cout << "isdigit('x'): " << std::isdigit('x') << "\n";
std::cout << "isalpha('x'): " << std::isalpha('x') << "\n";
std::cout << "isupper('x'): " << std::isupper('x') << "\n";
std::cout << "isspace(' '): " << std::isspace(' ') << "\n";
bool ehDigito = std::isdigit('7');
std::cout << "como bool: " << ehDigito << "\n";
}
$ g++ -std=c++23 -Wall -Wextra cctype.cpp -o cctype
$ ./cctype
65 « toupper devolve int: aparece o código, e não a letra
A
q
isdigit('7'): 1
isdigit('x'): 0
isalpha('x'): 1024 « "verdadeiro" pode vir como qualquer número diferente de 0
isupper('x'): 0
isspace(' '): 8192
como bool: 1
Duas surpresas, ambas porque essas funções vêm da linguagem C, que não tinha bool nem gostava de char como resultado:
std::toupperdevolve umint, o código da letra. Para ver a letra, converta:static_cast<char>(std::toupper(c)).- As funções
is…devolvemint:0quer dizer falso, e qualquer outro número quer dizer verdadeiro (1024, 8192…). Guardadas numbool, viram1(aula Booleanos). Numif, funcionam direto.
| Função | Pergunta ou faz | Exemplo |
|---|---|---|
std::isdigit(c) | É algarismo (0–9)? | '7' → sim |
std::isalpha(c) | É letra (A–Z, a–z)? | 'x' → sim; '7' → não |
std::isalnum(c) | É letra ou algarismo? | 'x', '7' → sim; '!' → não |
std::isupper(c) / std::islower(c) | É maiúscula? / minúscula? | 'Q' → maiúscula |
std::isspace(c) | É espaço, tabulação ou nova linha? | ' ', '\n' → sim |
std::ispunct(c) | É pontuação? | '!', '?' → sim |
std::toupper(c) | Devolve a maiúscula (como int) | 'a' → 65 ('A') |
std::tolower(c) | Devolve a minúscula (como int) | 'Q' → 113 ('q') |
Essas funções só conhecem a tabela ASCII: std::toupper não transforma ç em Ç. Para textos inteiros (std::string), você vai aplicá-las letra por letra em Acessar Caracteres.
Missão: o programa deveria mostrar a resposta em maiúscula, Resposta: S, mas mostra Resposta: 83. Conserte a linha do cout.
#include <cctype>
#include <iostream>
int main() {
char resposta = 's';
std::cout << "Resposta: " << std::toupper(resposta) << "\n";
}
#include <cctype>
#include <iostream>
int main() {
char resposta = 's';
std::cout << "Resposta: " << static_cast<char>(std::toupper(resposta)) << "\n";
}
6. Por que 'ç' não cabe num char
#include <iostream>
int main() {
char letra = 'ç';
std::cout << letra << "\n";
std::cout << static_cast<int>(letra) << "\n";
}
$ g++ -std=c++23 -Wall -Wextra cedilha.cpp -o cedilha
cedilha.cpp:4:18: warning: multi-character character constant [-Wmultichar]
4 | char letra = 'ç';
| ^~~
cedilha.cpp: In function ‘int main()’:
cedilha.cpp:4:18: warning: overflow in conversion from ‘int’ to ‘char’ changes value from ‘50087’ to ‘-89’ [-Woverflow]
$ ./cedilha
� « um pedaço de letra que o terminal não sabe desenhar
-89
O mesmo aviso do 'Ana': multi-character character constant. Mas ç é uma letra só! O que aconteceu?
- O arquivo
.cppestá salvo em UTF-8, o jeito moderno de guardar texto, que tem todas as letras do mundo. No UTF-8, as letras do ASCII ocupam 1 byte, mas oçocupa 2 bytes (195 e 167). - Para o compilador,
'ç'é como'Ana': dois "caracteres" de 1 byte entre aspas simples. Ele os junta num número só: 195 × 256 + 167 = 50087. - Um
chartem 1 byte. Ao guardar 50087, sobra só o último byte, 167, que numcharcom sinal aparece como -89 (o overflow in conversion). - Na hora de mostrar, o
coutmanda meioçpara o terminal, que desenha�("não sei o que é isto").
O Clang é mais rígido e recusa o programa: error: character too large for enclosing character literal type ("caractere grande demais para o tipo de literal de caractere").
Como guardar letras acentuadas, então? Num std::string, entre aspas duplas: std::string letra = "ç";. O texto ocupa 2 bytes, e o terminal recebe o ç inteiro. Os detalhes do UTF-8, e o que acontece quando você conta as letras de "ação", estão na aula Acentos e UTF-8.
Caracteres especiais
Alguns caracteres não dá para digitar entre aspas simples, então têm um código com barra invertida, a sequência de escape:
| Escrita | Caractere | Código |
|---|---|---|
'\n' | Nova linha | 10 |
'\t' | Tabulação | 9 |
'\'' | A própria aspa simples | 39 |
'\\' | A própria barra invertida | 92 |
'\0' | O caractere nulo (marca o fim de textos no estilo C) | 0 |
Parecem dois caracteres, mas são um só. A lista completa está em Caracteres Especiais e Raw Strings.
Quando dá errado
error: invalid conversion from ‘const char*’ to ‘char’
O que significa: você pôs aspas duplas ("A") num char.
Como consertar: aspas simples para um caractere ('A'); ou mude a variável para std::string se é texto.
warning: multi-character character constant [-Wmultichar]
O que significa: entre aspas simples há mais de um byte: várias letras ('Ana') ou uma letra acentuada ('ç', 'é').
Como consertar: textos e letras acentuadas vão em std::string, com aspas duplas.
O que significa: a letra passou por uma conta ('a' + 1) ou por std::toupper, e virou int.
Como consertar: guarde num char ou converta: static_cast<char>(...).
O que significa: você usou o caractere '7' (código 55) como se fosse o número 7.
Como consertar: subtraia '0': int valor = digito - '0';.
Referência rápida
| Escrita | O que faz |
|---|---|
char c = 'A'; | Um caractere (aspas simples) |
static_cast<int>(c) | O código do caractere (65) |
static_cast<char>(66) | O caractere de um código (B) |
c + 1 | Conta: resultado int |
digito - '0' | Caractere de algarismo → número |
std::toupper(c), std::tolower(c) | Maiúscula/minúscula (devolvem int; <cctype>) |
std::isdigit(c), std::isalpha(c), std::isspace(c) | Perguntas: 0 = não, outro número = sim |
'\n', '\t', '\'', '\\' | Caracteres especiais |
Exercícios
1. Código da letra
Qual é o código ASCII de 'B'?
2. Algarismo para número
Complete para transformar o caractere '5' no número 5:
3. O que std::cout << 'a' + 1; mostra?
4. Qual destas linhas está certa?
5. Por que o g++ avisa multi-character character constant em char c = 'ç';?
Missão final: o dobro do algarismo
Missão: a Ana digitou o algarismo '7' num formulário, e o programa deveria mostrar o dobro, Dobro: 14. Mas mostra Dobro: 110. Por quê? (Dica: qual é o código de '7'?) Conserte a linha do valor.
#include <iostream>
int main() {
char digito = '7';
int valor = digito;
std::cout << "Dobro: " << valor * 2 << "\n";
}
#include <iostream>
int main() {
char digito = '7';
int valor = digito - '0';
std::cout << "Dobro: " << valor * 2 << "\n";
}
Resumo
charguarda um caractere, entre aspas simples:'A'. Texto vai entre aspas duplas, emstd::string.- Por dentro, um
charé um número (tabela ASCII):'A'= 65,'a'= 97,'0'= 48, espaço = 32.static_cast<int>(c)mostra o código. - Numa conta, o
charviraint:'a' + 1mostra 98. Guarde numcharou usestatic_cast<char>.digito - '0'dá o valor do algarismo. <cctype>:std::toupper/std::tolower(devolvemint!) e as perguntasstd::isdigit,std::isalpha,std::isspace… (0 = não; outro número = sim).'ç'ocupa 2 bytes em UTF-8 e não cabe numchar: avisomulti-character character constantno g++, erro no Clang. Usestd::string(aula Acentos e UTF-8).