Jump to content

Passa a frente o Scanf


jonhhy
 Share

Recommended Posts

Hello people,

o meu programa não lê o segundo scanf e continua na execução do programa.

qrhf9vw.png

#include <stdio.h>
int main()
{
int n_horas;
char escolha;
long n_seg;
long int n_min,n_dseg;/*pode ser muit0 grande*/
printf("Nº de Horas: "); scanf("%d",&n_horas);
// o scanf pode ser que esteja a ler a mudança de linha sim...puts("Digite a unidade de conversão"); scanf("%c",&escolha);
printf("Digite a unidade de conversão"); scanf("%c",&escolha);
if (escolha == 's')
{
n_seg = n_horas < 0? 0: n_horas * (long) 3600;
printf("O número de segundos gasto é: %ld",n_seg);
}
else
if (escolha == 'm' || escolha == 'M')
{
	 n_min = n_horas < 0? 0: n_horas * (long) 60L;
printf("O número de minutos gasto é: %ld",n_min);
}
else
if (escolha == 'd' || escolha == 'D')
{
n_dseg = n_horas<0? 0: n_horas * (long) 3600*100;
printf("O número de minutos gasto é: %ld",n_dseg);
}
return 0;
}

ate já 🙂

Edited by apocsantos
geshi
Link to comment
Share on other sites

jonhhy,

A primeira invocação de scanf lê um número inteiro para n_horas e deixa o ENTER que deste no buffer de input.

Quando invocas o scanf pela segunda vez ele vai tentar ler um caracter -- que é o ENTER que ficou lá pendurado.

Solução: dizer à scanf para ignorar whitespace antes de ler o caracter, assim:

/* O espaço antes de '%c' é a solução */
scanf(" %c", &escolha);
Link to comment
Share on other sites

Ola muito obrigado pela explicação pwseo,

agora já percebi o porquê acontecer isso 🙂 .

bB19iUI.png

eu depois fiz a depuração do programa e realmente aparece \n.

Edited by jonhhy
Link to comment
Share on other sites

o espaço no scanf funciona como limpeza do buffer então ? (acho que há funções que também fazem isso especifícamente)

um getchar experimentei e portanto, ele lê o carater do buffer e elimina-o de lá. e o scanf já espera por 1carater com o buffer vazio.

Link to comment
Share on other sites

O espaço não funciona como limpeza de buffer. Como podes ver em scanf(3), o espaço é ele próprio uma directiva para a scanf:

A directive is one of the following:

  • A sequence of white-space characters (space, tab, newline, etc.; see isspace(3)). This directive matches any amount of white space, including none, in the input.

Portanto, quando inseres um espaço numa format-string para ser utilizada com a scanf, isso vai «engolir» todos os espaços no input, sejam eles 0 (zero) ou qualquer número deles.

Link to comment
Share on other sites

Sim pelo que percebi esta pergunta já vem incluida em muitos tutoriais e livros de programação e não é uma novidade.

Já algum tempo que não pegava a programar. até me esqueci deste detalhe.

Por exemplo no abc do C em "Linguagem C" do Luis Damas é dito que :"Nota: O espaço em branco dentro de um scanf pede a essa função para ler e ignorar todos os Espaços em Branco,New Lines e Tabs que encontrar.

Também existem tutorias onde o mesmo tema é abordado: http://www.cprogressivo.net/2012/12/Buffer--o-que-e-como-limpar-e-as-funcoes-fflush-e-fpurge.html

Link to comment
Share on other sites

Ola, eu tentei fazer a minha própria função x_toupper só que

tive série de complicações por comparei int e char (declarado)...

Por exemplo em function X_toupper2() , ele prefaz um ciclo infinito e já não será por causa do espaço no início da string scanf, porque ..(o compilador não faz o scanf ..mas deixei o espaço até)?

Usei o geany mas não deu para usar o toggle point/breakpoints mas penso que só funciona como marcação.. e no Eclipse o projeto em C é emitido com uma mensagem de erro e não é possível compilar no debug mode.

fontes:

http://plugins.geany.org/debugger.html

https://www.youtube.com/embed/GOxo5qWuAm0?feature=oembed

https://www.youtube.com/embed/9gAjIQc4bPU?feature=oembed

#include <stdio.h>
int sum(int arg1,int arg2)
{
return (arg1 + arg2);
}
int soma(float arg1,float arg2)
{
int res;
res = (int) arg1 + arg2;
return res;
}
int dobro(int d)
{
return 2*d;
}
int max (int e, int f)
{
if (e > f)
 return e;
else
 return f;
}
void prog7(int a,int b)
{
printf(" 1º  %d\n",max(a,b));
puts("Digite 2 numbers");
scanf("%d %d",&a,&b); // vai anular os valores atribuidados antes!
printf("A soma será:%d\n",soma(a,b));
printf("O dobro de y é:%d\n",dobro(b));
printf("Last   %d\n",max(a,b));
}
int x_toupper_(char letra)
{
 int i;
 for (i=0/* puts("Let's Go .. tenta novamente*/;;i++)
 {
 if(!(letra<121 && letra>=97))
 {
  puts("Tenta de novo ...");
  scanf("%c",&letra);
  continue; // passa à frente...
 }
 else
 letra=(int) letra-32;
 printf ("O que queres é:\n %c",letra);
 break;

 }
printf("\nÁ %dª tentativa consegui-mos arrancar ...\n",i);
return 0;
}
void X_toupper()
{
char c;
int j='A' - 'a';
puts("Digite a letra pretendida");
scanf("%c",&c);
c = (int) c;
printf("%d",c);
printf("%d",(int) c);
printf("%c",c);
while (!(c<120 && c>97))
{
  puts("Tenta de novo2 ...");
  scanf("%c",&c);
}
printf("%d\n",j);
c=(int) c-32; printf ("O que queres é:\n %c\n",c);
}
void  X_toupper3()
{
int c;
puts("Digite a letra pretendida");
scanf("%d",&c);
while (!(c<120 && c>97))
{
  puts("Tenta de novo3 ...");
  scanf(" %d",&c);
}
c= c-32; printf ("O que queres é:\n %c\n",c);
}
int main()
{

x_toupper_(69);
X_toupper();
X_toupper3();
/* int x,y;
puts("Digite valor para x e \nDigite valor para y"); scanf("%d%d",&x,&y);
max(x,y);
prog7(x,y);
printf("%d\n",max(x,y));  */
//printf("%d\n%d\n",sum(4,9),soma(3.3,5.21));
return 0;
}
Edited by thoga31
GeSHi
Link to comment
Share on other sites

Deu-me a curiosidade em relação a este, embora no fim o problema seja trivial. Mas antes uma nota, o Hippo tem razão, tenham mais cuidado com a forma como apresentam o problema, tentem ser o mais sucintos e claros possíveis, para que outros vos possam ajudar sem terem que decifrar os problemas...

void  X_toupper3()
{
int c;
puts("Digite a letra pretendida");
scanf("%d",&c);
while (!(c<120 && c>97))
{
  puts("Tenta de novo3 ...");
  scanf(" %d",&c);
}
c= c-32; printf ("O que queres é:\n %c\n",c);
}

Olha lá que tipo de variável estás a ler. Quando inseres um caracter o scanf falha, já que está à procura de um inteiro. O problema é que o caracter fica no buffer de entrada, pelo que as seguintes chamadas ao scanf vão também falhar, entrando em ciclo infinito.

Claro que a solução passa por corrigir o tipo de variável a ler, enquanto isso não acontecer a função não faz o que queres, mas para evitar este tipo de problemas, uma outra solução é limpar o buffer de entrada a seguir a uma leitura. Por exemplo:

while(getchar()!='\n');

Este código vai buscar todos os caracteres do buffer de leitura até encontrar um Enter, evitando neste caso que a função entre em ciclo infinito.

Edited by Flinger
  • Vote 1
Link to comment
Share on other sites

Se bem me lembro podes o usar o operador relacional para comparar os caracteres. Como o membro Flinger te diz só tens de corrigir a variável de entrada. O operador relacional ao fazer a comparação de caracteres faz o casting para inteiro. A mesma coisa é feita quando usas os operadores aritméticos.

Experimenta o seguinte código:

#include <stdio.h>
main()
{
char ch;
puts ("Introduza um caractere");
scanf ("%c", &ch);  /* ch = getchar(); */ 
if (ch >= 97 || ch <= 122)
{
 ch = ch - 32;
}
printf("O caractere agora e: %c", ch);

}

EDIT: Já agora lembra-te que cada vez que usas o scanf para caracteres ou strings morre um gatinho. Pensem nos gatinhos.

Edited by CarlosTex
Link to comment
Share on other sites

HappyHippyHippo

O operador relacional ao fazer a comparação de caracteres faz o casting para inteiro. A mesma coisa é feita quando usas os operadores aritméticos.

o cast só é realizado se assim for necessário. este é o problema de quem não percebe que o tipo de dados char não é mais do que declarar/reservar um byte em que os valores numéricos possuem sinal (1 bit para sinal e 7 bit para representação numérica).

por outras palavras, no seguinte código, não existe elevação do tipo de dados:

char c = 30;
if (c + 1 < 40) { // c + 1 = 31, pertence ao domínio de um "char" ]-128, 127[
                 // 31 e 40 pertence ao domínio de um "char" ]-128, 127[, não existe elevação do tipo de dados
 printf("nao existe elevacao do tipo de dados\n");
}

EDIT: Já agora lembra-te que cada vez que usas o scanf para caracteres ou strings morre um gatinho. Pensem nos gatinhos.

só morre um gatinho, se quem usa a função não sabe o que está a fazer.

IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

o cast só é realizado se assim for necessário. este é o problema de quem não percebe que o tipo de dados char não é mais do que declarar/reservar um byte em que os valores numéricos possuem sinal (1 bit para sinal e 7 bit para representação numérica).

por outras palavras, no seguinte código, não existe elevação do tipo de dados:

char c = 30;
if (c + 1 < 40) { // c + 1 = 31, pertence ao domínio de um "char" ]-128, 127[
			  // 31 e 40 pertence ao domínio de um "char" ]-128, 127[, não existe elevação do tipo de dados
 printf("nao existe elevacao do tipo de dados\n");
}

Certíssimo nunca quis insinuar o contrário.

só morre um gatinho, se quem usa a função não sabe o que está a fazer.

Concordo plenamente, o meu ponto é desaconselhar o uso de scanf constante para input isolado de caracteres e strings quando não se justifica. É ineficiente.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • 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.