Escrever um programa em C que leia uma cadeia de caracteres e imprima todas as palavras que contenham três ou mais vogais.

Passo 1

O enunciado pede: ler uma cadeia de caracteres e imprimir todas as palavras que contenham três ou mais vogais.
Informações relevantes que o enunciado fornece (ou que vou assumir, de forma explícita, para poder implementar sem ambiguidade):
  • A entrada é uma única cadeia de caracteres (uma linha de texto).
  • Precisamos identificar “palavras” e testar, para cada palavra, se ela tem pelo menos três vogais.
  • Vou considerar como vogais as letras: 'a', 'e', 'i', 'o', 'u' tanto em maiúsculas quanto em minúsculas (caso-insensível).
  • Vou definir “palavra” como uma sequência de caracteres alfabéticos (ou seja, letras). Caracteres que não são letras (espaço, pontuação, números, etc.) separam as palavras.
  • Não vou tratar letras acentuadas ( á, é, ôáéô etc.) como vogais especiais — isso exigiria tratamento de acordo com codificação/locale; aqui trataremos apenas as vogais ASCII mencionadas.
  • Saída: cada palavra que tiver três ou mais vogais será impressa (uma por linha, para ficar claro).

Passo 2

Escolha do método (o porquê):
Existem várias formas de fazer isso em C (por exemplo, usar `strtok` para separar por delimitadores, usar expressões regulares com bibliotecas extras, etc.). Vou usar um método bem básico e confiável: percorrer a string caractere a caractere, construir a palavra atual enquanto os caracteres forem letras, e ao encontrar um separador (ou o fim da cadeia) eu avalio a palavra construída. Motivos:
  • É um método que usa apenas biblioteca padrão de C (<stdio.h>, <ctype.h>, <string.h>), comum em provas.
  • Permite controlar exatamente o que é considerado letra e o que é delimitador.
  • É fácil de explicar e implementar sem funções avançadas.

Passo 3

Funções e conceitos da biblioteca que vamos usar (a mini-aula):
  • `fgets(buffer, size, stdin)`: lê uma linha de entrada segura (não ultrapassa o tamanho do buffer). Retorna \text{NULL} em caso de erro/fim de arquivo.
  • `strlen(s)`: obtem o comprimento (número de caracteres) da string `s`.
  • `isalpha\text{(c)}` (em <ctype.h>): retorna verdadeiro se `c` for uma letra (A–Z ou a–z). Atenção: o argumento deve ser convertido para `unsigned char` por segurança quando `char` for possivelmente negativo.
  • `tolower\text{(c)}` (em <ctype.h>): converte `c` para minúscula (se for letra). Também passe `unsigned char`.
  • Lógica básica de buffers: vamos manter um buffer para a string inteira e outro para construir a palavra atual; quando o separador aparece, finalizamos a palavra, avaliamos e limpamos o buffer da palavra.
  • Contagem de vogais: para cada letra adicionada à palavra incrementamos um contador se for vogal.
Exemplo rápido de uso:
  • Se a entrada for: “Programação em C é legal”, considerando apenas vogais ASCII sem acentos, as palavras seriam “Programacao”, “em”, “C”, “e”, “legal” (mas lembre que acentos seriam ignorados ou considerados não-letras dependendo do locale).

Passo 4

Pseudocódigo / lógica passo a passo (já bem mastigado, prepare para codificar):
  1. Ler a linha com `fgets` para um buffer grande o suficiente.
  2. Remover o caractere de nova linha final (se existir).
  3. Inicializar: índice do buffer da palavra `wlen = 0`, contador de vogais `vcount = 0`.
  4. Para cada caractere c da string (incluindo processar o '\0' ao final):
    • Se `isalpha\text{(c)}` for verdadeiro:
      • acrescentar c ao buffer da palavra (se ainda houver espaço).
      • se `tolower\text{(c)}` estiver entre a,e,i,o,u então incrementar vcount.
    • Senão (ou seja, c é separador ou final):
      • se wlen > 0 (temos uma palavra pronta):
        • terminar a palavra com '\0'.
        • se vcount >= 3 então imprimir a palavra.
        • resetar wlen = 0 e vcount = 0.
      • se c == '\0' então sair do laço (fim).
  5. Encerrar.
