Ir para o conteúdo
Dexter's Lab

Exercício de Teste

Mensagens Recomendadas

Dexter's Lab

Boas pessoal.

Queria, antes de mais, agradecer as opiniões, dicas e disposição em ajudar que têm prestado. Tenho efetivamente evoluído em C e aprendido muito mais do que se não tivesse esse feedback vosso.

Tive nota máxima no teste, que era só um exercício.

Gostava contudo de saber como poderia ter melhorado o meu programa.

O enunciado pede que calculemos a area e perimetro de um retangulo ou triangulo. Tinhamos de usar uma função menu, dois submenus com as respetivas funções de input e umas funções exclusivas aos calculos.

A ideia principal do programa pedido era perceber o nosso "à vontade" com funções.

Fugi um pouco dessa estrutura para outra que o meu stor disse que talvez até fosse melhor, e por isso não me descontou valores.

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

int MENU();			 /* Mostra as opcoes do programa */

void MENU_RETANGULO();		   /* Mostra as opcoes do submenu (Retangulo) */
void MENU_TRIANGULO();		   /* Mostra as opcoes do submenu (Triangulo) */
float AREA_TRIANGULO (float base, float altura);    /* Calcula: Area do Triangulo */
float PERIMETRO_TRIANGULO (float base);	  /* Calcula: Perimetro do Triangulo */
float AREA_RETANGULO (float comprimento, float largura);  /* Calcula: Area do Retangulo */
float PERIMETRO_RETANGULO (float comprimento, float largura); /* Calcula: Perimetro do Retangulo */

void INPUT_OUTPUT(int opcao);		 /* Recebe e valida o Input e mostra o Output */


#define CLEAR system("cls")
#define PAUSE getch(); CLEAR
int main(void)
{
 while (MENU()) { /*Entrada no menu do programa */ }

 return 0;
}

/* MENUS */
int MENU()
{
 int confirma, escolha;

 CLEAR;

 puts("TESTE AVALIACAO - PSI\n\n");

 puts("1.....RETANGULO");
 puts("2.....TRIANGULO");
 puts("0.....SAIR");

 do {
 printf ("ESCOLHA: ");
 confirma = (scanf("%d", &escolha)) ? escolha < 3 : 0;
 fflush(stdout);

 if (!(escolha)) exit(0);

 } while (!(confirma));


 switch(escolha) {
	 case 1:
	   MENU_RETANGULO();
	   break;
		  case 2:
	   MENU_TRIANGULO();
	   break;
	    case 0:
	   return 0;
	   break;
		  default:
	   printf("Opcao Invalida!");
	   PAUSE;
 }		  
}
void MENU_RETANGULO()
{
  int opcao_calculo;

  CLEAR;

  puts("\tOPCOES DO RETANGULO\n");

  puts("1.....AREA");
  puts("2.....PERIMETRO");
  puts("0.....MENU ANTERIOR");

  printf ("OPCAO: "); scanf("%d", &opcao_calculo);

	  switch(opcao_calculo) {
	 case 1:
	   INPUT_OUTPUT(1);
	   break;
		  case 2:
	   INPUT_OUTPUT(2);
	   break;
	    case 0:
	   CLEAR;
	   MENU();
	   break;
		  default:
	   puts("Opcao Invalida!");
	   PAUSE;
	   MENU_RETANGULO();
 }		  
}
void MENU_TRIANGULO()
{
  int opcao_calculo;

  CLEAR;

  puts("\tOPCOES DO TRIANGULO\n");

  puts("1.....AREA");
  puts("2.....PERIMETRO");
  puts("0.....MENU ANTERIOR");

  printf ("OPCAO: "); scanf("%d", &opcao_calculo);

	 switch(opcao_calculo) {
	 case 1:
	   INPUT_OUTPUT(3);
	   break;
		  case 2:
	   INPUT_OUTPUT(4);
	   break;
	    case 0:
	   MENU();
	   break;
		  default:
	   puts("Opcao Invalida!");
	   PAUSE;
	   MENU_TRIANGULO();
 }		  
}
/* DADOS */
void INPUT_OUTPUT(int opcao)
{
   float comprimento, largura, base, altura;

   switch(opcao) {
   case 1:
   /* Area do Retangulo */

	 CLEAR;

		   puts ("AREA DO RETANGULO\n\n");

		   printf ("COMPRIMENTO: "); scanf("%f", &comprimento);
		   printf ("LARGURA: ");  scanf("%f", &largura);

		  printf("%.2fcm", AREA_RETANGULO(comprimento, largura));
		  PAUSE;

	   MENU_RETANGULO();

		 break;

  case 2:
   /* Perimetro do Retangulo */

    CLEAR;

	    puts ("PERIMETRO DO RETANGULO\n\n");

		  printf ("COMPRIMENTO: "); scanf("%f", &comprimento);
		  printf ("LARGURA: ");  scanf("%f", &largura);

		 printf("%.2fcm", PERIMETRO_RETANGULO(comprimento, largura));
		 PAUSE;

	  MENU_RETANGULO();

		    break;


  case 3:
   /* Area do Triangulo */

    CLEAR;

	    puts ("AREA DO TRIANGULO\n\n");

	    printf ("BASE: "); scanf("%f", &base);
	    printf ("ALTURA: "); scanf("%f", &altura);

		 printf ("%.2fcm", AREA_TRIANGULO(base, altura));
		 PAUSE;

				   MENU_TRIANGULO();

			 break;

  case 4:
   /* Perimetro do Triangulo */

    CLEAR;

	   puts ("PERIMETRO DO TRIANGULO\n\n");

	    printf ("BASE: "); scanf("%f", &base); 

		 printf ("%.2fcm", PERIMETRO_TRIANGULO(base));
		 PAUSE;

				 MENU_TRIANGULO();

			 break;

   default:
   printf ("Opcao Invalida!");
   PAUSE;
 }
}

