Ajuda com este exercicio

Também já tinha tentado fazer isso e nada : /

Eu não costumo usar o getchar() daí eu estar com algumas dúvidas.

Mas pelo que pesquisei, no getchar() tens de dar enter primeiro e depois escreveres a letra. Li isso aqui https://stackoverflow.com/questions/1798511/how-to-avoid-press-enter-with-any-getchar

E faz sentido por causa disto que disseste

"Se eu tirar o segundo getchar quando eu insiro o primeiro valor (na primeira vez que perguntam) parece que o "Enter" ficou no buffer... Ou seja responde automaticamente na segunda vez que perguntam e diz que falhei pois mandou o "enter" e não o 0!"

Por isso, experimenta fazer o seguinte: tira o segundo getchar, deixa apenas o primeiro e quando pedir o input, carregas enter e depois escreves o carater que queres.
 
O getchar vai buscar um char do topo do buffer, e não de ficar à espera de um char, e para isso é preciso fazer flush ao buffer.

Código:
fflush(stdin);
ou
Código:
int c; while((c = fgetc(stdin)) != EOF && c !='\n')
Este último convém colocar numa função como se fosse um flush do stdin, e atenção que o fflush foi criado para flush de output e nunca de input, mas funciona.

Ou seja, sempre que for para usar o getchar devem fazer um flush antes (ou depois, depende do que quiserem fazer).
 
Eu não costumo usar o getchar() daí eu estar com algumas dúvidas.

Mas pelo que pesquisei, no getchar() tens de dar enter primeiro e depois escreveres a letra. Li isso aqui https://stackoverflow.com/questions/1798511/how-to-avoid-press-enter-with-any-getchar

E faz sentido por causa disto que disseste

"Se eu tirar o segundo getchar quando eu insiro o primeiro valor (na primeira vez que perguntam) parece que o "Enter" ficou no buffer... Ou seja responde automaticamente na segunda vez que perguntam e diz que falhei pois mandou o "enter" e não o 0!"

Por isso, experimenta fazer o seguinte: tira o segundo getchar, deixa apenas o primeiro e quando pedir o input, carregas enter e depois escreves o carater que queres.
O getchar vai buscar um char do topo do buffer, e não de ficar à espera de um char, e para isso é preciso fazer flush ao buffer.

Código:
fflush(stdin);
ou
Código:
int c; while((c = fgetc(stdin)) != EOF && c !='\n')
Este último convém colocar numa função como se fosse um flush do stdin, e atenção que o fflush foi criado para flush de output e nunca de input, mas funciona.

Ou seja, sempre que for para usar o getchar devem fazer um flush antes (ou depois, depende do que quiserem fazer).
Afinal não precisei de fazer nada disso xd
Simplesmentes pus um getchar antes de opcao_int2=getchar(); e deu tudo correto
O getchar que está antes "absorve" o enter...
 
Se calhar não é a abordagem mais "profissional" mas também resolve. ;)
Este próximo exercício que eu te vou pedir sugestões é o último da batch xd

Pretende-se desenvolver um programa para ler valores de tempo no formato “h(hora) m(minuto) s(segundo)”, devolvendo o número de segundos associado ao tempo introduzido.
No entanto, o utilizador deve poder omitir campos (e.g. introduzir só “h23”). Para terminar a leitura o utilizador pode introduzir um carácter diferente de ‘h’, ‘m’ ou ‘s’. Pretende-se também que o programa valide os valores introduzidos, não deixando introduzir valores de minutos ou segundos superiores a 59, nem introduzir campos repetidos (só se pode introduzir 0 ou 1 campo de hora; 0 ou 1 campo de minuto; 0 ou 1 campo de segundo). Repare que:
São necessárias variáveis para guardar cada componente do tempo;
Só há leitura da parte numérica de uma componente do tempo se o carácter for válido;
Dependendo do carácter lido, o valor numérico contribui para o valor final de tempo com um peso diferente;
O ciclo de leitura de componentes do tempo não tem um número de componentes fixo, nem uma ordem fixa.

Um exemplo de utilização com a aplicação pretendida:

./final2
Introduza o tempo no formato h(hora) m(minuto) s(segundo): m56 h37 s23 x
Leu 37h 56m 23s = 136583 segundos

./final2
Introduza o tempo no formato h(hora) m(minuto) s(segundo): h1 x
Leu 1h 0m 0s = 3600 segundos

./final2
Introduza o tempo no formato h(hora) m(minuto) s(segundo): h25 m70 x
Erro: número de minutos inválidos .

./final2
Introduza o tempo no formato h(hora) m(minuto) s(segundo): h25 h70 x
Erro: campo hora duplicado.