Observação importante: devemos lembrar de processar a última palavra após o fim da string — no pseudocódigo acima isso é tratado porque iteramos até incluir o '\0' e, ao vê-lo, o ramo “senão” trata a palavra final.

Passo 5

Implementação de como detectar vogal (mini-aula e cuidado prático):
  • Vamos criar uma função auxiliar simples:
    • Recebe um caractere c (tipo char).
    • Converte para minúscula com `tolower((unsigned char)c)`.
    • Verifica se é igual a 'a', 'e', 'i', 'o' ou 'u'.
    • Retorna 1 se for vogal, 0 caso contrário.
  • Por que converter para minúscula? Para tratar A e a do mesmo jeito sem duplicar verificações.
  • Por que usar `unsigned char` ao passar para tolower/isalpha? Para evitar comportamento indefinido quando char for negativo (em algumas implementações), é a prática segura.

Passo 6

Tratamento de limites, buffer overflow e saída:
  • Definir constantes: `MAX_LEN` para o tamanho da linha lida (por ex. 10000) e `MAX_WORD` para o tamanho máximo da palavra que guardaremos (por ex. 1000). Em provas, esses tamanhos são suficientes; mencionar que, em código de produção, considerar dinamicidade ou limites reais do problema.
  • Se uma palavra for maior que `MAX_WORD-1` vamos ignorar os caracteres excedentes para não estourar o buffer, mas continuar contando vogais (para não perder a condição) — implementamos essa estratégia simples no código.
  • Impressão: imprimo cada palavra que satisfaz a condição em uma linha separada com `printf("%s\n", word)`.

Passo 7

Complexidade e dicas para a prova (curta e motivadora):
  • Complexidade de tempo: O(n), onde `n` é o comprimento da cadeia de entrada, porque processamos cada caractere uma vez.
  • Complexidade de espaço: O(1) extra (além do buffer de entrada), pois só guardamos a palavra atual e contadores.
  • Dica para a prova: explique o algoritmo em poucas frases e diga que você percorre caractere a caractere e verifica letras/vogais; isso costuma ser suficiente para ganhar créditos antes de mostrar o código — depois entregue o código limpo.
  • Força aí! Respira, faz com calma, segue o passo a passo — você consegue.

Passo 8

Agora vem a implementação final. Ela segue tudo que expliquei: usa `fgets`, percorre caractere a caractere, constrói palavras com letras apenas, conta vogais (caso-insensível) e imprime as palavras que tiverem três ou mais vogais. Teste mental rápido: para entrada “Universidade de São Paulo”, como não tratamos acentos, “Universidade” (tem 6 vogais ASCII: u,i,e,i,a,e -> várias) será detectada e impressa; “de” não; “São” tem 1 vogal ASCII (o acento não contado), então não.

Resposta

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define MAX_LEN 10000
#define MAX_WORD 1000
int is_vowel(char c) {
c = tolower((unsigned char)c);
return (c == ‘a’ || c == ‘e’ || c == ‘i’ || c == ‘o’ || c == ‘u’);
}
int main(void) {
char s[MAX_LEN];
if (!fgets(s, sizeof s, stdin)) return 0;
size_t n = strlen(s);
if (n > 0 && s[n - 1] == '\n') s[n - 1] = '\0';

char word[MAX_WORD];
int wlen = 0;
int vcount = 0;

for (size_t i = 0; ; ++i) {
    char c = s[i];
    if (c != '\0' && isalpha((unsigned char)c)) {
        if (wlen < MAX_WORD - 1) {
            word[wlen++] = c;
        }
        if (is_vowel\text{(c)}) vcount++;
    } else {
        if (wlen > 0) {
            word[wlen] = '\0';
            if (vcount >= 3) {
                printf("%s\n", word);
            }
            wlen = 0;
            vcount = 0;
        }
        if (c == '\0') break;
    }
}

return 0;
}

Exercícios relacionados