Ir para o conteúdo
Dexter's Lab

divisores e estrutura

Mensagens Recomendadas

Dexter's Lab

Viva. O que está a acontecer com os meus divisores? Parece-me tudo bem mas o output está incorreto.

Já agora, se me puderem dar umas dicas de como posso trabalhar/organizar este código melhor (principalmente) a nível de estrutura, agradecia - porque é para apresentar ao professor.

# include <stdio.h>

void menu ();
void valores_mul ();
void valores_div ();

int cont;

void menu ()
{
 int slct;

 do {

   system ("cls");

   puts ("1...Divisor \n\n2...Multiplo\n\n0....Sair\n\nESCOLHA: ");
   scanf ("%d", &slct);

   switch (slct) {
     case 1:
       valores_div();
       break;
     case 2:
       valores_mul();
       break;
     case 0:
       exit(0);
     default:
       printf ("\nOpcao invalida!");
   }

 } while (slct != '0');

}

void valores_mul() {

 int num, n_mul;

 printf ("Valor a ser multiplo: "); scanf ("%d", &num);
 printf ("\n Agora numero de multiplos: "); scanf ("%d", &n_mul);

 for (cont = 1; cont <= n_mul; cont++) {
   printf ("%d x %d = %d \n", num, cont, num*cont);
 }

 getche();
}

void valores_div() {

 int div;

 printf ("Digite valor para mostrar divisores: "); scanf ("%d", div);

 for (cont = 1; cont <= div; cont++) {
   if ((div%cont)==0) {
     printf ("%d ", cont);
   }
 }

 getch();
}


int main (void)
{

 menu();

 getche();
 return 0;
}

Todas as ajudas que me prestaram aqui têm sido muito importantes. Obrigado, desde já.

output dos divisores:

Valor: 6
Divisores: 1 2 3 4 5 6 7 8 9 10 12 14 15 20 ... 

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Na funcao valores_div() passas o valor actual da variavel div para a funcao scanf() quando deverias passar o endereco da variavel


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
HappyHippyHippo

// indentação é quase obrigatória !!!!

# include <stdio.h>

void menu ();
void valores_mul ();
void valores_div ();

int cont; // <-- remove rvariavel global

void menu ()
{
 int slct;

 do {
   system ("cls"); // <-------- não usar a função system
   puts ("1...Divisor \n\n2...Multiplo\n\n0....Sair\n\nESCOLHA: ");
   scanf ("%d", &slct);
   // falta validacao de input
   // falta limpeza do buffer de leitura

   switch (slct) {
   case 1:
     valores_div();
     break;
   case 2:
     valores_mul();
     break;
   case 0:
     exit(0); // <--- em vez de chamar exit, basta colocares um return, afinal é uma função
   default:
     printf ("\nOpcao invalida!");
     // <--- falta um break simplesmente para normalização
   }
 } while (slct != '0');
}

void valores_mul() {
 int num, n_mul;

 printf ("Valor a ser multiplo: ");
 scanf ("%d", &num);
 // falta limpeza do buffer de leitura

 printf ("\n Agora numero de multiplos: ");
 scanf ("%d", &n_mul);
 // falta limpeza do buffer de leitura

 for (cont = 1; cont <= n_mul; cont++) {
   printf ("%d x %d = %d \n", num, cont, num*cont);
 }

 getche(); // <--- não uses getche, mas sim getchar()
}

void valores_div() {
 int div;

 printf ("Digite valor para mostrar divisores: ");
 scanf ("%d", div); // <----------- o argumento deverá ser um endereço
 // falta limpeza do buffer de leitura

 for (cont = 1; cont <= div; cont++) {
   if ((div%cont)==0) {
     printf ("%d ", cont);
   }
 }

 getch(); // <--- não uses getch, mas sim getchar()
}

int main (void) {

 menu();
 getche(); // <--- não uses getche, mas sim getchar()

 return 0;
}

o teu código com algumas correcções:

# include <stdio.h>

void menu ();
void valores_mul ();
void valores_div ();

#ifdef __linux__
#define CLEAR_SCREEN system("clear");
#else
#define CLEAR_SCREEN system("cls");
#endif

#define CLEAR_INPUT while (getchar() != '\n');

#define PAUSE getchar(); CLEAR_INPUT

void menu ()
{
 int slct, ok;

 do {
   CLEAR_SCREEN
   printf("1...Divisor \n\n2...Multiplo\n\n0....Sair\n\nESCOLHA: ");
   ok = scanf ("%d", &slct);
   CLEAR_INPUT

   if (ok) {
     switch (slct) {
     case 1:
       valores_div();
       break;
     case 2:
       valores_mul();
       break;
     case 0:
       return;
     default:
       printf ("\nOpcao invalida!");
       PAUSE
       break;
     };
   } else {
     printf ("\nOpcao invalida!");
     PAUSE
   }
 } while (slct != '0');
}

