C Classificar Caracteres (ctype.h)
"O CEP só tem algarismos?" "A senha tem pelo menos uma maiúscula?" "Esta resposta começa com S ou s?" Programas fazem perguntas assim o tempo todo, um caractere de cada vez. Dá para responder com contas na tabela ASCII, como em Caracteres (c >= '0' && c <= '9'), mas o C já traz as perguntas prontas, com nomes que se leem como frases: isdigit(c), "é algarismo?"; isupper(c), "é maiúscula?". Elas moram no cabeçalho <ctype.h> (de character type, "tipo de caractere"), junto com toupper e tolower, que trocam maiúscula e minúscula do jeito certo.
- Como perguntar "este caractere é um algarismo?" com
isdigit, e o que a função devolve. - A família completa:
isalpha,isalnum,isspace,isupper,islower,ispunct,isxdigit… - Como contar letras, algarismos e espaços de um texto, e validar um CEP.
- Como trocar maiúscula e minúscula com
toupperetolower. - Por que você nunca deve comparar o resultado com
== 1. - Por que se escreve
(unsigned char)antes do caractere, e por queçeãnão são letras para octype.h.
Todos os programas 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. Antes desta aula, veja Caracteres e Strings: aqui vamos percorrer strings letra por letra.
A ideia: a triagem dos Correios
Na agência dos Correios, cada pacote passa por uma esteira, e um funcionário faz perguntas simples: "é carta ou caixa?", "é para o Sul?", "é registrado?". Cada pergunta tem resposta sim ou não, e ele não precisa abrir o pacote para responder.
As funções is… do ctype.h são esse funcionário. Você entrega um caractere e faz uma pergunta. O nome de cada função é a pergunta em inglês: is ("é") + a categoria. isdigit = "is digit?", "é algarismo?". A resposta é um número: 0 quer dizer não; qualquer outro valor quer dizer sim (como no if, aula if e else).
1. A primeira pergunta: isdigit
#include <ctype.h>
#include <stdio.h>
int main(void) {
char c = '7';
if (isdigit(c)) {
printf("'%c' é um algarismo\n", c);
} else {
printf("'%c' não é um algarismo\n", c);
}
return 0;
}
- #include <ctype.h>
- Traz as funções de caractere. Sem ele, o compilador não conhece
isdigit(veja "Quando dá errado"). - isdigit(c)
- "O caractere
cé um dos algarismos'0'a'9'?" Devolve um número diferente de zero para sim e 0 para não. - if (isdigit(c))
- O
iftesta direto o resultado: diferente de zero é verdadeiro. É assim que se usa, sem comparar com nada.
$ gcc -std=c23 -Wall -Wextra digito.c -o digito $ ./digito '7' é um algarismo
O "sim" não é 1
Que número é esse "diferente de zero"? Vamos olhar:
#include <ctype.h>
#include <stdio.h>
int main(void) {
printf("isdigit('7') = %d\n", isdigit('7'));
printf("isdigit('x') = %d\n", isdigit('x'));
printf("isalpha('x') = %d\n", isalpha('x'));
printf("isupper('A') = %d\n", isupper('A'));
printf("isspace(' ') = %d\n", isspace(' '));
return 0;
}
$ gcc -std=c23 -Wall -Wextra valor.c -o valor
$ ./valor
isdigit('7') = 2048
isdigit('x') = 0
isalpha('x') = 1024
isupper('A') = 256
isspace(' ') = 8192
2048, 1024, 256… A norma do C só promete "zero ou diferente de zero". A biblioteca do Linux (a glibc) guarda as categorias de cada caractere como bits de um número (aula Máscaras de Bits) e devolve o bit da pergunta. No editor do guia, a biblioteca é outra e o mesmo programa mostra 1 em todas as respostas "sim". Os dois estão certos. A lição:
if (isdigit(c) == 1)
No notebook da Ana, isdigit('7') == 1 é 2048 == 1, falso: o programa diria que '7' não é algarismo. No editor, daria certo, e o erro ficaria escondido até alguém compilar com o gcc. Escreva if (isdigit(c)) para "sim" e if (!isdigit(c)) para "não". Se precisar guardar a resposta como 0 ou 1, use isdigit(c) != 0.
Missão: o programa pergunta se 'k' é um algarismo. Troque a pergunta: use isalpha ("is alphabetic?", "é uma letra?") e ajuste as duas mensagens, para a saída ser 'k' é uma letra. Depois, teste com 'K', '5' e '?'.
#include <ctype.h>
#include <stdio.h>
int main(void) {
char c = 'k';
if (isdigit((unsigned char) c)) {
printf("'%c' é um algarismo\n", c);
} else {
printf("'%c' não é um algarismo\n", c);
}
return 0;
}
#include <ctype.h>
#include <stdio.h>
int main(void) {
char c = 'k';
if (isalpha((unsigned char) c)) {
printf("'%c' é uma letra\n", c);
} else {
printf("'%c' não é uma letra\n", c);
}
return 0;
}
O (unsigned char) antes do c é um cuidado que todo programa com ctype.h deve ter. Por enquanto, aceite; a seção 5 explica o porquê.
2. A família completa
Todas as funções is… recebem um caractere e devolvem zero (não) ou diferente de zero (sim). Para os caracteres da tabela ASCII, as respostas são estas:
| Função | Pergunta (em inglês → português) | "Sim" para |
|---|---|---|
isdigit(c) | is digit? → é algarismo? | 0 a 9 |
isalpha(c) | is alphabetic? → é letra? | a a z e A a Z |
isalnum(c) | is alphanumeric? → é letra ou algarismo? | o que é isalpha ou isdigit |
isupper(c) | is upper case? → é maiúscula? | A a Z |
islower(c) | is lower case? → é minúscula? | a a z |
isspace(c) | is space? → é espaço em branco? | espaço, \t (tab), \n (Enter), \r, \v, \f |
isblank(c) C99 | is blank? → é espaço na linha? | só o espaço e o \t |
ispunct(c) | is punctuation? → é pontuação? | ! " # , . ; ? @ _ - e os outros símbolos visíveis |
isxdigit(c) | is hex digit? → é algarismo hexadecimal? | 0–9, a–f, A–F |
isprint(c) | is printable? → aparece na tela? | tudo que é visível, mais o espaço |
isgraph(c) | is graphic? → tem desenho? | o mesmo que isprint, menos o espaço |
iscntrl(c) | is control? → é caractere de controle? | os invisíveis: \n, \t, '\0'… (códigos 0 a 31 e 127) |
Para ver várias perguntas de uma vez, este programa passa por cada caractere de um texto e responde sete delas:
#include <ctype.h>
#include <stdio.h>
int main(void) {
char texto[] = "Ana, 29 anos!";
printf("char alpha digit alnum space upper lower punct\n");
for (int i = 0; texto[i] != '\0'; i++) {
unsigned char c = texto[i];
printf(" '%c' %3s %3s %3s %3s %3s %3s %3s\n", c,
isalpha(c) ? "sim" : "-",
isdigit(c) ? "sim" : "-",
isalnum(c) ? "sim" : "-",
isspace(c) ? "sim" : "-",
isupper(c) ? "sim" : "-",
islower(c) ? "sim" : "-",
ispunct(c) ? "sim" : "-");
}
return 0;
}
- for (int i = 0; texto[i] != '\0'; i++)
- Anda pela string até a marca de fim, como em Strings.
- unsigned char c = texto[i];
- Copia o caractere para um
unsigned char(o mesmo cuidado do(unsigned char), escrito de outro jeito: seção 5). - isalpha(c) ? "sim" : "-"
- O operador ternário (aula Ternário): se a resposta é diferente de zero, mostra
"sim"; se é zero,"-".
$ gcc -std=c23 -Wall -Wextra tabela.c -o tabela $ ./tabela char alpha digit alnum space upper lower punct 'A' sim - sim - sim - - 'n' sim - sim - - sim - 'a' sim - sim - - sim - ',' - - - - - - sim ' ' - - - sim - - - '2' - sim sim - - - - '9' - sim sim - - - - ' ' - - - sim - - - 'a' sim - sim - - sim - 'n' sim - sim - - sim - 'o' sim - sim - - sim - 's' sim - sim - - sim - '!' - - - - - - sim
Repare: cada caractere do ASCII visível cai em exatamente uma destas três: letra, algarismo ou pontuação. O espaço não é nenhuma das três. E isalnum é só "letra ou algarismo", muito usado para validar nomes de usuário.
Experimente: troque o texto por "#1A2b3G" (uma cor em hexadecimal, com um erro no fim) e acrescente uma coluna com isxdigit(c). Qual caractere não é hexadecimal? Teste também um texto com \t no meio: o isspace responde "sim", e o %c mostra um tab.
#include <ctype.h>
#include <stdio.h>
int main(void) {
char texto[] = "Ana, 29 anos!";
printf("char alpha digit space punct\n");
for (int i = 0; texto[i] != '\0'; i++) {
unsigned char c = texto[i];
printf(" '%c' %3s %3s %3s %3s\n", c,
isalpha(c) ? "sim" : "-",
isdigit(c) ? "sim" : "-",
isspace(c) ? "sim" : "-",
ispunct(c) ? "sim" : "-");
}
return 0;
}
3. Contar e validar
Com uma pergunta por caractere e um laço, dá para contar e para conferir textos inteiros.
Contar letras, algarismos e espaços
#include <ctype.h>
#include <stdio.h>
int main(void) {
char frase[] = "Pedido 42: 3 cafes e 2 bolos, por favor!";
int letras = 0, algarismos = 0, espacos = 0, outros = 0;
for (int i = 0; frase[i] != '\0'; i++) {
unsigned char c = frase[i];
if (isalpha(c)) {
letras++;
} else if (isdigit(c)) {
algarismos++;
} else if (isspace(c)) {
espacos++;
} else {
outros++;
}
}
printf("%s\n", frase);
printf("letras: %d, algarismos: %d, espaços: %d, outros: %d\n",
letras, algarismos, espacos, outros);
return 0;
}
$ gcc -std=c23 -Wall -Wextra contar.c -o contar $ ./contar Pedido 42: 3 cafes e 2 bolos, por favor! letras: 25, algarismos: 4, espaços: 8, outros: 3 « os outros: ':' ',' '!'
O else if (aula else if) garante que cada caractere entra numa conta só. "cafes" está sem acento de propósito: a seção 6 mostra o que o ctype.h faz com o é.
Validar um CEP
Na lojinha, o CEP de entrega tem de ter o formato 01310-100: 9 caracteres, um traço na posição 5 e algarismos no resto.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void) {
char cep[] = "01310-100";
int ok = strlen(cep) == 9 && cep[5] == '-';
for (int i = 0; ok && i < 9; i++) {
if (i != 5 && !isdigit((unsigned char) cep[i])) {
ok = 0;
}
}
printf("%s: %s\n", cep, ok ? "CEP válido" : "CEP inválido");
return 0;
}
- int ok = strlen(cep) == 9 && cep[5] == '-';
- Começa conferindo o tamanho (
strlen, aula Funções de String) e o traço. O resultado da comparação é 1 ou 0. Se o tamanho estiver errado, o&&nem olha ocep[5](aula Operadores Lógicos). - ok && i < 9
- O laço para assim que algo der errado: não adianta continuar olhando.
- i != 5 && !isdigit(…)
- "Não é a posição do traço e não é algarismo": então o CEP é inválido. O
!inverte a resposta doisdigit.
$ gcc -std=c23 -Wall -Wextra cep.c -o cep $ ./cep 01310-100: CEP válido
Troque o CEP por "0131O-100" (com a letra O no lugar do zero) e o programa diz CEP inválido. Para transformar o CEP já validado em número, use strtol (aula Texto ↔ Número).
4. Trocar maiúscula e minúscula: toupper e tolower
toupper ("to upper case", "para maiúscula") recebe um caractere e devolve a versão maiúscula. tolower faz o contrário. O detalhe que importa: se o caractere não é letra, elas devolvem o mesmo caractere, sem mexer.
#include <ctype.h>
#include <stdio.h>
int main(void) {
char nome[] = "ana maria, 29!";
for (int i = 0; nome[i] != '\0'; i++) {
nome[i] = (char) toupper((unsigned char) nome[i]);
}
printf("%s\n", nome);
printf("tolower('Q') = %c\n", tolower('Q'));
printf("toupper('!') = %c\n", toupper('!'));
printf("'!' - 32 = %c\n", '!' - 32);
return 0;
}
- toupper((unsigned char) nome[i])
- Calcula a maiúscula da letra da posição
i. A função não muda a string: ela só devolve um valor novo. - nome[i] = (char) …
- Por isso o resultado tem de ser guardado de volta na posição. O
toupperdevolve umint; o(char)deixa claro que você sabe que ele vai virarchar. - toupper('!')
- Não é letra: volta o próprio
'!'. Os espaços, a vírgula e o 29 do nome também passaram intactos. - '!' - 32
- O truque da aula Caracteres, subtrair 32, aplicado a algo que não é letra: 33 − 32 = 1, um caractere de controle invisível.
$ gcc -std=c23 -Wall -Wextra maiusculas.c -o maiusculas
$ ./maiusculas
ANA MARIA, 29!
tolower('Q') = q
toupper('!') = !
'!' - 32 = « o código 1: invisível no terminal
Esse é o motivo de preferir toupper à conta com 32: a conta só funciona se você tiver certeza de que o caractere é uma letra minúscula. O toupper confere sozinho.
Missão: o cadastro da lojinha recebeu o nome todo em minúsculas. Deixe maiúscula só a primeira letra de cada palavra, para mostrar Ana Maria Souza. Dica: um caractere é começo de palavra quando é o primeiro (i == 0) ou quando o anterior (nome[i - 1]) é um espaço.
#include <ctype.h>
#include <stdio.h>
int main(void) {
char nome[] = "ana maria souza";
for (int i = 0; nome[i] != '\0'; i++) {
// se nome[i] começa uma palavra, troque por maiúscula
}
printf("%s\n", nome);
return 0;
}
#include <ctype.h>
#include <stdio.h>
int main(void) {
char nome[] = "ana maria souza";
for (int i = 0; nome[i] != '\0'; i++) {
if (i == 0 || nome[i - 1] == ' ') {
nome[i] = (char) toupper((unsigned char) nome[i]);
}
}
printf("%s\n", nome);
return 0;
}
O i == 0 || vem primeiro de propósito: quando i é 0, o || já tem a resposta e não calcula nome[i - 1], que seria nome[-1], fora do array (aula Arrays).
Comparar sem ligar para maiúsculas
Um uso muito comum: aceitar S ou s como "sim". Em vez de if (r == 's' || r == 'S'), converta antes: if (tolower((unsigned char) r) == 's'). A aula Validar a Entrada usa esse truque para ler respostas do teclado.
5. Por que (unsigned char)
Até aqui, todo caractere passou por um (unsigned char) antes de entrar numa função do ctype.h. O motivo está na regra da norma do C: essas funções só aceitam um valor que caiba num unsigned char (de 0 a 255) ou o valor especial EOF (o "fim de arquivo" do getchar, que vale −1). Qualquer outro número negativo é comportamento indefinido.
E um char comum pode ser negativo. No Linux de PC (e no editor), ele vai de −128 a 127 (aula Inteiros). As letras do ASCII são todas positivas, mas os bytes de uma letra acentuada passam de 127 e, num char, viram negativos:
#include <ctype.h>
#include <stdio.h>
int main(void) {
char palavra[] = "é";
char c = palavra[0];
printf("como char: %d\n", c);
printf("como unsigned char: %d\n", (unsigned char) c);
printf("isalpha(c) = %d\n", isalpha(c));
printf("toupper(c) = %d\n", toupper(c));
return 0;
}
$ gcc -std=c23 -Wall -Wextra negativo.c -o negativo « nenhum aviso $ ./negativo como char: -61 como unsigned char: 195 isalpha(c) = 0 toupper(c) = 195
O primeiro byte do é é o 195; num char, ele aparece como −61. O toupper(-61) devolveu 195 no gcc. No editor do guia, o mesmo programa mostrou toupper(c) = -61. Duas bibliotecas, dois resultados, porque a norma não diz o que acontece com −61: é comportamento indefinido (aula Comportamento Indefinido). Na biblioteca do Windows, em modo de depuração, um valor negativo chega a interromper o programa com um alerta.
O conserto é sempre o mesmo: converter para unsigned char antes. Com (unsigned char) c, a função recebe 195, um valor permitido, e todas as bibliotecas dão a mesma resposta. Há dois jeitos de escrever:
| Jeito | Exemplo | Quando usar |
|---|---|---|
| Converter na chamada | isdigit((unsigned char) s[i]) | Uma pergunta só, no meio de um if |
| Guardar numa variável | unsigned char c = s[i]; e depois isdigit(c) | Várias perguntas sobre o mesmo caractere (como no contar.c) |
| Sem converter | isdigit('7') | Só com um caractere fixo escrito entre aspas simples, que você sabe que é ASCII |
getchar?
O getchar (aula Caracteres) já devolve um int no formato certo: de 0 a 255, ou EOF. Se você guardar o resultado num int c, pode passar direto: isdigit(c). O (unsigned char) é para caracteres que vêm de um array de char, como uma string.
6. Acentos não são letras para o ctype.h
A Ana tentou contar as letras de "maçã":
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void) {
char palavra[] = "maçã";
int letras = 0;
for (int i = 0; palavra[i] != '\0'; i++) {
unsigned char c = palavra[i];
printf("byte %d: %3d isalpha: %s\n", i, c, isalpha(c) ? "sim" : "não");
if (isalpha(c)) {
letras++;
}
}
printf("isalpha contou %d letras em \"%s\" (%zu bytes)\n", letras, palavra, strlen(palavra));
return 0;
}
$ gcc -std=c23 -Wall -Wextra acento.c -o acento $ ./acento byte 0: 109 isalpha: sim byte 1: 97 isalpha: sim byte 2: 195 isalpha: não « primeira metade do ç byte 3: 167 isalpha: não « segunda metade do ç byte 4: 195 isalpha: não « primeira metade do ã byte 5: 163 isalpha: não « segunda metade do ã isalpha contou 2 letras em "maçã" (6 bytes)
"maçã" tem 4 letras, mas 6 bytes: o ç e o ã ocupam 2 bytes cada na codificação UTF-8, a usada pelos arquivos e terminais de hoje. As funções do ctype.h olham um byte por vez, e nenhuma metade de letra é uma letra. O editor dá exatamente a mesma resposta. Na prática:
- o
ctype.hé perfeito para o que é ASCII: algarismos, CEP, CPF, códigos de produto, senhas, comandos, respostas "s/n"; - para contar ou converter letras acentuadas de português, ele não serve sozinho. O
touppernão transformaçemÇ, nemãemÃ.
Como o C lida com acentos de verdade (bytes, strlen que conta "a mais", caracteres largos e setlocale) é o assunto da próxima aula, Acentos e UTF-8.
Formas diferentes: contas com a tabela ou ctype.h?
As duas formas abaixo respondem igual para caracteres ASCII:
| Pergunta | Com contas | Com ctype.h |
|---|---|---|
| É algarismo? | c >= '0' && c <= '9' | isdigit(c) |
| É minúscula? | c >= 'a' && c <= 'z' | islower(c) |
| É letra? | (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') | isalpha(c) |
| É espaço em branco? | c == ' ' || c == '\t' || c == '\n' || … | isspace(c) |
| Para maiúscula | if (c >= 'a' && c <= 'z') c = c - 32; | c = toupper(c); |
Qual usar: o ctype.h. O código fica mais curto, se lê como uma frase, e não há como esquecer um caso (quem lembra do \v no "é espaço?"). A conta manual faz sentido em dois lugares: c - '0' para transformar o algarismo em número (depois de conferir com isdigit), e quando você quer exatamente um intervalo que não é uma categoria pronta, como "é uma letra de a a f?".
O locale (as "configurações regionais": idioma, formato de número, de data) pode mudar as respostas para os bytes acima de 127. Um programa começa sempre no locale "C", em que só o ASCII tem categoria, e só muda se chamar setlocale. Mesmo com o locale português em UTF-8 ligado, um byte sozinho de uma letra acentuada continua não sendo letra (seção 6). A aula Acentos e UTF-8 mostra o setlocale.
Quando dá errado
error: implicit declaration of function ‘isdigit’ [-Wimplicit-function-declaration]
O que significa: faltou o #include <ctype.h>. O compilador não conhece a função. O gcc 15 até diz o que fazer, na linha seguinte: note: include ‘<ctype.h>’ or provide a declaration of ‘isdigit’ ("inclua o <ctype.h> ou declare isdigit"), e mostra onde a linha entraria (+#include <ctype.h>). No editor, o Clang diz call to undeclared library function 'isdigit' with type 'int (int)' e dá a mesma dica.
Como consertar: #include <ctype.h> no topo do arquivo.
toupper; e o aviso warning: statement with no effect [-Wunused-value]
O que significa: você escreveu toupper((unsigned char) nome[i]); sozinho na linha. A função calculou a maiúscula e o resultado foi jogado fora: o programa mostrou ana, em minúsculas. O gcc avisa "comando sem efeito"; o Clang do editor diz ignoring return value of function declared with pure attribute ("ignorando o valor devolvido por uma função que só calcula").
Como consertar: guarde o resultado: nome[i] = (char) toupper((unsigned char) nome[i]);.
if (isdigit(c) == 1) diz "não" para um algarismo
O que significa: no gcc (glibc), isdigit('7') devolve 2048, e não 1. O "sim" é qualquer valor diferente de zero. No editor, o mesmo código funciona por acaso, porque lá o "sim" é 1.
Como consertar: if (isdigit(c)) ou if (isdigit(c) != 0). Nunca == 1 nem == true.
Falha de segmentação com isdigit("7")
O que significa: aspas duplas criam uma string (um endereço na memória), não um caractere. No gcc do laboratório, if (isdigit("7")) compilou sem nenhum aviso (na glibc, isdigit é uma macro que esconde o problema) e, ao rodar, caiu com Falha de segmentação, código 139. O Clang do editor recusa na compilação: error: incompatible pointer to integer conversion passing 'char[2]' to parameter of type 'int' ("conversão de ponteiro para inteiro incompatível").
Como consertar: aspas simples para um caractere: isdigit('7'). Para conferir um texto inteiro, use um laço, como no cep.c.
O que significa: em UTF-8, cada acentuada ocupa 2 bytes, e o ctype.h olha um byte por vez (seção 6).
Como consertar: para dados ASCII (códigos, números, senhas), está certo como está. Para texto em português, veja Acentos e UTF-8.
Referência rápida
| Função | Devolve "sim" (diferente de zero) para |
|---|---|
isdigit(c) | '0' a '9' |
isxdigit(c) | '0'–'9', 'a'–'f', 'A'–'F' |
isalpha(c) | letras (no locale "C": só a–z, A–Z) |
isalnum(c) | letras e algarismos |
isupper(c) / islower(c) | maiúsculas / minúsculas |
isspace(c) | ' ', '\t', '\n', '\r', '\v', '\f' |
isblank(c) | ' ' e '\t' (C99) |
ispunct(c) | símbolos visíveis que não são letra nem algarismo |
isprint(c) / isgraph(c) | visíveis, com / sem o espaço |
iscntrl(c) | caracteres de controle (códigos 0–31 e 127) |
toupper(c) / tolower(c) | Devolvem a maiúscula / minúscula; o que não é letra volta igual |
(unsigned char) s[i] | Sempre antes de passar um char de uma string |
if (isdigit(c)) | O jeito certo de testar (nunca == 1) |
Exercícios
1. O cabeçalho
Complete para poder usar isdigit e toupper:
2. A pergunta certa
Qual função responde "é espaço, tab ou Enter?"
3. Para minúscula
Complete para guardar em r a versão minúscula de resposta:
4. O que toupper('7') devolve?
5. No gcc do Linux, isdigit('5') pode devolver 2048. O que isso quer dizer?
6. Por que se escreve isalpha((unsigned char) s[i]) e não só isalpha(s[i])?
7. Para o ctype.h, quantas letras tem a string "pão", em UTF-8?
Missão final: a senha forte
Missão: o sistema da lojinha só aceita senhas com pelo menos 8 caracteres, uma maiúscula, uma minúscula e um algarismo. Complete o laço para contar as maiúsculas (isupper), as minúsculas (islower) e os algarismos (isdigit) de senha. O resto do programa já decide se a senha é forte. Sem avisos. Depois, teste com "lojinha" e com "LOJINHA2026".
Maiúsculas: 1 Minúsculas: 6 Algarismos: 4 Senha forte
#include <ctype.h>
#include <stdio.h>
int main(void) {
char senha[] = "Lojinha2026";
int maiusculas = 0, minusculas = 0, algarismos = 0, tamanho = 0;
for (int i = 0; senha[i] != '\0'; i++) {
unsigned char c = senha[i];
// conte aqui o tipo do caractere c
tamanho++;
}
printf("Maiúsculas: %d\n", maiusculas);
printf("Minúsculas: %d\n", minusculas);
printf("Algarismos: %d\n", algarismos);
if (tamanho >= 8 && maiusculas > 0 && minusculas > 0 && algarismos > 0) {
printf("Senha forte\n");
} else {
printf("Senha fraca\n");
}
return 0;
}
#include <ctype.h>
#include <stdio.h>
int main(void) {
char senha[] = "Lojinha2026";
int maiusculas = 0, minusculas = 0, algarismos = 0, tamanho = 0;
for (int i = 0; senha[i] != '\0'; i++) {
unsigned char c = senha[i];
if (isupper(c)) {
maiusculas++;
} else if (islower(c)) {
minusculas++;
} else if (isdigit(c)) {
algarismos++;
}
tamanho++;
}
printf("Maiúsculas: %d\n", maiusculas);
printf("Minúsculas: %d\n", minusculas);
printf("Algarismos: %d\n", algarismos);
if (tamanho >= 8 && maiusculas > 0 && minusculas > 0 && algarismos > 0) {
printf("Senha forte\n");
} else {
printf("Senha fraca\n");
}
return 0;
}
A solução testa com if direto (nunca == 1) e usa else if, porque um caractere não pode ser maiúscula e algarismo ao mesmo tempo. Um sistema de verdade também exigiria um símbolo: seria mais um contador com ispunct.
Resumo
- O
<ctype.h>traz perguntas prontas sobre um caractere:isdigit,isalpha,isalnum,isspace,isupper,islower,ispunct,isxdigit,isprint,iscntrl… - A resposta é 0 para "não" e qualquer outro valor para "sim" (2048 no gcc, 1 no editor). Teste com
if (isdigit(c)), nunca com== 1. toupperetolowerdevolvem a letra convertida e deixam o resto igual. Elas não mudam a string: guarde o resultado (s[i] = (char) toupper(…)).- Sempre
(unsigned char)antes de passar umcharde uma string: valores negativos são comportamento indefinido, e o resultado muda de uma biblioteca para outra. - Com um laço, as perguntas contam e validam textos: CEP, senha, códigos.
- O
ctype.holha um byte por vez: os acentos do UTF-8 (2 bytes) não são letras para ele. Para isso, veja Acentos e UTF-8.