Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

Carlos7

[Resolvido] Limpar Buffer antes de ler caracter

Mensagens Recomendadas

Carlos7

Boas, o meu professor deu-nos esta função para limpar o buffer antes da leitura de caracteres/strings mas quando a utilizo, tenho de dar 2 enters para "guardar" o que digitei.

Após dar o primeiro enter ele fica à espera do segundo e só depois "guarda" a string/caracter na variável.

/*Gives support to the boolean datatype*/
typedef enum {
	FALSE, TRUE
} Boolean;
/*Allows to clear the standard input buffer*/
Boolean clearInputBuffer() {
	Boolean clear = FALSE;
	char c;
	while ((c = getchar()) != '\n' && c != EOF) {
		clear = TRUE;
	}
	return clear;
}

Queria saber o porquê de isto me estar acontecer.

Editado por Carlos7

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Tirando o erro de c ter de ser declarado como int, o codigo que apresentaste remove do buffer do teclado tudo o que la esta ate ao primeiro ENTER inclusive.

Se o teu programa espera por dois ENTERs o problema esta noutro lado, possivelmente na sequencia de scanf()s e clearInputBuffer()s. Quando pensas que tens um ENTER no buffer, tens de facto dois.


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Pois, se limpas o buffer antes e depois, tens de la ter qualquer coisa antes e depois.

Se nao tiveres la nada, o programa fica a espera do tal segundo ENTER.


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

A maneira mais fiavel de resolveres o teu problema é com fgets().

Ao usares fgets() para leres input, o ENTER é incluido no buffer e deixas de te preocupar com ele. Se preferires podes apagar o ENTER do buffer.

Para passar dados do buffer para outras variaveis podes usar sscanf(), strtol(), ou muitas outras funcoes; sem excluir a hipotese te tratares o input caracter-a-caracter.

/* Exemplo */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
   char buffer[1000], name[999];
   size_t blen;
   int age;
   char *err;

   printf("Enter name: ");
   fflush(stdout);
   fgets(buffer, sizeof buffer, stdin);
   blen = strlen(buffer);
   if (buffer[blen - 1] == '\n') buffer[--blen] = '\0'; /* apaga ENTER final */
   strcpy(name, buffer);

   printf("Enter age: ");
   fflush(stdout);
   fgets(buffer, sizeof buffer, stdin);
   errno = 0;
   age = strtol(buffer, &err, 10);
   /* para validacao deves examinar errno e err */

   printf("Ola %s. Tu tens %d anos.\n", name, age);
   return 0;
}

Editado por pmg

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Rui Carlos

Penso que a solução passa por limpares o buffer depois de cada operação de leitura (de modo a garantires que tens o buffer sempre limpo).

pmg, mesmo com o fgets, não tens garantia que o buffer fique limpo, pois nada te garante que não tens mais do que o números de bytes que definiste para ler.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

pmg, mesmo com o fgets, não tens garantia que o buffer fique limpo, pois nada te garante que não tens mais do que o números de bytes que definiste para ler.

Pois, com aquele exemplo basico nao tens garantia de ler tudo ate o ENTER seguinte. Mas podes complicar o basico verificando o ultimo caracter. Se for '\n', leste tudo; se nao for, ha mais dados para ler (ou houve um erro na leitura).


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Carlos7

Já tentei de tudo e isto continua a espera de um enter para me mostrar a mensagem seguinte.

Só depois de eu dar o enter é que ele me apresenta a mensagem.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pedro596

Pelo que entendi... Apenas queres por exemplo usar gets() ou getchar() e não correr o risco de o programa continuar sem parar... Muitas vezes ao usar o gets() é logo atribuído o que esta no buffer sem sequere chegares a tocar no teclado...

Se apenas quiseres resolver esse problema, antes de usares por exemplo o gets() faz isto:

//pode dar erro e atribuir o que estiver no buffer
int main() {
 char frase[50];
 gets(frase);
 return 1;
}
//Correção:
int main() {
 char frase[50];
 fflush(stdin);
 gets(frase);
 return 1;
}
//ou ainda:
int main() {
 char frase[50];
 rewind(stdin);
 gets(frase);
 return 1;
}

Editado por Rui Carlos

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

Se apenas quiseres resolver esse problema, antes de usares por exemplo o gets() faz isto:

http://www.crasseux.com/books/ctutorial/gets.html

If you want to read a string from standard input, you can use the gets function, the name of which stands for "get string". However, this function is deprecated -- that means it is obsolete and it is strongly suggested you do not use it -- because it is dangerous. It is dangerous because it provides no protection against overflowing the string into which it is saving data. Programs that use gets can actually be a security problem on your computer.


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Carlos7