/* CALCULOS */
float AREA_TRIANGULO(float base,
			   float altura)
{   
   return (base * altura) /2;
}

float PERIMETRO_TRIANGULO(float base)
{   
 return base * 3;
}


float AREA_RETANGULO(float comprimento,
			   float largura)
{	 
  return comprimento * largura;
}

float PERIMETRO_RETANGULO(float comprimento,
					 float largura)
{	
  return (comprimento * 2) + (largura * 2);
}

Pretendo críticas. Obrigado.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

a primeira coisa que me salta à vista (tirando a indentação ...) é que não fazes qualquer tipo de validação dos dados de entrada


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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Copiei o teu codigo e comecei a edita-lo para anotar criticas

1) Gaaaahh!!! detesto espacos em branco no fim das linhas

2) O header <conio.h> nao esta disponivel no meu computador. Por causa duma unica instrucao (getch()) usada umas poucas de vezes limitas o teu programa desnecessariamente

3) Eu gosto de usar prototipos para todas as funcoes, mesmo as que nao recebem parametros. A declaracao int MENU(); nao é um prototipo; para ser prototipo devia ser int MENU(void);

4) Sem razoes especias, nunca uses float; usa sempre double

5) system("cls"); tambem nao funciona no meu sistema. Se conseguisses fazer o programa sem a limpeza do ecra alcancavas mais computadores

6) O uso de maisuculas chateia-me!

7) O que e isto? ???? Parte esta confusao em 2 ou 3 linhas!

confirma = (scanf("%d", &escolha)) ? escolha < 3 : 0;

8) Eu tambem ponho um break no ultimo case dum switch

9) a tua funcao menu() pode acabar sem passar por uma instrucao de return. ERRO

10) menu_rectangulo() ... xiiiiiiiiiiiiiiiiiiii ... estas a chamar as funcoes recursivamente. Nao facas isso. Organiza as funcoes de maneira a que quado uma sub-funcao acaba a funcao principal volta a repetir o ciclo.

