Escrever um programa em C que calcule a frequência de uso de cada palavra dentro de uma cadeia de caracteres que possui diversas palavras. Considerar o tamanho máximo da cadeia como sendo de 80 colunas.
Passo 1
O enunciado pede: escrever um programa em C que calcule a frequência de uso de cada palavra dentro de uma cadeia de caracteres que possui diversas palavras. O tamanho máximo da cadeia é de
colunas. \n
Informações/dados relevantes (explicitando suposições que vou usar para resolver o problema, já que o enunciado não detalha alguns pontos):\n
Informações/dados relevantes (explicitando suposições que vou usar para resolver o problema, já que o enunciado não detalha alguns pontos):\n
- Vou assumir que a entrada é uma única linha de texto com no máximo
caracteres (mais o caractere nulo).\n - Defino “palavra” como uma sequência de caracteres alfanuméricos (letras e dígitos). Ou seja, qualquer caractere que não seja letra nem dígito funciona como separador (espaço, pontuação, etc.).\n
- O reconhecimento de palavras será feito de forma case-insensitive (não diferencio maiúsculas/minúsculas). Assim, “Teste”, “teste” e “TESTE” contam como a mesma palavra.\n
- Vou armazenar as palavras distintas usando um vetor de estruturas com espaço suficiente para, no pior caso, uma palavra por caractere (ou seja, até
palavras), cada palavra com tamanho máximo .\n - O programa vai imprimir cada palavra seguida da sua contagem, na ordem em que as palavras distintas aparecem pela primeira vez na linha.\n
Passo 2
Estratégia/algoritmo (visão geral passo a passo):\n
- Ler a linha de entrada usando uma função segura como \verb|fgets| para garantir que não ultrapassamos o limite de
caracteres.\n - Percorrer a linha caractere a caractere e construir tokens (palavras) quando encontrarmos caracteres alfanuméricos; ao encontrar um separador, fechar o token atual (se existir) e processá-lo.\n
- Para cada token obtido (já normalizado para minúsculas), procurar no vetor de palavras já armazenadas: se encontrado, incrementar o contador; se não encontrado, adicionar uma nova entrada com contador
.\n - Ao fim do processamento, imprimir as palavras e suas frequências.\n
Passo 3
Estruturas de dados e funções C que vamos usar (explicando didaticamente):\n
- Arrays de char (strings em C): uma string é um array de caracteres terminado por
'\0'. Para armazenar atécaracteres utilizamos um array com tamanho para deixar espaço ao terminador nulo.\n - struct para palavra e contagem: uma estrutura com um campo
char word[81]eint countpermite guardar a palavra e quantas vezes ela apareceu.\n - Função \verb|fgets(buffer, size, stdin)|: lê no máximo
size-1caracteres e coloca um'\0'ao final; também capta o'\n'se houver.\n- Funções dectype.h: \verb|isalnum(c)| diz se o caractere é letra ou dígito; \verb|tolower(c)| converte caractere para minúsculo. Importantíssimo: passarunsigned charpara essas funções para evitar UB com chars negativos.\n- Funções destring.h: \verb|strcmp(a,b)| compara strings; \verb|strcpy(dest, src)| copia strings; \verb|strlen(s)| dá o comprimento (não usado obrigatoriamente aqui).\n\nExplicação prática curta: ao montar um token, vamos usar um pequeno buffertoken[]. Quando um separador aparece, terminamostokencom'\0'e buscamos no vetor de structs usandostrcmp. Se igual, incrementamoscount, senão usamosstrcpypara gravar a nova palavra no vetor.\n
Passo 4
Pseudocódigo detalhado (para ajudar a transformar em C sem surpresas):\n
- Inicializar
words_count = 0(número de palavras distintas armazenadas).\n- Ler a linha comfgets(line, sizeof line, stdin).\n- Para cada caracterecda linha (incluindo o'\0'no final):\n - Seisalnum\text{(c)}: acrescentartolower\text{(c)}aotoken(se houver espaço no token).\n - Senão (é separador): setokennão estiver vazio, então:\n - terminartokencom'\0';\n - procurartokenemwords[0..words_count-1]comstrcmp;\n - se achar incrementacount; se não achar, copiartokenparawords[words_count].word, setarcount = 1ewords_count++;\n - esvaziartoken(resetar comprimento para 0).\n- Depois do loop, pode haver token pendente se a linha terminou com caractere alfanumérico: tratar do mesmo modo.\n- Imprimir todas as entradas dewordscomprintf("%s: %d\n", word, count).\n
Passo 5
Decisões e alternativas (por que escolhi este método):\n
- Poderíamos usar tabelas de hash para acelerar buscas (bom para grandes textos), mas o enunciado limita a linha a
colunas e é questão de graduação básica — então um vetor com busca linear é simples, fácil de implementar na prova e suficiente em desempenho para esse tamanho.\n- Optei por normalizar para minúsculas para tratar casos de capitalização. Poderíamos tratar case-sensitive, mas isso tornaria a resposta menos útil na maioria dos exercícios práticos.\n
Passo 6
Boas práticas e cuidados (o que observar na hora da implementação na prova):\n
- Sempre proteger leituras com limites (usar
fgetscom o tamanho do buffer).\n- Ao usar funções dectype.hconverta ocharparaunsigned charantes de passar paraisalnum/tolower, por segurança.\n- Garantir que os buffers de palavras têm espaço para o terminador nulo'\0'.\n- Evitar overflow ao acrescentar caracteres aotoken: verificar o comprimento máximo.\n- Lembre-se de tratar o token que pode ficar no buffer ao atingir o fim da string (quando o último caractere é alfanumérico).\n
Passo 7
Programa em C com comentários explicativos (este é o código que você escreveria na prova). Ele lê uma linha (até
caracteres), conta a frequência das palavras e imprime o resultado na ordem de primeira aparição:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_LINE 80
#define MAX_WORDS 80
#define MAX_WORD_LEN 80
typedef struct {
char word[MAX_WORD_LEN + 1];
int count;
} Word;
int main(void) {
char line[MAX_LINE + 2]; /* +2 para '\n' possível e '\0' */
Word words[MAX_WORDS];
int words_count = 0;
/* Inicializa contadores */
for (int i = 0; i < MAX_WORDS; i++) {
words[i].word[0] = '\0';
words[i].count = 0;
}
/* Lê a linha de entrada */
if (fgets(line, sizeof(line), stdin) == NULL) {
return 0; /* sem entrada */
}
/* Processa caractere a caractere */
char token[MAX_WORD_LEN + 1];
int tlen = 0;
for (int i = 0; ; i++) {
unsigned char c = (unsigned char) line[i];
/* termina quando alcança o caractere nulo */
if (c == '\0') {
if (tlen > 0) {
token[tlen] = '\0';
/* processa token final */
int found = 0;
for (int j = 0; j < words_count; j++) {
if (strcmp(words[j].word, token) == 0) {
words[j].count++;
found = 1;
break;
}
}
if (!found && words_count < MAX_WORDS) {
strcpy(words[words_count].word, token);
words[words_count].count = 1;
words_count++;
}
tlen = 0;
}
break;
}
if (isalnum\text{(c)}) {
/* adicionar caractere em minúscula ao token, se houver espaço */
if (tlen < MAX_WORD_LEN) {
token[tlen++] = (char) tolower\text{(c)};
}
/* se token atingir MAX_WORD_LEN, ignoramos excesso para evitar overflow */
} else {
/* separador encontrado: se havia token, processá-lo */
if (tlen > 0) {
token[tlen] = '\0';
int found = 0;
for (int j = 0; j < words_count; j++) {
if (strcmp(words[j].word, token) == 0) {
words[j].count++;
found = 1;
break;
}
}
if (!found && words_count < MAX_WORDS) {
strcpy(words[words_count].word, token);
words[words_count].count = 1;
words_count++;
}
tlen = 0;
}
/* caso contrário, apenas ignoramos sequências de separadores */
}
}
/* Imprime resultado: palavra: frequência */
for (int i = 0; i < words_count; i++) {
printf("%s: %d\n", words[i].word, words[i].count);
}
return 0;
}
Passo 8
Explicação do código e exemplo rápido:\n
- O loop principal percorre a string
lineaté o'\0'.\n-isalnumdetecta letras e dígitos; quando isso acontece adicionamos o caractere convertido portoloweraotoken(garantindo não ultrapassarMAX_WORD_LEN).\n- Ao encontrar um separador (ou o fim da linha), se otokentiver conteúdo, comparamos linearmente com aswordsjá registradas; se achar, incrementamoscount, senão criamos uma nova entrada.\n- Impressão final mostra cada palavra com seu número de ocorrências na ordem de primeira aparição.\n\nExemplo de uso (entrada -> saída):\nEntrada:\nThis is a test. This test is simple!\nSaída esperada (cada linhapalavra: frequência):\nthis: 2\nis: 2\na: 1\ntest: 2\nsimple: 1\n\nObservação: os resultados aparecem em minúsculas porque normalizamos tudo para minúsculas.\n
Resposta
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <string.h>
#include <ctype.h>
#define MAX_LINE 80
#define MAX_WORDS 80
#define MAX_WORD_LEN 80
#define MAX_WORDS 80
#define MAX_WORD_LEN 80
typedef struct {
char word[MAX_WORD_LEN + 1];
int count;
} Word;
char word[MAX_WORD_LEN + 1];
int count;
} Word;
int main(void) {
char line[MAX_LINE + 2]; /* +2 para ‘\n’ possível e ‘\0’ */
Word words[MAX_WORDS];
int words_count = 0;
char line[MAX_LINE + 2]; /* +2 para ‘\n’ possível e ‘\0’ */
Word words[MAX_WORDS];
int words_count = 0;
/* Inicializa contadores */
for (int i = 0; i < MAX_WORDS; i++) {
words[i].word[0] = '\0';
words[i].count = 0;
}
/* Lê a linha de entrada */
if (fgets(line, sizeof(line), stdin) == NULL) {
return 0; /* sem entrada */
}
/* Processa caractere a caractere */
char token[MAX_WORD_LEN + 1];
int tlen = 0;
for (int i = 0; ; i++) {
unsigned char c = (unsigned char) line[i];
/* termina quando alcança o caractere nulo */
if (c == '\0') {
if (tlen > 0) {
token[tlen] = '\0';
/* processa token final */
int found = 0;
for (int j = 0; j < words_count; j++) {
if (strcmp(words[j].word, token) == 0) {
words[j].count++;
found = 1;
break;
}
}
if (!found && words_count < MAX_WORDS) {
strcpy(words[words_count].word, token);
words[words_count].count = 1;
words_count++;
}
tlen = 0;
}
break;
}
if (isalnum\text{(c)}) {
/* adicionar caractere em minúscula ao token, se houver espaço */
if (tlen < MAX_WORD_LEN) {
token[tlen++] = (char) tolower\text{(c)};
}
/* se token atingir MAX_WORD_LEN, ignoramos excesso para evitar overflow */
} else {
/* separador encontrado: se havia token, processá-lo */
if (tlen > 0) {
token[tlen] = '\0';
int found = 0;
for (int j = 0; j < words_count; j++) {
if (strcmp(words[j].word, token) == 0) {
words[j].count++;
found = 1;
break;
}
}
if (!found && words_count < MAX_WORDS) {
strcpy(words[words_count].word, token);
words[words_count].count = 1;
words_count++;
}
tlen = 0;
}
/* caso contrário, apenas ignoramos sequências de separadores */
}
}
/* Imprime resultado: palavra: frequência */
for (int i = 0; i < words_count; i++) {
printf("%s: %d\n", words[i].word, words[i].count);
}
return 0;
}