Escrever um programa em C que calcule e imprima o número de caracteres distintos presentes em uma cadeia de caracteres dada. Considerar o tamanho máximo da cadeia como sendo de 80 colunas.

Passo 1

O enunciado pede que você escreva um programa em C que calcule e imprima o número de caracteres distintos presentes em uma cadeia de caracteres dada. Informações fornecidas pelo enunciado (vou listar bem claro):
  • O tamanho máximo da cadeia é ...80 ... colunas.
  • O programa deve ler uma única cadeia de entrada (uma linha) e imprimir a quantidade de caracteres diferentes que aparecem nela.
  • Não foi especificado ignorar espaços, pontuação ou diferenciar maiúsculas/minúsculas — portanto vou considerar que todos os caracteres possíveis na linha contam (espaço conta, ponto conta, e A e a são diferentes).
  • A saída esperada é apenas o número de caracteres distintos (seguido de uma nova linha, normalmente).

Passo 2

Decisões e suposições (não te pergunto nada, apenas explico o que vou usar):
  • Vou tratar os caracteres considerando seu valor de byte, isto é, cada possível código de caractere distinto (do conjunto de valores de 0 a 255) pode ser contado separadamente. Isso cobre a maioria dos casos práticos de entrada em C. Em resumo, vou usar uma tabela de presença de tamanho ...256 ....
  • Vou ler a linha com uma função segura (vou usar \texttt{fgets}) e garantir espaço suficiente no buffer para até ...80 ... caracteres mais o possível caractere de nova linha e o terminador nulo. Por isso o buffer terá tamanho \texttt{MAX + 2} quando \texttt{MAX} é ...80 ....
  • Vou remover o caractere de nova linha lido por \texttt{fgets} (se existir) para que ele não seja contado como parte da cadeia, pois a intenção usual é contar apenas os caracteres da linha digitada.

Passo 3

Estratégia algorítmica (explicação didática do método):
  • Idea geral: percorrer cada caractere da cadeia e marcar que esse caractere já apareceu. Toda vez que encontramos um caractere que ainda não apareceu, incrementamos o contador de distintos.
  • Estrutura usada: um vetor \texttt{seen} de inteiros com tamanho ...256 ..., inicializado com zeros. A posição \texttt{seen}[k] indica se já vimos o caractere cujo código de byte é k.
  • Por que ...256 ...? Porque um \texttt{unsigned char} tem valores de 0 a 255 e podemos indexar diretamente por esse valor.
  • Por que converter para \texttt{unsigned char}? Em C, o tipo \texttt{char} pode ser assinado ou não. Se for assinado, ao usá-lo como índice ele pode gerar índice negativo. Converter para \texttt{unsigned char} garante índices na faixa 0 255.
  • Complexidade: para uma cadeia de tamanho n, percorremos a cadeia uma vez, logo é O(n) em tempo. A memória usada é constante O(1) (o vetor \texttt{seen} tem tamanho fixo ...256 ...).

Passo 4

Leitura da entrada e tratamento de nova linha (detalhes práticos):
  • Defino \texttt{MAX = 80}. Vou declarar o buffer como \texttt{char s[MAX + 2];}. Explicando: \texttt{MAX + 2} dá espaço para até ...80 ... caracteres reais, mais um possível caractere de nova linha \(\backslash\)n e o terminador nulo \(\backslash\)0.
  • Uso \texttt{fgets(s, sizeof s, stdin)} para ler a linha. \texttt{fgets} lê no máximo \texttt{sizeof s - 1} caracteres e sempre termina a string com \(\backslash\)0\). Se houver uma nova linha e couber, ela também ficará em \texttt{s}.
  • Após a leitura, calculo o comprimento com \texttt{strlen(s)} e, se o último caractere for \(\backslash\)n, eu o substituo por \(\backslash\)0\) para que não seja contado.

Passo 5

Contagem passo a passo (o laço que faz a mágica):
  • Inicializo \texttt{int seen[256] = \{0\};} e \texttt{int count = 0;}.
  • Percorro a string com um índice \texttt{i} começando em ...0 ... e rodando enquanto \texttt{s[i] != '\\ 0'}.
  • Para cada caractere faço:
    • \texttt{unsigned char uc = (unsigned char)s[i];} — pega o código de byte não-negativo.
    • Se \texttt{seen[uc] == 0} então \texttt{seen[uc] = 1;} e \texttt{count++;}.
  • Ao final do laço, \texttt{count} contém o número de caracteres distintos na linha.

Passo 6

Exemplo concreto (para fixar a ideia):
  • Se a entrada for a string \texttt{"banana"}:
    • percorremos: \texttt{'b'} -> visto pela primeira vez -> \texttt{count = 1};
    • \texttt{'a'} -> visto pela primeira vez -> \texttt{count = 2};
    • \texttt{'n'} -> visto pela primeira vez -> \texttt{count = 3};
    • \texttt{'a'} -> já visto -> sem mudança;
    • \texttt{'n'} -> já visto -> sem mudança;
    • \texttt{'a'} -> já visto -> sem mudança;
    • Resultado: \texttt{count = 3}.
  • Se a entrada tiver espaços, por exemplo \texttt{"ola mundo"}, o espaço conta como um caractere separado.

Passo 7

Detalhes de implementação e boas práticas:
  • Inicializar \texttt{seen} com \texttt{\{0\}} garante zeros em todas as posições.
  • Usar \texttt{size_t} para índices quando for apropriado (por exemplo ao usar \texttt{strlen}), mas \texttt{int} para \texttt{count} é suficiente.
  • Imprimir com \texttt{printf("%d\n", count);} — isso mostra o número e quebra a linha.
  • Caso a entrada seja vazia (linha só com \(\backslash\)n ou sem caracteres), o programa imprime ...0 ....

Passo 8

Agora que você entendeu tudo passo a passo, aqui está o programa completo em C que implementa exatamente o que descrevemos (leitura segura, remoção de nova linha, tabela de presença de caracteres, contagem e impressão do resultado).

Resposta

#include <stdio.h>
#include <string.h>

#define MAX 80

int main(void) {
    char s[MAX + 2]; /* espaço para até 80 chars + possível '\n' + '\0' */
    if (fgets(s, sizeof s, stdin) == NULL) return 0;

    /* remover nova linha final, se presente */
    size_t len = strlen(s);
    if (len > 0 && s[len - 1] == '\n') {
        s[len - 1] = '\0';
    }

    int seen[256] = {0};
    int count = 0;

    for (size_t i = 0; s[i] != '\0'; ++i) {
        unsigned char uc = (unsigned char)s[i];
        if (!seen[uc]) {
            seen[uc] = 1;
            ++count;
        }
    }

    printf("%d\n", count);
    return 0;
}

Exercícios relacionados