Pronto e com esta da recursividade acabei de estudar o teu programa.

Sugestao: segue sempre a mesma convencao para chamar funcoes. Por vezes tinhas um espaco a frente do nome da funcao, outras vezes tinhas o parentesis logo a seguir (printf() ... printf ())


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
Dexter's Lab

HHHippo, tens razão. Devia ter validado os dados de entrada dos valores. A questão é que só tinhamos 50 minutos; a ideia do stor era colocar-nos a trabalhar estruturação sob pressão de tempo e por isso não me preocupei muito com um "pormenor" que merece a maior importância. Vou passar a validar todos os inputs. Já agora, faço-o sempre na estrutura que usei para a escolha de opção no menú principal? Ou existem situações mais específicas de validação? (nomeadamente, como faço para apenas validar 2 números fracionarios?)

Copiei o teu codigo e comecei a edita-lo para anotar criticas

1) Gaaaahh!!! detesto espacos em branco no fim das linhas

2) O header <conio.h> nao esta disponivel no meu computador. Por causa duma unica instrucao (getch()) usada umas poucas de vezes limitas o teu programa desnecessariamente

3) Eu gosto de usar prototipos para todas as funcoes, mesmo as que nao recebem parametros. A declaracao int MENU(); nao é um prototipo; para ser prototipo devia ser int MENU(void);

4) Sem razoes especias, nunca uses float; usa sempre double

5) system("cls"); tambem nao funciona no meu sistema. Se conseguisses fazer o programa sem a limpeza do ecra alcancavas mais computadores

6) O uso de maisuculas chateia-me!

7) O que e isto? ???? Parte esta confusao em 2 ou 3 linhas!

confirma = (scanf("%d", &escolha)) ? escolha < 3 : 0;

8) Eu tambem ponho um break no ultimo case dum switch

9) a tua funcao menu() pode acabar sem passar por uma instrucao de return. ERRO

10) menu_rectangulo() ... xiiiiiiiiiiiiiiiiiiii ... estas a chamar as funcoes recursivamente. Nao facas isso. Organiza as funcoes de maneira a que quado uma sub-funcao acaba a funcao principal volta a repetir o ciclo.

Pronto e com esta da recursividade acabei de estudar o teu programa.

Sugestao: segue sempre a mesma convencao para chamar funcoes. Por vezes tinhas um espaco a frente do nome da funcao, outras vezes tinhas o parentesis logo a seguir (printf() ... printf ())

1 - Tens toda a razão. Eu também detesto mas não tive mesmo tempo na altura do teste para dar muita atenção a esse aspeto. Mas ainda bem que referiste isso, assim vou dar mais ênfase nos próximos códigos a isso.

2 ^ 5 - É muito bem visto. Já sabia e há algum tempo que gostava de explorar alternativas mais globais. Agora que disseste isso vou tornar numa prioridade essa questão de funções com uma maior capacidade de compatibilidade.

3 - Pmg, protótipo no sentido de poder usá-la mais tarde, noutro programa?

4 - O double não me vai ocupar mais espaço? Uma vez que um double é float^2, supondo que uso 4 floats no programa, sendo esses double seria como se usasse o dobro dos floats (ocupando o dobro da memoria).

6 - Eu só uso maiúsculas em coisas constantes e às quais posso querer recorrer mais que uma vez, como o nome da função e dos macros. É só mesmo nessas situações.

7 - Neste ponto discordo em parte. Pelo menos é-me mais legível como se fosse uma fórmula matemática do que partido como uma função, mas acho que tens razão se pensar que pode estar de fato ilegível numa prespetiva mais geral.

8 - Sinceramente, não sei como não lá pus break no default. Ponho sempre e desta vez, por alguma razão, não coloquei em ambos. Vou ter mais em atenção.

