Jogo da Forca em C com erro no while( ){ } [RESOLVIDO]

1. Jogo da Forca em C com erro no while( ){ } [RESOLVIDO]

Raquel Moura Pereira
raquelrmp

(usa Nenhuma)

Enviado em 14/06/2015 - 14:09h

Gente, preciso de ajuda!
Esse código que segue abaixo é de um Jogo da Forca utilizando arquivo. Ele é compilado, mas o erro aparece quando o usuário digita a letra, se o usuário acertar a letra ele atribui +1 aos erros ao invés de +0. E quando o usuário erra, ele atribui +2 ao erros ao invés de +1. Agradeceria imensamente se alguém pudesse me ajudar!


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


#define NUMPL 100
#define MAXTAMPL 16



int Aleatorio(){ // Retorna um número aleatório entre 1 e 100;
srand(time(NULL));
return rand()%NUMPL;
}

void linha_forca(int x, char y[15]){ //imprime as letras acertadas da palavra sorteada

printf("***** ");
for (int j=0;j<=x-1;j++){
printf("%c ", y[j]);
}
printf("\n");

printf("***** ");
for(int i=0;i<= x-1;i++){
printf("-- ");
}
printf("\n");
printf("\n");
printf("\n");


}

void des_forca(int x, int y, char z[15]){ //desenha a forca e as letras acertadas.
switch (x){
case 0:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 1:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 2:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** | \n");
printf(" ** | \n");
printf(" ** | \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 3:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /| \n");
printf(" ** / | \n");
printf(" ** | \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 4:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /|\\ \n");
printf(" ** / | \\ \n");
printf(" ** | \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 5:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /|\\ \n");
printf(" ** / | \\ \n");
printf(" ** | \n");
printf(" ** / \n");
printf(" ** _/ \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 6:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /|\\ \n");
printf(" ** / | \\ VOCE PERDEU! \n");
printf(" ** | \n");
printf(" ** / \\ \n");
printf(" ** _/ \\_ \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
}

}



main()
{
char palavra[NUMPL][MAXTAMPL]; // matriz que irá armazenar as palavras do arquivo([NUMPAL) e as letras de cada palavra([MAXTAMPL])
char vetpl[16];
int IndicePalavrasLidas = 0; //indicar a linha da matriz

FILE *pl;
pl = fopen ("palavras.txt", "r"); // abrir aquivo onde esta o banco de palavras

if (pl == NULL){
printf("O arquivo nao pode ser aberto.\n \f"); //teste para saber se ocorreu algum erro ao abrir o arquivo
getchar();
exit(0);
}


while(fgets(vetpl, 15, pl)){

sscanf(vetpl,"%s",palavra[IndicePalavrasLidas]);
IndicePalavrasLidas++;
}

fclose(pl);

int c = Aleatorio();

int tentativas = 6;
int num_erros = 0;
char letra;
char ShowWord[15];

bool acertou = 0;
int cont = 0;
int teste = 0;
int num_letr = strlen (palavra[Aleatorio()]); // retorna um inteiro com a quantidade de caracteres da palavra sorteada.

for (int i=0;i<=num_letr;i++){ // atribui espaço as letras da forca, limpando assim a memória.
ShowWord[i] =' ';
}

while((num_erros<6) or (acertou == 0)){

system("CLS"); // limpa tela
printf("Erros: %d Cont: %d teste: %d \n ", num_erros,cont,teste);
printf("%s \n",palavra[c]);
des_forca(num_erros,num_letr,ShowWord); //desenha forca
printf("Digite uma letra: ");
scanf("%c",&letra);

teste = 0; // variável auxiliar para saber se o usuário errou
for(int i = 0; i <=num_letr-1;i++){ // verificará a letra digitada
if(letra == palavra[c][i]){ // Teste para saber se a palavra digitada é correspondente com a da forca
ShowWord[i] = letra;
cont = cont+1; // número de acertos
teste = 1; // se o usuário tiver acertado a letra, teste passará a ter o valor 1.
}
}

if (teste == 0){ //Se teste permanecer 0, significa que o usuario errou, já que a condição if(letra == palavra[c][i]) deu falsa
num_erros = (num_erros + 1);
}
if (cont==num_letr){ //se o contador for igual ao numero de letras da palavra sorteada o usuário ganhou
acertou = 1;
break;
}

}

if (acertou==1){ //se o contador for igual ao numero de letras da palavra sorteada o usuário ganhou
system("CLS");
printf("\n\n Parabens!!! Voce Acertou!!!");

}


printf("\n \n");

system("PAUSE");


}



arquivo : palavras.txt
abelha
aguia
alce
anta
aranha
avestruz
arara
baleia
borboleta
cabra
calango
camaleao
cachorro
capivara
carangueijo
carneiro
cascavel
cavalo
cisne
coala
coelho
corvo
crocodilo
elefante
ema
esquilo
foca
galinha
gorila
golfinho
hamster
jacare
leao
leopardo
lobo
lula
lontra
papagaio
pato
pavao
panda
peru
pinguim
pombo
porco
pulga
puma
raposa
rato
rinoceronte
sapo
tatu
tigre
touro
urso
urubu
veado
zebra
tucano
coral
arvore
formiga
tanajura
lagarta
lanterna
barata
predio
caneta
caderno
computador
perola
ostra
relogio
vestido
termometro
voltimetro
biscoito
celular
coleira
pirulito
chocolate
leite
minhoca
acerola
ceramica
bicicleta
aviao
onibus
balanco
automovel
igreja
cadeira
computador
sorvete
travesseiro
basquete
voleibol
ventilador
imovel
violao



  


2. MELHOR RESPOSTA

Thiago Henrique Hüpner
Thihup

(usa Manjaro Linux)

Enviado em 15/06/2015 - 11:35h

Ah, esqueci de dizer uma coisa:

O scanf(" %c") com um espaço, ele ignora "\n", espaços, enfim.

Eu testei o seu código e não funcionou como esperado (por que o buffer está sujo, e o fflush stdin é do Windows (principalmente).

Então foi só colocar o espaço no Scanf e funcionou.

Espero ter ajudado

Clique em Melhor Resposta para manter a organização do fórum

[]'s

T+

--
http://piadasnerds.com/wp-content/uploads/2011/08/grafico_souProgramador.png

3. Que erro do

Thiago Henrique Hüpner
Thihup

(usa Manjaro Linux)

Enviado em 14/06/2015 - 16:39h

Olá.

Gostei da proposta desse game, talvez eu tente fazer algo parecido usando o C + SDL (para ter interface gráfica).

Mas um dúvida: Que erro do do{}while()?

Aparentemente não possui esse trecho no código.

Existe um loop while e for, mas só.

[]'s

T+

--
http://piadasnerds.com/wp-content/uploads/2011/08/grafico_souProgramador.png


4. Re: Thiago Henrique

Raquel Moura Pereira
raquelrmp

(usa Nenhuma)

Enviado em 14/06/2015 - 16:54h

Perdão, o que quis dizer foi erro no while(){} mesmo, é que anteriormente este código estava com o do(){} e depois mudei para o while(){} tentando resolver o problema, mas não deu certo.

Não possui erro de compilação, porém quando é executado e usuário digita uma letra e aperta enter é acrescido ao num_erros mais 1 do que deveria ser, independentemente da letra que o usuário digite e não consigo corrigi-lo para que só seja acrescentado +1 aos erros caso o usuário erre a letra.

Deste jeito como está, quando o usuário erra é acrescentado +2 aos erros e quando acerta é acrescentado +1.


5. Re: Jogo da Forca em C com erro no while( ){ }

Thiago Henrique Hüpner
Thihup

(usa Manjaro Linux)

Enviado em 14/06/2015 - 18:32h

Consegui resolver.

Mas vou mandar o código com alguns bug pra você corrigir.

Já estou lhe dando o código pronto, e eu não faço isso (mas abri uma excessão pra você).


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


#define NUMPL 100
#define MAXTAMPL 16



int Aleatorio(){ // Retorna um número aleatório entre 1 e 100;
srand(time(NULL));
return rand()%NUMPL;
}

void linha_forca(int x, char y[15]){ //imprime as letras acertadas da palavra sorteada

printf("***** ");
for (int j=0;j<=x-1;j++){
printf("%c ", y[j]);
}
printf("\n");

printf("***** ");
for(int i=0;i<= x-1;i++){
printf("-- ");
}
printf("\n");
printf("\n");
printf("\n");


}

void des_forca(int x, int y, char z[15]){ //desenha a forca e as letras acertadas.
switch (x){
case 0:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 1:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 2:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** | \n");
printf(" ** | \n");
printf(" ** | \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 3:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /| \n");
printf(" ** / | \n");
printf(" ** | \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 4:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /|\\ \n");
printf(" ** / | \\ \n");
printf(" ** | \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 5:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /|\\ \n");
printf(" ** / | \\ \n");
printf(" ** | \n");
printf(" ** / \n");
printf(" ** _/ \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 6:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /|\\ \n");
printf(" ** / | \\ VOCE PERDEU! \n");
printf(" ** | \n");
printf(" ** / \\ \n");
printf(" ** _/ \\_ \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
}

}



int main(){
char palavra[NUMPL][MAXTAMPL]; // matriz que irá armazenar as palavras do arquivo([NUMPAL) e as letras de cada palavra([MAXTAMPL])
char vetpl[16];
int IndicePalavrasLidas = 0; //indicar a linha da matriz

FILE *pl;
pl = fopen ("palavras.txt", "r"); // abrir aquivo onde esta o banco de palavras

if (pl == NULL){
printf("O arquivo nao pode ser aberto.\n \f"); //teste para saber se ocorreu algum erro ao abrir o arquivo
getchar();
exit(0);
}


while(fgets(vetpl, 15, pl)){
sscanf(vetpl,"%s",palavra[IndicePalavrasLidas]);
IndicePalavrasLidas++;
}

fclose(pl);

int c = Aleatorio();

int num_erros = 0;
char letra;
char ShowWord[15];

bool acertou = 0;
int cont = 0;
//int teste = 0;
int num_letr = strlen (palavra[Aleatorio()]); // retorna um inteiro com a quantidade de caracteres da palavra sorteada.
int i;
for (i=0;i<num_letr;i++){ // atribui espaço as letras da forca, limpando assim a memória.
ShowWord[i] =' ';
}

printf("A palavra era \"%s\"\n",palavra[c]);

do{
printf("Erros: %d Cont: %d\n ", num_erros,cont);
des_forca(num_erros,num_letr,ShowWord);
printf("Digite uma letra: ");
// Com espaço pra ignorar espaços em branco, tabulações, etc
scanf(" %c",&letra);

printf("\n\n");

for(i = 0; i <num_letr;i++){
if(letra == palavra[c][i]){
// Acertou a Letra
ShowWord[i] = letra;
cont += 1;
acertou = 1;
continue;
}else{
acertou = 0;
}
}


if(!acertou){
// Errou a Letra
num_erros += 1;
continue;
}

if (cont==num_letr){
// Acertou a palavra
acertou = 1;
des_forca(num_erros,num_letr,ShowWord);
printf("\n\n Parabens!!! Voce Acertou!!!");
break;
}
}while((num_erros<6) && (!acertou));

printf("\n \n");

return 0;
}



Qualquer dúvida só postar aqui.

NOTA: Eu ví que você fez o código no Windows!

Espero ter ajudado

Se ajudei, marque o tópico como resolvido e clique em melhor resposta.

[]'s

T+

--
http://piadasnerds.com/wp-content/uploads/2011/08/grafico_souProgramador.png


6. Re: Thiago Henrique

Raquel Moura Pereira
raquelrmp

(usa Nenhuma)

Enviado em 15/06/2015 - 11:07h

Thiago, agradeço as observações feitas no código (nos "if( ){ }" e no while( ){ }), porém o mesmo erro persistiu.

Revi o código, fiz muitos testes e descobri o erro estava no enter(/n) digitado pelo usuário após digitar a letra, pois o scanf, por um erro da própria função, pega esse enter.
Então achei a solução, aqui no Viva o Linux, colocando "fflush(stdin);" após o scanf(); para limpar o buffer do teclado.

OBS: Sim, infelizmente usei o Windows porque peguei um computador novo a duas semanas e ele não tem drive de CD/DVD. Então vou tirar um tempo para aprender a fazer um pendrive bootavel, já que nunca fiz um, para tentar instalar o Linux.

O código corrigido fica assim:

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


#define NUMPL 100
#define MAXTAMPL 16



int Aleatorio(){ // Retorna um número aleatório entre 1 e 100;
srand(time(NULL));
return rand()%NUMPL;
}

void linha_forca(int x, char y[15]){ //imprime as letras acertadas da palavra sorteada

printf("***** ");
for (int j=0; j<x ;j++){
printf("%c ", y[j]);
}
printf("\n");

printf("***** ");
for(int i=0; i<x ;i++){
printf("-- ");
}
printf("\n");
printf("\n");
printf("\n");


}

void des_forca(int x, int y, char z[15]){ //desenha a forca e as letras acertadas.
switch (x){
case 0:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 1:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 2:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** | \n");
printf(" ** | \n");
printf(" ** | \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 3:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /| \n");
printf(" ** / | \n");
printf(" ** | \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 4:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /|\\ \n");
printf(" ** / | \\ \n");
printf(" ** | \n");
printf(" ** \n");
printf(" ** \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 5:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /|\\ \n");
printf(" ** / | \\ \n");
printf(" ** | \n");
printf(" ** / \n");
printf(" ** _/ \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
case 6:
printf("\n");
printf(" *********** \n");
printf(" *********** \n");
printf(" ** ** \n");
printf(" ** ( ) \n");
printf(" ** /|\\ \n");
printf(" ** / | \\ VOCE PERDEU! \n");
printf(" ** | \n");
printf(" ** / \\ \n");
printf(" ** _/ \\_ \n");
printf(" ** \n");
printf(" *** \n");
linha_forca(y,z);
break;
}

}



int main()
{
char palavra[NUMPL][MAXTAMPL]; // matriz que irá armazenar as palavras do arquivo([NUMPAL) e as letras de cada palavra([MAXTAMPL])
char vetpl[16];
int IndicePalavrasLidas = 0; //indicar a linha da matriz

FILE *pl;
pl = fopen ("palavras.txt", "r"); // abrir aquivo onde esta o banco de palavras

if (pl == NULL){
printf("O arquivo nao pode ser aberto.\n \f"); //teste para saber se ocorreu algum erro ao abrir o arquivo
getchar();
exit(0);
}


while(fgets(vetpl, 15, pl)){

sscanf(vetpl,"%s",palavra[IndicePalavrasLidas]);
IndicePalavrasLidas++;
}

fclose(pl);

int c = Aleatorio();
int k=0;
int tentativas = 6;
int num_erros = 0;
char letra;
char ShowWord[15];
char lt_digitadas[15];

bool acertou = 0;
int cont = 0;
int teste = 0;
int num_letr = strlen (palavra[Aleatorio()]); // retorna um inteiro com a quantidade de caracteres da palavra sorteada.

for (int i=0;i<num_letr;i++){ // atribui espaço as letras da forca, limpando assim a memória.
ShowWord[i] =' ';
lt_digitadas[i] =' ';
}

while((num_erros<6) or (acertou == 0)){

system("CLS"); // limpa tela
printf("Erros: %d Cont: %d teste: %d \n ", num_erros,cont,teste);
printf("%s \n",palavra[c]);
des_forca(num_erros,num_letr,ShowWord); //desenha forca

printf("Letras digitadas:");
for (int i=0;i<num_letr;i++){
printf("%c ",lt_digitadas[i]);
}

printf("\nDigite uma letra: ");
scanf("%c",&letra);
fflush(stdin); // limpar a entrada padrão.
lt_digitadas[k]=letra;

system("PAUSE");

teste = 0; // variável auxiliar para saber se o usuário errou
for(int i = 0; i <num_letr;i++){ // verificará a letra digitada
if(letra == palavra[c][i]){ // Teste para saber se a palavra digitada é correspondente com a da forca
ShowWord[i] = letra;
cont = cont+1; // número de acertos
teste = 1; // se o usuário tiver acertado a letra, teste passará a ter o valor 1.
}
}

if (teste == 0){ //Se teste permanecer 0, significa que o usuario errou, já que a condição if(letra == palavra[c][i]) deu falsa
num_erros = (num_erros + 1);
}
if (cont==num_letr){ //se o contador for igual ao numero de letras da palavra sorteada o usuário ganhou
acertou = 1;
break;
}
++k;
}

if (acertou==1){ //se o contador for igual ao numero de letras da palavra sorteada o usuário ganhou
system("CLS");
des_forca(num_erros,num_letr,ShowWord);
printf("\n\n Parabens!!! Voce Acertou!!!");

}


printf("\n \n");

system("PAUSE");
return(0);


}



7. Re: Jogo da Forca em C com erro no while( ){ } [RESOLVIDO]

Thiago Henrique Hüpner
Thihup

(usa Manjaro Linux)

Enviado em 15/06/2015 - 11:26h

Marque o tópico como resolvido e clique em melhor resposta.

Espero ter ajudado

[]'s

T+

--
http://piadasnerds.com/wp-content/uploads/2011/08/grafico_souProgramador.png


8. Obrigada Thiago!

Raquel Moura Pereira
raquelrmp

(usa Nenhuma)

Enviado em 15/06/2015 - 13:07h


Você tem razão Thiago, testei o código com scanf(" %c") apenas acrescentando um espaço e deu certo. É realmente melhor do que usar o
fflush stdin. Obrigada :)








9. Re: Jogo da Forca em C com erro no while( ){ } [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 16/06/2015 - 11:18h

raquelrmp escreveu:

Thiago, agradeço as observações feitas no código (nos "if( ){ }" e no while( ){ }), porém o mesmo erro persistiu.

Revi o código, fiz muitos testes e descobri o erro estava no enter(/n) digitado pelo usuário após digitar a letra, pois o scanf, por um erro da própria função, pega esse enter.


Cuidado com o que você diz, pois você comete um grave equívoco ao falar em “por um erro da própria função”.

A função scanf() (na verdade, a família inteira de funções xyscanf(), onde x pode ser omitido ou igual a ‘v’, e y pode ser omitido ou igual a ‘f’ ou ‘s’) não simplesmente extrai dados de uma fonte de entrada e atribui valores a variáveis. Ela foi feita para verificar se dados dessa fonte se adequam a um determinado formato (o nome dela, aliás, é a composição de “scan”, que significa “buscar”, e “f”, que é uma abreviação de “format”). O formato buscado pode ocupar uma linha inteira, ou apenas uns poucos caracteres dentro de uma linha, ou até mesmo várias linhas consecutivas. Durante o exame do formato, a função pode ou não modificar o valor de algumas variáveis que lhe forem passadas por referência.

Para fazer tudo isso, scanf() é necessariamente complexa -- possivelmente a mais complexa de todas as funções da biblioteca padrão do C. Por isso mesmo, eu recomendo fortemente que você leia com muito cuidado a documentação da função (a que vem com o Linux, por exemplo, é muito boa). Com isso, espero que não cometa mais o equívoco de atribuir a um erro de implementação aquilo que você simplesmente não conhece.

Então achei a solução, aqui no Viva o Linux, colocando "fflush(stdin);" após o scanf(); para limpar o buffer do teclado.


Escolheu uma solução ruim, por sinal, pois não é uma solução universal.

O padrão da linguagem só define o comportamento de fflush() para streams de saída de dados; aplicada a um stream de entrada, como stdin, ignorar a operação (como nos BSDs ou nos Linuxes com versões mais antigas da glibc ou com uClibc), remover caracteres do buffer (como no Windows e algumas versões mais novas da glibc) ou até mesmo matar o programa são comportamentos igualmente possíveis e aceitáveis.

Se você quiser suprimir possíveis sobras de caracteres até encontrar uma marca de fim de linha que você sabe que está presente na entrada, ou mesmo recuperar um estado estável após o usuário ter causado um erro (por exemplo: colocando letras numa situação em que se estava tentando ler um número), minha sugestão é que você use a seguinte invocação a scanf().

scanf("%*[^\n]%*1[\n]") 


OBS: Sim, infelizmente usei o Windows porque peguei um computador novo a duas semanas e ele não tem drive de CD/DVD. Então vou tirar um tempo para aprender a fazer um pendrive bootavel, já que nunca fiz um, para tentar instalar o Linux.


Usar Windows, por si só, não é um problema do ponto de vista de querer aprender C. Contudo, é bom aprender primeiro o que é universal, e usar o que é específico de cada sistema operacional apenas quando você tiver de fazer coisas que são necessariamente e exclusivamente voltadas para esse sistema operacional.


10. Re: Jogo da Forca em C com erro no while( ){ } [RESOLVIDO]

Raquel Moura Pereira
raquelrmp

(usa Nenhuma)

Enviado em 16/06/2015 - 13:08h

paulo1205 escreveu:

Cuidado com o que você diz, pois você comete um grave equívoco ao falar em “por um erro da própria função”.

scanf() (na verdade, a família de funções {,v}{,s,f}scanf()) não é uma função que simplesmente extrair dados e atribui valores a variáveis. Ela foi feita para verificar se dados da entrada se adequam a um determinado formato (o nome dela, aliás, é a composição de “scan”, que significa “buscar”, e “f”, que é uma abreviação de “format”). O formato buscado pode ocupar uma linha inteira, ou apenas uns poucos caracteres dentro de uma linha, ou até mesmo várias linhas consecutivas. Durante o exame do formato, a função pode ou não modificar o valor de algumas variáveis que lhe forem passadas por referência. Para fazer tudo isso, scanf() é necessariamente complexa -- possivelmente a mais complexa de todas as funções da biblioteca padrão do C.

Eu recomendo fortemente que você leia a documentação da função (a que vem com o Linux, por exemplo, é muito boa). Com isso, espero que não atribua mais a um erro aquilo que você simplesmente não conhece.


Paulo, comecei a ver a linguagem C a três semanas e nessa fase inicial é normal cometer-se erros. Porém, ao referir-me a função scanf(), o fato dela ter "recuperado" o enter do buffer do teclado, pulando assim uma entrada, pareceu ser um erro, mas talvez realmente não devesse atribuir este erro a função.

Escolheu uma solução ruim, por sinal, pois não é uma solução universal.

O padrão da linguagem só define o comportamento de fflush() para streams de saída de dados; aplicada a um stream de entrada, como stdin, ignorar a operação (como nos BSDs ou nos Linuxes com versões mais antigas da glibc ou com uClibc), remover caracteres do buffer (como no Windows e algumas versões mais novas da glibc) ou até mesmo matar o programa são comportamentos igualmente possíveis e aceitáveis.

Se você quiser suprimir possíveis sobras de caracteres até encontrar uma marca de fim de linha que você sabe que está presente na entrada, ou mesmo recuperar um estado estável após o usuário ter causado um erro (por exemplo: colocando letras numa situação em que se estava tentando ler um número), minha sugestão é que você use a seguinte invocação a scanf().


Em relação ao uso feito por mim da função fflush(), pode ter sido uma "solução ruim", mas o fato é que ela funcionou e inicialmente foi bem-vinda até que Thiago alertou-me sobre esta função e me indicou um modo melhor, com o uso do espaço entre " e o %, no scanf(): scanf(" %c",&letra). A final, é para isso que estamos aqui, para aprender uns com os outros!

Após minha ultima publicação já fiz várias pequenas modificações no código, algumas indicadas pelo Thiago que agradeço novamente,
trocando inclusive o scanf() com espaço por setbuf(stdin, NULL); após o scanf("%c",&letra):

	printf("\nDigite uma letra:  ");
scanf("%c",&letra);
setbuf(stdin, NULL); //limpa o buffer do teclado


que parece ser mais eficiente, já que limpa o buffer do teclado.

Em fim, achei desnecessária a sua "revolta", mas agradeço pelo acréscimo de informação.



11. Re: Jogo da Forca em C com erro no while( ){ } [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 16/06/2015 - 14:55h

raquelrmp escreveu:

Paulo, comecei a ver a linguagem C a três semanas e nessa fase inicial é normal cometer-se erros. Porém, ao referir-me a função scanf(), o fato dela ter "recuperado" o enter do buffer do teclado, pulando assim uma entrada, pareceu ser um erro, mas talvez realmente não devesse atribuir este erro a função.


Eu já estive no seu lugar. Ninguém aqui no fórum nasceu sabendo C.

Pesa a seu favor o fato de que a maioria dos cursos introdutórios, mesmo aqueles ministrados em faculdades, serem omissos ou cheios de informações equivocadas. Possivelmente você aprendeu no seu curso algo como “scanf() serve para ler valores de variáveis”, e seu professor talvez nem saiba que essa definição mostra apenas uma pequena parte do que a função pode fazer.

De todo modo, eu reitero meu conselho de que você precisa ter cuidado para não se precipitar. Até pelo fato de você ser iniciante, você deve evitar conclusões antes de entender o que realmente está acontecendo e analisar o que você está fazendo. De novo, eu não digo isso como “guru”, mas por experiência própria: algumas conclusões erradas que eu tirei ao longo da minha jornada acabaram me atrapalhando tempos depois, quando precisei usar alguns do resultados a elas associados e fiquei estupefato quando encontrei outros resultados.

Uma dica que lhe dou para que você tenha menos problemas ao longo da sua carreira de aluna e de profissional é não se limitar ao que recebe em sala de aula. Às vezes, é necessário mesmo confrontar com a realidade o que você aprende nos cursos. Leia documentações. Faça muitos testes. Consulte gente mais experiente (neste fórum ou em outros lugares), escute o que ela (ou nós) lhe diz e confronte isso também, com mais exame de documentação e mais testes.

Em relação ao uso feito por mim da função fflush(), pode ter sido uma "solução ruim", mas o fato é que ela funcionou e inicialmente foi bem-vinda até que Thiago alertou-me sobre esta função e me indicou um modo melhor, com o uso do espaço entre " e o %, no scanf(): scanf(" %c",&letra). A final, é para isso que estamos aqui, para aprender uns com os outros!


Começo pelo fim: concordo plenamente que podemos nos ajudar mutuamente.

Se você examinar minha crítica da solução que você adotara, verá que eu não me limitei a dizer que ela era ruim. Eu apontei o cenário em que ele funcionava, mas deixei claro que esse cenário nem sempre é verdadeiro. Por isso mesmo, eu também mostrei uma solução alternativa e universal (mais universal, inclusive, que a sugestão feita pelo Thiago).

Após minha ultima publicação já fiz várias pequenas modificações no código, algumas indicadas pelo Thiago que agradeço novamente,
trocando inclusive o scanf() com espaço por setbuf(stdin, NULL); após o scanf("%c",&letra):

	printf("\nDigite uma letra:  ");
scanf("%c",&letra);
setbuf(stdin, NULL); //limpa o buffer do teclado


que parece ser mais eficiente, já que limpa o buffer do teclado.


Eu acho ótimo que você faça esses pequenos testes.

No entanto, por razões didáticas (e em seu favor), eu tenho que apontar um problema também na nova solução.

A documentação de setvbuf() (que é a verdadeira função que executa quando se chama setbuf()) no padrão do C (§7.21.5.6) diz explicitamente que ela só deve ser usada após uma operação de abertura de arquivo (com fopen() ou freopen(), por exemplo). Que isso funcione como modo de esvaziar buffer é uma particularidade da implementação que você usou, da qual você não deve depender e a qual não deve assumir como verdadeira num caso geral.

Comparativamente -- e sem negar a possibilidade de influência de gosto pessoal -- fflush(stdin) ainda é melhor que setbuf(stdin, NULL). O comportamento de ambas não é previsto no padrão, mas o uso da primeira forma é uma extensão em área em que o padrão se omite; o da segunda, uma violação do que ele expressamente prescreve.

Em fim, achei desnecessária a sua "revolta", mas agradeço pelo acréscimo de informação.


Não houve revolta de qualquer tipo, nem qualquer forma de ataque pessoal. Sinceramente não entendo onde nem como você tenha percebido isso.

Como sempre digo aqui, meu único objetivo neste fórum é ajudar a compartilhar conhecimento correto, e isso às vezes implica desfazer equívocos como o que você havia cometido. Mas sem revolta nem mágoa, até porque seria muito mais fácil -- e mais inteligente, se minha proposta não fosse realmente compartilhar conhecimento -- ignorar erros alheios do que gastar tempo mostrando quais são eles, por quê o são, e que outras soluções melhores existem.



  



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts