Jump to content
Carlos7

[Resolvido] Limpar Buffer antes de ler caracter

Recommended Posts

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.

Edited by Carlos7

Share this post


Link to post
Share on other 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!

Share this post


Link to post
Share on other 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!

Share this post


Link to post
Share on other sites
Carlos7

Não estou a ver então solução para o meu problema, podes dar uma ideia de como resolver para ver se chego à solução?

Share this post


Link to post
Share on other 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;
}

Edited by 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!

Share this post


Link to post
Share on other 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.

Share this post


Link to post
Share on other 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!

Share this post


Link to post
Share on other 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.

Share this post


Link to post
Share on other 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;
}

Edited by Rui Carlos

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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;
}

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other sites
HappyHippyHippo

tens ... usa um buffer grande para leitura do teclado

depois processa a informação no buffer como entenderes


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

Share this post


Link to post
Share on other 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;
}

Edited by HappyHippyHippo

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

Share this post


Link to post
Share on other 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?

Share this post


Link to post
Share on other sites
HappyHippyHippo

a função (se dado um buffer suficientemente grande) funciona bem.

o teu problema encontrasse noutro lado


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

Share this post


Link to post
Share on other 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.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.