9 - Não me tinha apercebido na altura de escrever aquela parte do código que a falta o default poderia desencadear isso. Talvez pela pressa. Foi muito bem observado. Vou também considerar mais isso nos próximos programas.

10 - Obrigado pela dica. Mas porque não chamar uma função anterior para chegar lá? É quase como se fosse um goto, eu sei, e sei que regra geral bons programadores detestam a estruturação em "esparguete", mas porque não?

Obrigado pelas críticas. Vou amanhã ou depois alterar este código tendo em consideração todas as vossas dicas.

HHHippo, mais uma vez, na passagem do código para aqui a identação ficou um bocado distorcida. Na próxima passagem de código vou tentar re-identar na própria cópia.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

ok, eu percebo que 50 minutos é pouco tempo para "pensar" em indentação, no entanto esse passo não é uma questão de "pós-processamento" e nem sequer deveria ser necessário pensar. deveria ser um reflexo como ter uma boa caligrafia para que os outros consigam entender o que escreveste.

já agora, usa o editor simples do forúm para não perderes a indentação (primeiro botão do editor)

agora vou tentar responder a algumas questões por parte do @pmg.

4 - um double tem 8 bytes, se tiveres 4GB de memória estás a usar 0.000000002% da tua memória. isto para não falar do espaço em disco ...

6 - ok, podes usar em constantes, mas o nome de uma função não é uma constante mas sim um identificador (como nome de variáveis)

7 - eu até aceito o uso do operador ternário, mas agora responde-me o que acontece se eu escrever -1 ?

10 - imagina que insiro um valor errado 1 milhão de vezes, tens 1 milhão de chamadas recursivas ...

se achas que 1 milhão de vezes é algo absurdo, imagina que a escolha é algo que vem pela net, e por algum desvaneio do acaso, existe um erro que faz com que o valor seja errado ... prontos, lá tens tu muitas chamadas recursivas ...


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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

3) protótipo no sentido de informar o compilador sobre o tipo do valor devolvido pelas funções e pelos tipos (e quantidades) de argumentos que as funções aceitam.

Uma declaração serve para o compilador saber que a função existe (e não se queixar quando encontrar essa função no código). Mas não indica quais os parametros que a função aceita, por isso o compilador não verifica os argumentos

/* funcao foo() não declarada */
int bar(); /* declaracao */
int baz(void); /* prototipo (tambem é declaracao) */
int qux() { return 0; } /* definicao sem prototipo */
int corge(void) { return 0; } /* definicao com prototipo */

int main(void) {
   int a, b, c, d, e, f, g, h, i, j;
   a = foo(); /* chamada de funcao nao declarada: ERRO na compilacao */
   b = foo(42); /* chamada de funcao nao declarada: ERRO na compilacao */
   c = bar(); /* chamada de funcao declarada: OK (o linker é que da erro) */
   d = bar(42); /* chamada de funcao declarada com argumentos diferentes: OK (o linker é que da erro) */
   e = baz(); /* chamada de funcao com prototipo: OK */
   f = baz(42); /* chamada de funcao com prototipo mas com argumentos incompativeis: ERRO */
   g = qux(); /* chamada de funcao sem prototipo: OK */
   h = qux(42); /* chamada de funcao sem prototipo mas com argumentos incompativeis: OK mas COMPORTAMENTO NAO DEFINIDO */
   i = corge(); /* chamada de funcao com prototipo: OK */
   j = corge(42); /* chamada de funcao com prototipo mas com argumentos incompativeis: ERRO */

   return 0;
}

4) Sim, o double ocupa mais espaco em memoria. Não te preocupes com "meia-duzia" de bytes :)

Se tiveres um array (ou uma lista, ...) com milhoes de valores já a história é outra (é uma das razões especiais para usar float)

6) o comum é usar maisuculas apenas para macros (INT_MAX, CHAR_BIT, ...). As funções costumam ser em minusculas (printf, malloc, etc ...)

Editado por pmg

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

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.