O meu professor deu-nos esta função para leitura de strings:


unsigned char readString(char * const string, const unsigned int size) {
   unsigned int stringSize;
   if (fgets(string, size, stdin) != NULL) {
       stringSize = strlen(string) - 1;
       if (string[stringSize] == '\n')
           string[stringSize] = '\0';
       return 1;
   } else
       return 0;
}

Eu estou a ler strings com esta função tipo isto:

printf("Enter street:\n");
   if (readString(tempStreet, SIZEOFADRESS) != 1) {
       printf("Invalid street!\n");
   } else {
    strcpy(elementsAdress.street, tempStreet);
   }

E quando diz Invalid street! fica a espera de um enter para me voltar a pedir novamente para introduzir :s

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

E quando diz Invalid street! fica a espera de um enter para me voltar a pedir novamente para introduzir :s

apresenta todo o ciclo de leitura


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Carlos7

Não convinha muito inserir o meu ciclo porque é de um trabalho e andam sempre por aqui muitos mirones da minha escola xD

E para não se considerar que depois foi copiado vou fazer um ciclo igual mas de um tema diferente e já ponho aqui :P

Obrigado.

Para ler faço isto:

elementsDaMorada.codigoPostal = validateCodigoPostal();

Depois tenho aqui as duas funções (leitura e validação). Não ligues a validação, sei que não está totalmente correcta, por agora só quero mesmo saber o porquê de o programa ficar a espera do enter para voltar a pedir o codigo postal se este for inválido.

CogidoPostal lerCodigoPostal() {
   CodigoPostal codigoPostal;
   unsigned int castOfcodigoPostal[2];
   unsigned int i = 0;
   char tempCodigoPostal[sizeOFPOSTALCODE];
   printf("Insira codigo postal:\n");
   if (readString(tempCodigoPostal, SIZEOFPOSTALCODE) == 1) {
    //Function copy by cplusplus.com
    char * pch;
    pch = strtok(tempCodigoPostal, "-");
    while (pch != NULL) {
	    castOfcodigoPostal[i] = atoi(pch);
	    pch = strtok(NULL, "-");
	    i++;
    }
    //
   }
   codigoPostal.cityCode = castOfcodigoPostal[0];
   codigoPostal.localCode = castOfcodigoPostal[1];
   return codigoPostal;
}
CodigoPostal validateCodigoPostal() {
   CodigoPostal codigoPostal;
   unsigned int validate;
   do {
    validate = 0;
    codigoPostal = lerCodigoPostal();
    if (codigoPostal.cityCode > 9999 || codigoPostal.cityCode < 1000 || codigoPostal.localCode > 999 || codigoPostal.localCode < 0) {
	    printf("Invalid Postal Code!\n");
	    validate = 1;
    }
   } while (validate == 1);
   return codigoPostal;
}

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

vamos imaginar que estou a ler ps quatro pimeiros dígitos de um código postal

unsigned char readString(char * const string,       // ponteiro para a posição de memória que irá guardar os valores ditos
                        const unsigned int size) { // 4 ...
   unsigned int stringSize;
   if (fgets(string, size, stdin) != NULL) {       // vai ler no máximo 4 caracteres, logo o '\n' final não é lido
       stringSize = strlen(string) - 1;            // deverá ficar com o valor de 3 (depende do byte seguinte aos 4 do buffer) 
       if (string[stringSize] == '\n')             // verificar se o 4 elemento (indice 3) é o caracter '\n'
           string[stringSize] = '\0';              // se sim, alterar/remover
       return 1;                                   // retornar sucesso
   } else
       return 0;                                   // retornar erro
}

como vês, a remoção dos caracteres depende sempre do tamanho do buffer dado


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo
unsigned char readString(char * const string, const unsigned int size) {
   char buffer[256];
   unsigned int last;

   if (fgets(buffer, 256, stdin) != NULL) {
       strncpy(string, buffer, size);
       last = strlen(string) - 1;
       if (string[last] == '\n')
           string[last] = '\0';
       return 1;
   } else
       return 0;
}

Editado por HappyHippyHippo

IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Carlos7

Mas mesmo assim ele continua à espera do enter depois de dizer que o codigo postal e invalido :s

E se eu percorrer a string toda à procura do '\n' e substitui-lo pelo '\0' em vez de procura-lo apenas na ultima posição?

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Carlos7

Ufa, já resolvi, retirei todas as limpezas de buffer que tinha e fui verificando uma a uma se realmente era preciso limpar o buffer naquele momento.

Estava a limpar o buffer em sitios que não havia nada para limpar e penso que seria disso, agora já está tudo a funcionar correctamente.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.