void valores_mul() {
 int num, n_mul, cont, ok;

 do {
   printf ("Valor a ser multiplo: ");
   ok = scanf ("%d", &num);
   CLEAR_INPUT
 } while (!ok);

 do {
   printf ("\n Agora numero de multiplos: ");
   ok = scanf ("%d", &n_mul);
   CLEAR_INPUT
 } while (!ok);

 for (cont = 1; cont <= n_mul; cont++) {
   printf ("%d x %d = %d \n", num, cont, num*cont);
 }

 PAUSE
}

void valores_div() {
 int div, cont, ok;

 do {
   printf ("Digite valor para mostrar divisores: ");
   ok = scanf ("%d", &div);
   CLEAR_INPUT
 } while (!ok);

 for (cont = 1; cont <= div; cont++) {
   if ((div%cont)==0) {
     printf ("%d ", cont);
   }
 }

 PAUSE
}

int main (void) {

 menu();

 return 0;
}

Editado por HappyHippyHippo

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Dexter's Lab

.1 HHHippo, porquê o "ok!"? Sei o que faz, mas não sei o propósito e a mais valia em relação ao que estava anteriormente.

.2 Porquê o if antes do switch se vai fazer o mesmo?

.3 O scanf retorna dados? Sempre me disseram que o scanf tinha limitações (por exemplo, não podia fazer " if(scanf()) " porque não retorna dados - por isso acho estranho poder retornar para o "ok!". Ainda assim, qual a razão de estar assim?

ok = scanf ("%d", &num);

.4 Se pudesses dar também uma achega com isto:

#define CLEAR_INPUT while (getchar() != '\n');

sff.

Obrigado.

Pmg, tens razão. Já é distração pelo cansaço. Obrigado pela observação.

Editado por thoga31

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

sim, o scanf retorna dados.

o scanf retorna o número de elementos lidos do teclado, exemplo:

int i, v1, v2, v3, v4;

i = scanf("%d %d %d %d", &v1, &v2, &v3, &v4);

// se o input for :
// 1 2 3 as 4
// somente as primeira 3 variáveis serão preenchidas e o scanf retorna 3
// logo à variável i será atribuído o valor de 3

// se o input for :
// as 1 2 3 4
// nenhuma variável será preenchida e o scanf retorna 0
// logo à variável i será atribuído o valor de 0

com isso, espero que percebas a razão da variável ok

----

o if está lá para que o switch não seja executado quando não foi lido correctamente um valor do teclado.

isto é importante porque como referi acima, a variável de destino dos dados do scanf só é actualizada se os dados forem correctamente lidos. para prevenir que uma leitura errada dos dados leve a que um valor anterior da variável slct implique a entrada numa das opções do switch, o if foi colocado no código.

----

é um problema muito usual que (por alguma razão muito estranha) nunca é explicada ao iniciantes de programação. nem imaginas a quantidade de tópicos aqui no forum que tiveram origem nesse problema. o problema é este:

quando tu escreves na consola, estás a inserir dados num buffer de leitura. agora imagina que escreves o numero 123. o que acontece realmente é :

- escreves os caracteres '1', depois o '2', de seguida o '3'

aqui estes dados ainda não foram para o buffer de leitura, e é por isso que o scanf ainda não retornou nada. somente quando carregas na tecla Enter é que os dados são processados pela consola e gravados no buffer.

o problema é que a tecla Enter também envia um caracter muito específico para o buffer de leitura, o caracter '\n'.

mas no teu código tens:

scanf("%d", &var);

como podes ver, so estás a pedir para ler um número. e é isso que o scanf faz, lê um número e não toca no resto, ficando o caracter '\n' no buffer de leitura.

outro tipo de casos é quando o utilizador adiciona mais do que o pretendido ou algo diferente.

imagina o mesmo caso. pedes um número ao utilizador e ele insere o seguinte : "1 2"

o scanf irá ler o número 1, ficando o número 2 no buffer de leitura. o que acontece é na próxima vez que chamares o scanf, os caracteres ' 2' serão os primeiros a serem processados, dando azo a muitos erros ou tópicos relativos com erros descritos do géneor:

- o meu programa ignora o menu (porque a opção foi lida de dados inseridos anteriormente)

- não aparece nada (porque o getchar leu algo que ficou no buffer)

- etc ...

o mesmo acontece com dados errados.

se pedires num número no scanf, e inserires 'a123', o scanf não lê o número e não retira nada do buffer, devido ao 'a' inicial.

agora, para resolver este tipo de problema (todos de uma vez) é limpar o buffer de leitura sempre que chamas o scanf.

como te disse anteriormente, os dados só são inseridos no buffer de leitura quando carregas no Enter, e disse também que o Enter adiciona um caracter específico no buffer, o caracter '\n'.

o código que está na macro, não é mais do que : enquando o caracter lido do buffer de leitura for diferente de '\n', não faz nada

desta forma, o buffer de leitura é limpo de qualquer dados. prevenindo assim a miriedade de erros ai provenientes.


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

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.