Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Henrique Barcelos

O compilador tá maluco?

Recommended Posts

Galera, to com essa função de calculo de media aritmetica aqui, tá td belezinha... O único problema é quando eu termino de executar... Notem que eu mando o programa ler a variavel ch, mas ele não le... Aparece de cara "caractere invalido"...

 

void media_aritmetica() {
	char ch;
	float soma, x, media;
	int i;
	soma = 0;

	printf("Calculo de media simples. \t<x> retornar \t<ENTER> continuar");
	scanf("%c", &ch);

	for (i = 1; i <= 5; i++) {
		printf("Digite o %do. num.:\n", i);
		scanf("%f", &x);
		soma += x;
	}
	media = soma / 5.0;
	printf("\nA media eh: %2f\n\n", media);
	printf("Pressione <x> para voltar ao menu\n");
	scanf("%c", &ch);
	printf("%c", ch);
	while(ch != 'x'){
		printf("Caractere invalido\n");
		printf("Pressione <x> para voltar ao menu\n");
		scanf("%c", &ch);
	}
	if(ch == 'x'){
		main();
	}
}

Se alguem souber onde tá o problema, eu agradeço :rolleyes:

Compartilhar este post


Link para o post
Compartilhar em outros sites

O compilador não lê variável....

Limpe o buffer no scanf.Tem um topico sobre isso.

 

if(ch == 'x'){

main();

}

 

Se você fez o programa do jeito que eu imagino, está nojento: main -> media_aritmetica -> main -> media_aritmetica -> main -> media_aritmetica...

Compartilhar este post


Link para o post
Compartilhar em outros sites

como a Isis disse sujeira de buffer.

e é verdade, uma função chamando a main(); q coisa feia :P

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom... então como que faço pra retornar à função principal? exit()????

 

Vou ver isso sobre o buffer... estranho o programa simplesmente ignorar o scanf :s

Compartilhar este post


Link para o post
Compartilhar em outros sites
Bom... então como que faço pra retornar à função principal? exit()????

 

Programando direito.

 

 

Código porco:

 

int main() {

int opcao;
scanf("%d",&opcao);
switch(opcao){
	  case 1:
		   produto_vetorial();
		   return main();
		   break;
	  case 2:
			produto_escalar();
			return main();
			break;
	  case 3:
			 minimax();
			return main();
			break;
	  case 4: return;
}
}

 

 

Código decente:

 

