Validar caracteres [Linguagem C]

Patrick_maura

Power Member
Boa tarde,

tenho uma duvida e precisava que alguém me desse uma ajuda.

O código é o seguinte:

Código:
do{
            printf("\nUtiliza conta poupanca-habitacao (1-Sim, 0-Nao):\n\n");
            printf("Opcao:");
            scanf("%d",&dad.conta_pouhab);
        }while(dad.conta_pouhab<0 || dad.conta_pouhab>1);

Nas aulas para validar os caracteres fazia-mos while (dad.conta_pouhab>'a' && dad.conta_pouhab<'z'), no entanto isso não está a dar resultado.

Como faço para validar os caracteres, ou seja, para que não seja possível introduzi-los?
 
falas em validar caracteres, mas o que eu vejo no código é uma variavel to tipo int.
pelo que percebo do código, queres que o utilizador insira 0 ou 1. então basta isto:

while (dad.conta_pouhab!=0 && dad.conta_pouhab!=1)
 
O que eu quero é que não seja possivel introduzir caracteres. Por exemplo, se for introduzido um numero qualquer alem de 0 ou 1 a pergunta é feita novamente porque aquela resposta nao é valida.. Quero fazer o mesmo para letras. Se introduzir uma letra, por exemplo o caracter x a pergunta é feita novamente.

Perceberam? Estou a ser confusa?
 
Usa antes uma implementação do getline. Supondo que estás a trabalhar em C, e não em C++, precisas de implementar a função. Tenho aqui uma de um projecto meu anterior:

Código:
/**
 * Getline implementation in C
 */
int getline(char *s, int lim) {
    char *t;
    int c;

    t = s;
    while((--lim > 1) && ((c=getchar()) != EOF) && (c != '\n'))
        *s++ = c;
    if(lim == 1) {
        fprintf(stderr, "WARNING. getline: Line too long.\n");
        exit(-1);
    }
    *s = '\0';
    return s - t;
}

É melhor prática. Depois disto, apenas tens de filtrar os "alcances" (ranges) usando a tabela ASCII da posição 0 do que foi lido. Se queres apenas letras, queres < codigo_do_z e > codigo_do_a. Se queres numeros, queres < codigo_do_9 e > codigo_do_0. Se forem números, não te esqueças de fazer o atoi do buffer[0].

Podes alterar ligeiramente o código para ler apenas o primeiro caracter e descartar todos os seguintes (mas descartá-los mesmo, senão ficam no buffer de entrada).
 
Eu percebi o teu problema e penso ter a solução.

-> dad.conta_pouhab é um inteiro.
-> Por defeito, os inteiros são inicializados com o valor 0.

Agora, pelo que eu pude testar (em Linux), o comportamento do scanf é que quando usas o placeholder %d (que é exclusivo para valores inteiros) e passas outra coisa que não seja números ao scanf pelo teclado, ele simplesmente limita-se a deixar o valor que estava na variável intocado. Ou seja, imagina que tinhas:

Código:
dad.conta_pouhab = 2000;

...e depois tinhas:

Código:
scanf("%d", &dad.conta_pouhab);

E nesta segunda operação, escrevias "abc" pelo teclado. Depois do scanf, a variável dad.conta_pouhab iria ter 2000 tal como tinha antes do scanf. Isto é, o valor só muda quando lhe passas um inteiro válido, que ele consegue processar.

Ora, isto resulta num problema muito grave no teu caso. Assumindo que a variável está realmente inicializada a 0, quando o utilizador mete lixo no input (i.e. texto em vez de algarismos), a variável continua com o valor 0...... QUE por acaso, é um valor válido para a tua verificação.

Moral da história: ou alteras o teu espaço de resultados possíveis de 0 e 1 para, por exemplo, 1 e 2; ou inicializas a variável com outro valor (-1 costuma ser uma boa opção). Fica ao teu critério :)
 
-> Por defeito, os inteiros são inicializados com o valor 0.

Esta afirmação não é necessariamente verdadeira. Comparem-se as seguintes instruções:

Código:
int x;
int y = 0;
Apenas a segunda garante que é um inteiro inicializado com o valor 0.

Quanto a essa questão do scanf, pode-se perfeitamente verificar se o utilizador introduziu um número inteiro - muito embora algumas pessoas possam não o saber, o scanf tem um valor de retorno, que corresponde ao número de conversões bem sucedidas.

Exemplo:

Código:
int valor_do_scanf = scanf("%d", &o_meu_int);
Quantos itens queremos converter neste caso? Apenas um, especificado pelo %d. Por isso, a variável "valor_do_scanf" tomará um de dois valores possíveis:

0, se a conversão para inteiro não tiver sido bem sucedida.
1, se a conversão para inteiro tiver sido bem sucedida.

Com isto, se o utilizador introduzir "abc" como disseste, a variável "o_meu_int" permanecerá inalterada de facto, mas possuímos agora outra variável "valor_do_scanf" que nos vai permitir detectar se houve algum erro.

Cumprimentos.
 
O teu problema é que a protecção do scanf não está a ser bem feita. Falta introduzir aí um scanf que descarte os caracteres não numéricos deixados pelo utilizador na entrada padrão bem como utilizar o valor de retorno do já existente para saber se ele leu correctamente um valor.

Fica assim então:

Código:
do {
    printf("\nUtiliza conta poupanca-habitacao (1-Sim, 0-Nao):\n\n");
    printf("Opcao:");
    j=scanf("%d",&dad);
    scanf("%*[^\n]");
}while((dad<0 || dad>1) && j<1);
 
O teu problema é que a protecção do scanf não está a ser bem feita. Falta introduzir aí um scanf que descarte os caracteres não numéricos deixados pelo utilizador na entrada padrão bem como utilizar o valor de retorno do já existente para saber se ele leu correctamente um valor.

Fica assim então:

Código:
do {
    printf("\nUtiliza conta poupanca-habitacao (1-Sim, 0-Nao):\n\n");
    printf("Opcao:");
    j=scanf("%d",&dad);
    scanf("%*[^\n]");
}while((dad<0 || dad>1) && j<1);


Desculpa la mas para que serve o J e esse segundo scanf()

</div>
 
O segundo scanf serve para limpar o STDIN (i.e. para remover o \n que lá fica depois de pressionares ENTER) e o j é para garantir que o primeiro scanf processa algo. (j == 1, então recebeu um parametro).
 
Mas esse scanf() só irá ser necessário no caso de se introduzir caracteres inválidos, pois iremos ter que voltar a introduzir. Corrigeme se estiver errado.

Nesse caso não bastava colocar um space antes de %d.

assim:
Código:
do {
    printf("\nUtiliza conta poupanca-habitacao (1-Sim, 0-Nao):\n\n");
    printf("Opcao:");
    j=scanf(" %d",&dad);
   }while((dad<0 || dad>1) && j<1);
 
Última edição pelo moderador:
O segundo scanf serve para limpar o STDIN (i.e. para remover o \n que lá fica depois de pressionares ENTER) e o j é para garantir que o primeiro scanf processa algo. (j == 1, então recebeu um parametro).

Exacto.

Mas esse scanf() só irá ser necessário no caso de se introduzir caracteres inválidos, pois iremos ter que voltar a introduzir. Corrigeme se estiver errado.

Nesse caso não bastava colocar um space antes de %d.

assim:

O objectivo não era prever casos de input de caracteres inválidos para o programa em questão? Um espaço antes de %d não irá fazer nada. O funcionamento do scanf consiste em ler aquilo que lhe é mandado ler até encontrar um \n. Se deres um espaço (ou quantos quiseres) e só depois colocares o número ele lê bem na mesma com o código que eu aqui coloquei (sem qualquer espaço). O único problema que existia era não descartar os caracteres inválidos que ficavam no stdin, o que causava um erro ou um loop infinito no programa original. Esta limpeza do buffer pode ser feita da forma que indiquei ou através de um gets.
 
Última edição:
Exacto.



O objectivo não era prever casos de input de caracteres inválidos para o programa em questão? Um espaço antes de %d não irá fazer nada. O funcionamento do scanf consiste em ler aquilo que lhe é mandado ler até encontrar um \n. Se deres um espaço (ou quantos quiseres) e só depois colocares o número ele lê bem na mesma com o código que eu aqui coloquei (sem qualquer espaço). O único problema que existia era não descartar os caracteres inválidos que ficavam no stdin, o que causava um erro ou um loop infinito no programa original. Esta limpeza do buffer pode ser feita da forma que indiquei ou através de um gets.


Pode-se limpar o buffer do teclado atraves de fflush(stdin);
Dá muito jeito mesmo pa capar nomes através do gets, ou getfs.

Já agor, se alguém me puder ajudar, como faço validação através do código ascii?!
Já tou farto de tentar e não consigo, pensava que era do género:
while(a!='\65');
Mas não me está a dar resultados...se alguém puder ajudar agradeço.

Cumps
 
Última edição:
Back
Topo