Jump to content
Dexter's Lab

divisores e estrutura

Recommended Posts

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

Share this post


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

Share this post


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

Edited by HappyHippyHippo

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

Share this post


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

Edited by thoga31

Share this post


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

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.