O meu problema inicial é, como é que eu posso ler com o scanf vários componentes do tempo sabendo que eles podem trocar de sítio (por exemplo "h(hora) m(minuto)" e "m(minuto) h(hora)"?
 
Este próximo exercício que eu te vou pedir sugestões é o último da batch xd

Pretende-se desenvolver um programa para ler valores de tempo no formato “h(hora) m(minuto) s(segundo)”, devolvendo o número de segundos associado ao tempo introduzido.
No entanto, o utilizador deve poder omitir campos (e.g. introduzir só “h23”). Para terminar a leitura o utilizador pode introduzir um carácter diferente de ‘h’, ‘m’ ou ‘s’. Pretende-se também que o programa valide os valores introduzidos, não deixando introduzir valores de minutos ou segundos superiores a 59, nem introduzir campos repetidos (só se pode introduzir 0 ou 1 campo de hora; 0 ou 1 campo de minuto; 0 ou 1 campo de segundo). Repare que:
São necessárias variáveis para guardar cada componente do tempo;
Só há leitura da parte numérica de uma componente do tempo se o carácter for válido;
Dependendo do carácter lido, o valor numérico contribui para o valor final de tempo com um peso diferente;
O ciclo de leitura de componentes do tempo não tem um número de componentes fixo, nem uma ordem fixa.

Um exemplo de utilização com a aplicação pretendida:

./final2
Introduza o tempo no formato h(hora) m(minuto) s(segundo): m56 h37 s23 x
Leu 37h 56m 23s = 136583 segundos

./final2
Introduza o tempo no formato h(hora) m(minuto) s(segundo): h1 x
Leu 1h 0m 0s = 3600 segundos

./final2
Introduza o tempo no formato h(hora) m(minuto) s(segundo): h25 m70 x
Erro: número de minutos inválidos .

./final2
Introduza o tempo no formato h(hora) m(minuto) s(segundo): h25 h70 x
Erro: campo hora duplicado.

O meu problema inicial é, como é que eu posso ler com o scanf vários componentes do tempo sabendo que eles podem trocar de sítio (por exemplo "h(hora) m(minuto)" e "m(minuto) h(hora)"?

A ordem não parece ser problema pois tu tens um carácter próprio que indica se é minuto ou hora. Só te consigo dar ajuda mais logo para o fim do dia. A melhor ideia parece-me guardar tudo numa string e depois parsála. Isso segue sempre uma estrutura: %c%d%d, ou seja, caracter valor valor espaço, por isso nas posições 0, 4 e 8 tens os caractéres, e nas posições 1,2,5,6,9,10 tens os valores. Assim sem pensar muito parece-me a melhor ideia, mas logo poderei ajudar mais.
 
A ordem não parece ser problema pois tu tens um carácter próprio que indica se é minuto ou hora. Só te consigo dar ajuda mais logo para o fim do dia. A melhor ideia parece-me guardar tudo numa string e depois parsála. Isso segue sempre uma estrutura: %c%d%d, ou seja, caracter valor valor espaço, por isso nas posições 0, 4 e 8 tens os caractéres, e nas posições 1,2,5,6,9,10 tens os valores. Assim sem pensar muito parece-me a melhor ideia, mas logo poderei ajudar mais.
Oi, acho que já consegui fazer :P
Código:
#include <stdio.h>
#include <stdlib.h>
int main()
{  
char c;
int a =0;
int hora,minuto,segundo,contagem_h,contagem_m,contagem_s,segundos;

contagem_h = 0;
contagem_m = 0;
contagem_s = 0;
printf("Introduza o tempo no formato h(hora) m(minuto) s(segundo):");
do{
scanf("%c",&c);

switch(c){

   case ' ': break;

   case 'h': scanf("%d",&hora);
        contagem_h++; break;

   case 'm': scanf("%d",&minuto);
        contagem_m++; break;

   case 's': scanf("%d",&segundo);
      contagem_s++; break;

   default: a = 5;



    }
stop++;
  }
while (a < 5);

if(contagem_h > 1){
   printf("campo hora duplicado");
   exit(1);  
      }
if(contagem_m > 1){
   printf("campo minuto duplicado");
   exit(1);
      }
if(contagem_s > 1){
   printf("campo segundo duplicado");
   exit(1);
  }
if(minuto > 59){
   printf("numero de minutos invalidos");
   exit(1);
    }
if(segundo > 59){
   printf("numero de segundos invalidos");  
   exit(1);
    }

segundos=hora*3600 + minuto*60 +segundo   ;  

printf("Leu %dh %dm %ds = %d segundos ",hora,minuto,segundo, segundos);
}

E isto certo?
 
Última edição:
A ordem não parece ser problema pois tu tens um carácter próprio que indica se é minuto ou hora. Só te consigo dar ajuda mais logo para o fim do dia. A melhor ideia parece-me guardar tudo numa string e depois parsála. Isso segue sempre uma estrutura: %c%d%d, ou seja, caracter valor valor espaço, por isso nas posições 0, 4 e 8 tens os caractéres, e nas posições 1,2,5,6,9,10 tens os valores. Assim sem pensar muito parece-me a melhor ideia, mas logo poderei ajudar mais.
Para fazer um parser decente convém receber a string e fazer parse a partir dessa string, mas ir de char a char é uma péssima solução.

O sscanf serve para fazer parse de strings em vez de stdin, e pelo exercicio tem que saber se foi definido mais do que uma vez cada um (hora, minutos, etc).
Código:
  char t[] = "m30 h23 s30 h20 s20";
  unsigned int a=0,b=0,n=0;
  n=sscanf(t, "%*s h%d %*s h%d", &a, &b);
O sscanf devolve o número que encontrou, como há h23 e h20 vai devolver 2, logo com esse n já consegues saber se foi definido por múltiplas vezes (ou 0 vezes), depois é só fazer o sscanf vários vezes para obter minutos e segundos.

O "%*s" é para ignorar o resto.
 
Para fazer um parser decente convém receber a string e fazer parse a partir dessa string, mas ir de char a char é uma péssima solução.

O sscanf serve para fazer parse de strings em vez de stdin, e pelo exercicio tem que saber se foi definido mais do que uma vez cada um (hora, minutos, etc).
Código:
  char t[] = "m30 h23 s30 h20 s20";
  unsigned int a=0,b=0,n=0;
  n=sscanf(t, "%*s h%d %*s h%d", &a, &b);
O sscanf devolve o número que encontrou, como há h23 e h20 vai devolver 2, logo com esse n já consegues saber se foi definido por múltiplas vezes (ou 0 vezes), depois é só fazer o sscanf vários vezes para obter minutos e segundos.

O "%*s" é para ignorar o resto.


Admito que na altura que vi o exercício li por alto, não tive tempo para analisar e pensar bem. Mas se não for receber tudo numa string, como seria?
É que a por numa string não te obrigava a obedecer tamanhos (por outras palavras, não eras obrigado a por hora, minutos e segundos, podes por apenas o que quiseres), sabes o formato dela (%c%d%d ) e sabes as posições para cada coisa.
Para analisar se houve caracteres repetidos, a solução que apresentaste parece-me a melhor.
 
Admito que na altura que vi o exercício li por alto, não tive tempo para analisar e pensar bem. Mas se não for receber tudo numa string, como seria?
É que a por numa string não te obrigava a obedecer tamanhos (por outras palavras, não eras obrigado a por hora, minutos e segundos, podes por apenas o que quiseres), sabes o formato dela (%c%d%d ) e sabes as posições para cada coisa.
Para analisar se houve caracteres repetidos, a solução que apresentaste parece-me a melhor.
A minha solução coloca tudo numa string e depois faz parse dessa string para horas, minutos e segundos, ou estás a dizer para ele usar vários scanfs (que é o que ele está a fazer)?

O "char" pode nem estar no 0, 4 e 8, segundo o exemplo dele tem um "h1", logo o "char" que vinha a seguir estava em na posição 3, e tinhas que andar a fazer muitos mais cálculos.
 
A minha solução coloca tudo numa string e depois faz parse dessa string para horas, minutos e segundos, ou estás a dizer para ele usar vários scanfs (que é o que ele está a fazer)?

O "char" pode nem estar no 0, 4 e 8, segundo o exemplo dele tem um "h1", logo o "char" que vinha a seguir estava em na posição 3, e tinhas que andar a fazer muitos mais cálculos.

Dizia para guardar tudo numa string de uma vez claro! Fazendo referência no post hoje de manhã " A melhor ideia parece-me guardar tudo numa string e depois parsála."

Pois isso já pode ser um problema, pois pensava que tinhas que por sempre 2 dígitos. Sendo assim não pode ir pela ordem que tinha falado, mas tem que ver quando ocorre um espaço na string.
Assim sem pensar muito diria:
- Guardar tudo numa string.
- Ir char a char da string e guardar char a char numa string auxiliar.
- Quando chegasse a um espaço, analisava a string auxiliar que tinha
- Se string tinha chegado ao fim era OK, se não, continuava a abordagem.
 
Back
Topo