int main() {
int opcao;
while(1) {
	 scanf("%d",&opcao);
	 if (opcao == 1) produto_vetorial();
	 else if (opcao == 2) produto_escalar();
	 else if (opcao == 3) minimax();
	 else if (opcao == 4) break;
 }
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

Desulpa, mas você está usando break dentro de um while...

 

Isso não é estruturado...

 

Pelo menos foi assim que eu aprendi...

 

Outra coisa... não tem diferença nenhuma entre um switch e um monte de if else's... na verdade, com switch fica até mais organizado dependendo...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Cara, posso estar enganado, mas, como já dito, o problema está no buffer de leitura.

 

Basicamente acontece que você lê um dado e dá um ENTER, na hora que você dá esse ENTER, ele fica armazenado no buffer como se fosse um dado a ser lido, daí quando você dá um scanf ele passa direto, pois ele lê esse dado.

 

Há duas soluções, uma é limpar o buffer sempre antes de ler um dado, porém isso não é cross-plataform e só funciona perfeitamente bem no windows, além do mais há a necessidade de chamar uma função (o fflush(stdin)) toda vez antes de cada scanf (pra string ou char).

 

A outra solução é mais simples e mais elegante, basta você adicionar um espaço (" ") ou um enter ("\n") no scanf, o que esses caracteres fazem é consumir tudo que seja espaço em branco a mais (isso inclui: enter, tab e espaço), sendo assim, se você colocar antes do %[char] ele consumirá o que tem antes (e irá "limpar" o buffer, lembre-se, limpar somente caraceres "brancos") ou depois do %[char] ele irá limpar o que vem depois. Eu costumo limpar antes, mas poderia ser antes e depois, assim você garante. No seu exemplo:

 

void media_aritmetica() {
	char ch;
	float soma, x, media;
	int i;
	soma = 0;

	printf("Calculo de media simples. \t<x> retornar \t<ENTER> continuar");
	scanf("\n%c", &ch);

	for (i = 1; i <= 5; i++) {
		printf("Digite o %do. num.:\n", i);
		scanf("\n%f", &x);
		soma += x;
	}
	media = soma / 5.0;
	printf("\nA media eh: %2f\n\n", media);
	printf("Pressione <x> para voltar ao menu\n");
	scanf("\n%c", &ch);
	printf("%c", ch);
	while(ch != 'x'){
		printf("Caractere invalido\n");
		printf("Pressione <x> para voltar ao menu\n");
		scanf("%c", &ch);
	}
	if(ch == 'x'){
		main();
	}
}

Teste aí e ve se funciona como você espera.

 

Quando ao problema que apareceu no decorrer do tópico, de fato um break dentro de um while (e um while(1)) não é muito "bonito", mas na minha opinião funciona muito melhor do que chamar o main (que você ocupa espaço desnecessário na pilha), eu não vejo problema em usar o while(1) mas um professor de faculdade provavelmente iria te encher o ..... Então o ideal seria deixar algo +ou- assim (pra ficar bonito e deixar o prof. feliz):

 

int main() {
	int opcao;
	do{
		 scanf(" %d",&opcao); // veja que coloquei um espaço antes do %d
		 switch(opcao){
			  case 1:
				  produto_vetorial();
				  break;
			  case 2:
				  produto_escalar();
				  break;
			  case 3:
				  minimax();
				  break;
			  case 4:
				  break;
			  default:
				  printf("Opcao incorreta!\n");
				  opcao = -1;
	 }while(opcao >= 1 && opcao <= 3);
}

É isso...

 

flw

Compartilhar este post


Link para o post
Compartilhar em outros sites

Há duas soluções, uma é limpar o buffer sempre antes de ler um dado, porém isso não é cross-plataform e só funciona perfeitamente bem no windows, além do mais há a necessidade de chamar uma função (o fflush(stdin)) toda vez antes de cada scanf (pra string ou char).

eu vou fingir que não li isso...

Existe um tópico, relativamente grande, que trata sobre esse asunto. Laboratório de Códigos Fontes, está pendurado...

 

Rick

Outra coisa... não tem diferença nenhuma entre um switch e um monte de if else's... na verdade, com switch fica até mais organizado dependendo...

foi a única diferença que você notou??

 

cof cof *return main()* cof cof...

Compartilhar este post


Link para o post
Compartilhar em outros sites
Desulpa, mas você está usando break dentro de um while...

 

Isso não é estruturado...

 

Pelo menos foi assim que eu aprendi...

 

 

Ao invés de prestar atenção se é estruturado ou não, preste atenção na diferença na pilha durante a execução, porque ISSO caga mais com o programa do que não seguir paradigma.

 

 

Outra coisa... não tem diferença nenhuma entre um switch e um monte de if else's... na verdade, com switch fica até mais organizado dependendo...

 

Existe sim, diferença entre switch e if:

1- Você não pode usar condições diferentes de igualdade num switch.

2- O switch está restrito a inteiros e caracteres.

3-

 

Código com switch

main:
	  leal	4(%esp), %ecx
	  andl	$-16, %esp
	  pushl   -4(%ecx)
	  pushl   %ebp
	  movl	%esp, %ebp
	  pushl   %ecx
	  subl	$36, %esp
	  movl	$3, -8(%ebp)
	  movl	-8(%ebp), %eax
	  movl	%eax, -24(%ebp)
	  cmpl	$2, -24(%ebp)
	  je	  .L4
	  cmpl	$3, -24(%ebp)
	  je	  .L5
	  cmpl	$0, -24(%ebp)
	  je	  .L3
	  jmp	 .L2
 .L5:
	  movl	$.LC0, (%esp)
	  call	puts
	  jmp	 .L2
 .L4:
	  movl	$.LC1, (%esp)
	  call	puts
	  jmp	 .L2
 .L3:
	  movl	$.LC2, (%esp)
	  call	puts
 .L2:
	  movl	$0, %eax
	  addl	$36, %esp
	  popl	%ecx
	  popl	%ebp
	  leal	-4(%ecx), %esp
	  ret

 

 

 

 

Código com if

main:
	  leal	4(%esp), %ecx
	  andl	$-16, %esp
	  pushl   -4(%ecx)
	  pushl   %ebp
	  movl	%esp, %ebp
	  pushl   %ecx
	  subl	$20, %esp
	  movl	$3, -8(%ebp)
	  cmpl	$3, -8(%ebp)
	  jne	 .L2
	  movl	$.LC0, (%esp)
	  call	puts
	  jmp	 .L3
 .L2:
	  cmpl	$2, -8(%ebp)
	  jne	 .L4
	  movl	$.LC1, (%esp)
	  call	puts
	  jmp	 .L3
 .L4:
	  cmpl	$0, -8(%ebp)
	  jne	 .L3
	  movl	$.LC2, (%esp)
	  call	puts
 .L3:
	  movl	$0, %eax
	  addl	$20, %esp
	  popl	%ecx
	  popl	%ebp
	  leal	-4(%ecx), %esp
	  ret

 

Compilados sem flag de otimização nenhuma (LC0,LC1 e LC2 são as strings a imprimir). O switch reserva mais espaço na pilha do que o if. No teu desktop pode não parecer nada, mas numa aplicação que roda em ambiente extremamente limitado, bytes fazem diferença.

 

Outra coisa que pode-se ver pelo assembly: o switch, ao invés de compara e fazer a tarefa logo abaixo caso for igual, "opta" por realizar um jump p/ imprimir a string se for igual e depois, realiza mais um jump p/ terminar o programa. Considero isso bem mais confuso do que comparar e se for igual, imprimir a string em seguida, pulando somente p/ ir para o final do programa ou se o elemento comparado não satisfizer a comparação, como faz o if. Desenhe o grafo desses programas. O grafo do if é bem mais "atrativo" do que o grafo do switch.

 

Também não sei do teu computador, já que compilo as coisas normlmente dentro do VMWare por causa dos trabalhos da pós. Mas escrevendo o seguinte código e passando pelo gnu profiler vi uma diferença a favor do IF.

 

#include <stdio.h>
 int main(int argc, char const* argv[])
 {
  int a;
  int valor;
  for(a=1;a<999999999;a++) {
	  if (a == 1) valor = -1;
	  else if (a==2) valor=-2;
	  else if (a==3) valor=-3;
	  else valor=0;
  }
  return 0;
 }

 

 #include <stdio.h>
 int main(int argc, char const* argv[])
 {
  int a;
  int valor;
  for(a=1;a<999999999;a++) {
	  switch(a){
		  case 1:
			  valor = -1;
			  break;
		  case 2:
			  valor=-2;
			  break;
		  case 3:
			  valor=-3;
			  break;
		  default:
			  valor=0;
	  }
  }
  return 0;
 }

 

SWITCH:

cumulative seconds: 5.79

self seconds: 5.79

 

IF:

cumulative seconds : 5.42

self seconds : 5.42

 

 

4- A delimitação de blocos de código (multilinhas) é diferente. No if isso é feito através de chaves. No switch, a delimitação é feita pela cláusula case e o break, sendo que a última cláusula não precisa de break

 

5- O comportamento deles é diferente (dá p/ ver isso no assembly gerado). Enquanto o if é processado em cascata e você consegue ver isso num debugger. No caso do switch, é mais "transparente": marcando um breakpoint na keyword switch e os demais nas cláusulas case, a primeira parada é no switch(op) e a segunda é o bloco de código da cláusula case verdadeira (não é processado em cascata visivelmente).

 

6- Engana fácil. Observando o assembly do switch, após verificar que a cláusula case é verdadeira, ele segue até o final da estrutura. Mas normalmente os programadores novos acham que não precisam saber assembly "porque ninguém usa" e p/ tentar imitar o if abaixo

 

if (a == 2) puts("if 1");
if (a == 3) puts("if 2");
puts("---");

 

Podem ser levados a escrever

 

switch(a) {
  case 2: puts("case 1");
  case 3: puts("case 2");
  default: puts("-----");
}

 

Já que, aparentemente, a ausência do break vai impedir que o fluxo seja desviado para o final, processando todos os cases em seqüência.Eis o assembly:

 

	   movl $.LC4, (%esp) #.LC4 = "SWITCH"
   call puts
   movl -8(%ebp), %eax
   movl %eax, -24(%ebp)
   cmpl $2,-24(%ebp)
   je .L5
   cmpl $4, -24(%ebp)
   je .L6
   jmp .L4

.L5:
   movl $.LC1,(%esp)
   call puts
.L6:
   movl $.LC5,(%esp)
   call puts
.L4:
	movl $.LC3,(%esp)
   call puts

 

E o que acontece é que imprime "case 1", "case 2" e "-----", ao invés de "case 1" e "-----", se assemelhando mais a 3 chamadas da função puts sem qualquer condicional, já que em nenhuma das seções alvo do jump temos um desvio para a instrução depois do .je.

Alterando o assembly do código gerado parao switch, precisamos adicionar um label e um jump incondicional p/ que o switch faça a mesma coisa que o if mostrado.

 

 

	   movl $.LC4, (%esp) #.LC4 = "SWITCH"
   call puts
   movl -8(%ebp), %eax
   movl %eax, -24(%ebp)
   cmpl $2,-24(%ebp)
   je .L5
VOLTA1:
   cmpl $4, -24(%ebp)
   je .L6
   jmp .L4

.L5:
   movl $.LC1,(%esp)
   call puts
jmp VOLTA1
.L6:
   movl $.LC5,(%esp)
   call puts
.L4:
	movl $.LC3,(%esp)
   call puts

 

No entanto, se trocarmos de lugar os números comparados no código original, o if e o switch mostram os mesmos resultados (GCC):

 

#include <stdio.h>
int main() {
int a = 2;
puts("IF");
if (a == 3) puts("if 1");
if (a == 2) puts("if 2");
puts("---");

puts("SWITCH");
switch(a) {
   case 3: puts("case 1");
   case 2: puts("case 2");
   default: puts("-----");
}
}

 

Só por causa disso é capaz de alguém escrever um artigo "Switch considered harmful"...

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.