Jump to content

Conflito entre duas funções If


BrunoJunior
Go to solution Solved by nunopicado,

Recommended Posts

Sempre que seleciono a sobremesa número 1, em vez de aparecer apenas a frase "Iremos trazer agora o seu arroz doce então.", ela entra em conflito com a número 4 aparecendo tanto a frase da 1 como a da 4, porém todas as outras funcionam perfeitamente, incluindo que se eu escolher a 4 nenhum erro ocorre.

Encontrei a solução de trabalhar com variáveis Char em vez de Real, mas queria entender o que causa este conflito

Uses Crt;

Const

    Sopa_Legumes = 2;
    Camarao = 8;
    Enchidos = 7;
    Pao_Alho = 3;
    Creme_Marisco = 4;
    Salada = 3;
    Pasteis_Bacalhau = 3.50;

    IceTea = 1.50;
    Coca_Cola = 1.50;
    Cerveja = 2;
    Agua = 1;
    Cha = 1.50;
    Vinho_Rose = 7;
    Whisky_Velho = 13;
    Nenhuma_Bebida = 0;

    Bitoque = 10;
    Carne_Alentejana = 15;
    Francesinha = 13;
    Peito_Frango = 10;

    Filete_Robalo = 13;
    Ameijoa = 11;
    Bacalhau_Espiritual = 12;
    Bacalhau_Natas = 12;

    Arroz_Doce = 3;
    Leite_Creme = 2.50;
    Bolo_Bolacha = 4;
    Doce_Casa = 3;
    Cafe = 1.20;
    Gelado = 1.30;
    Nenhuma_Sobremesa = 0;

    Pedidos = 0;

Var

    Cliente_1, Cliente_2, Cliente_3, Cliente_4, Cliente_5: String;
    Num_Pedidos: Integer;
    Registro_Conta_1, Registro_Conta_2, Registro_Conta_3, Registro_Conta_4, Registro_Conta_5: Real;
    Quer_Entrada_1, Quer_Entrada_2, Quer_Entrada_3, Quer_Entrada_4, Quer_Entrada_5, Quer_Sobremesa_1, Quer_Sobremesa_2, Quer_Sobremesa_3, Quer_Sobremesa_4, Quer_Sobremesa_5: Integer;
    Pedidos_Entrada, Pedidos_Sobremesa: Integer;
    Entrada_1, Entrada_2, Entrada_3, Entrada_4, Entrada_5: Real;
    Prato_Principal_1, Prato_Principal_2, Prato_Principal_3, Prato_Principal_4, Prato_Principal_5: Real;
    Sobremesa_1, Sobremesa_2, Sobremesa_3,Sobremesa_4, Sobremesa_5: Real;
    Bebida_1, Bebida_2, Bebida_3, Bebida_4, Bebida_5: Real;
    Avaliacao_1, Avaliacao_2, Avaliacao_3, Avaliacao_4, Avaliacao_5: Real;

    Begin

        WriteLn('Espero que tudo tenha estado do seu agrado :)');
                        WriteLn;
                        WriteLn('Iremos agora mostrar as sobremesas.');
                        WriteLn;
                        WriteLn('======================');
                        WriteLn('MENU DO RESTAURANTE');
                        WriteLn('======================');
                        WriteLn;
                        WriteLn('SOBREMESAS');
                        WriteLn;
                        WriteLn('(1) Arroz Doce- 3$');
                        WriteLn;
                        WriteLn('(2) Leite Creme- 2,50$');
                        WriteLn;
                        WriteLn('(3) Bolo de Bolacha- 4$');
                        WriteLn;
                        WriteLn('(4) Doce da Casa(Serradura)- 3$');
                        WriteLn;
                        WriteLn('(5) Café- 1,20$');
                        WriteLn;
                        WriteLn('(6) Gelado- 1.30$');
                        WriteLn;
                        WriteLn;
                        Write('Deseja uma sobremesa? (1=Y/2=N) ');
                        Read(Quer_Sobremesa_1);
                        WriteLn;
                        WriteLn;

                        If(Quer_Sobremesa_1 = 1)
                            Then
                                Begin

                                    Write('Que sobremesa deseja? ');
                                    Read(Sobremesa_1);

                                    If(Sobremesa_1 = 1)
                                        Then
                                            Begin
                                                Sobremesa_1 := Sobremesa_1 + Arroz_Doce;
                                                WriteLn;
                                                WriteLn('Iremos trazer agora o seu arroz doce então.');
                                            End;

                                    If(Sobremesa_1 = 2)
                                        Then
                                            Begin
                                                Sobremesa_1 := Sobremesa_1 + Leite_Creme;
                                                WriteLn;
                                                WriteLn('Iremos trazer agora o seu leite creme então.');
                                            End;

                                    If(Sobremesa_1 = 3)
                                        Then
                                            Begin
                                                Sobremesa_1 := Sobremesa_1 + Bolo_Bolacha;
                                                WriteLn;
                                                WriteLn('Iremos trazer agora o seu bolo de bolacha então.');
                                            End;

                                    If(Sobremesa_1 = 4)
                                        Then
                                            Begin
                                                Sobremesa_1 := Sobremesa_1 + Doce_Casa;
                                                WriteLn;
                                                WriteLn('Iremos trazer agora o doce da casa então.');
                                            End;

                                    If(Sobremesa_1 = 5)
                                        Then
                                            Begin
                                                Sobremesa_1 := Sobremesa_1 + Cafe;
                                                WriteLn;
                                                WriteLn('Iremos trazer agora o seu café então.');
                                            End;

                                    If(Sobremesa_1 = 6)
                                        Then
                                            Begin
                                                Sobremesa_1 := Sobremesa_1 + Gelado;
                                                WriteLn;
                                                WriteLn('Iremos trazer agora o seu gelado então.');
                                            End;

                                End;

    End.

 

BrunoJnr.

Link to comment
Share on other sites

Em 09/04/2024 às 10:30, BrunoJunior disse:

                                    If(Sobremesa_1 = 1)
                                        Then
                                            Begin
                                                Sobremesa_1 := Sobremesa_1 + Arroz_Doce;
                                                WriteLn;
                                                WriteLn('Iremos trazer agora o seu arroz doce então.');
                                            End;

 

Sobremesa_1 começa com valor 1, mas depois somas o valor do arroz doce logo Sobremesa_1 = 4. Como usas IF sem condição ELSE, quanto termina de processar o valor 1 vai entrar no if do valor 4 porque entretanto Sobremesa_1 passou a 4.

  • Vote 1
Link to comment
Share on other sites

  • Solution

O que respondeu o @iznougudpt está corretíssimo. É esse o problema deste código específico.

No entanto quero ir um pouco mais a fundo no caso, pois parece-me que há aí um problema de raciocínio que deve ser corrigido.

O que estás a fazer, e que causou o problema descrito, é a usar a mesma variável que serve para ler a opção, para acumular o preço. E pior, estás a somar o preço à opção, o que claro, vai dar um preço errado.
Obviamente estás a começar, e este tipo de problema todos por lá passámos. Mas é mesmo por isso que é importante corrigir já, antes que se instituam maus hábitos.

Os computadores atuais têm muitos recursos. A sério, mesmo muitos. No contexto de um programa deste tipo, os recursos de um computador atual são virtualmente infinitos.
E antigamente, quando os computadores eram infinitamente mais limitados, já aí a regra era não reaproveitar variáveis. Isto é importante, pelo que vou repetir: Nunca deves reaproveitar uma variável.

Quando crias uma variável, ela deve ter um, e um só objetivo. Se é para a opção do menu, é para a opção do menu. Se é para o preço, é para o preço. Não interessa para que é, mas a partir do momento que é para uma coisa, é só para essa coisa.
Cria quantas variáveis a tua imaginação ditar, o computador aguenta.

Neste caso concreto, se a variável sobremesa_1 fosse usada apenas para ler a opção, nunca terias problemas, independentemente de usar um else ou não.

Cria uma nova variável para o preço a pagar, inicializa-a a 0, e dentro do IF, somas o preço do arroz doce (ou do que for) a essa variável, e não à Sobremesa_1. 
Tens o problema resolvido.

 

---------------------
Bónus:
Corrigindo a situação das variáveis, o teu código vai funcionar, mas não é um código optimizado. Como eu dizia, os computadores têm recursos quasi-infinitos, mas o nosso código deve sempre procurar ser o mais optimizado possível.
Em vez de IFs, substitui por um CASE ... OF.

Ficaria algo como isto:

...
  
                                    case Sobremesa_1 of
                                      1: Begin
                                           Total := Total + Arroz_Doce;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o seu arroz doce então.');
                                         End;
									  2: Begin
                                           Total := Total + Leite_Creme;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o seu leite creme então.');
                                         End;
									  3: Begin
                                           Total := Total + Bolo_Bolacha;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o seu bolo de bolacha então.');
                                         End;
                                      4: Begin
                                           Total := Total + Doce_Casa;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o doce da casa então.');
                                         End;
                                      5: Begin
                                           Total := Total + Cafe;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o seu café então.');
                                         End;
                                      6: Begin
                                           Total := Total + Gelado;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o seu gelado então.');
                                         End;
                                      else begin
                                        WriteLn;
                                        WriteLn('Opção inválida.');
                                      end;  
                                    end;  

Neste código, além de esteticamente mais apelativo e organizado, o compilador não precisa percorrer todas as opções, avaliando a cada uma se a opção é correta ou não. Entra no case, vai à opção cerca, e faz o que tem a fazer. E ainda ficas com a possibilidade de alertar o utilizador caso a opção escolhida não seja nenhuma das propostas, algo que de contrário precisarias de IFs encadeados para fazer, o que deixaria o código ainda mais frágil.

  • Vote 1

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

Em 09/04/2024 às 16:24, nunopicado disse:

O que respondeu o @iznougudpt está corretíssimo. É esse o problema deste código específico.

No entanto quero ir um pouco mais a fundo no caso, pois parece-me que há aí um problema de raciocínio que deve ser corrigido.

O que estás a fazer, e que causou o problema descrito, é a usar a mesma variável que serve para ler a opção, para acumular o preço. E pior, estás a somar o preço à opção, o que claro, vai dar um preço errado.
Obviamente estás a começar, e este tipo de problema todos por lá passámos. Mas é mesmo por isso que é importante corrigir já, antes que se instituam maus hábitos.

Os computadores atuais têm muitos recursos. A sério, mesmo muitos. No contexto de um programa deste tipo, os recursos de um computador atual são virtualmente infinitos.
E antigamente, quando os computadores eram infinitamente mais limitados, já aí a regra era não reaproveitar variáveis. Isto é importante, pelo que vou repetir: Nunca deves reaproveitar uma variável.

Quando crias uma variável, ela deve ter um, e um só objetivo. Se é para a opção do menu, é para a opção do menu. Se é para o preço, é para o preço. Não interessa para que é, mas a partir do momento que é para uma coisa, é só para essa coisa.
Cria quantas variáveis a tua imaginação ditar, o computador aguenta.

Neste caso concreto, se a variável sobremesa_1 fosse usada apenas para ler a opção, nunca terias problemas, independentemente de usar um else ou não.

Cria uma nova variável para o preço a pagar, inicializa-a a 0, e dentro do IF, somas o preço do arroz doce (ou do que for) a essa variável, e não à Sobremesa_1. 
Tens o problema resolvido.

 

---------------------
Bónus:
Corrigindo a situação das variáveis, o teu código vai funcionar, mas não é um código optimizado. Como eu dizia, os computadores têm recursos quasi-infinitos, mas o nosso código deve sempre procurar ser o mais optimizado possível.
Em vez de IFs, substitui por um CASE ... OF.

Ficaria algo como isto:

...
  
                                    case Sobremesa_1 of
                                      1: Begin
                                           Total := Total + Arroz_Doce;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o seu arroz doce então.');
                                         End;
									  2: Begin
                                           Total := Total + Leite_Creme;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o seu leite creme então.');
                                         End;
									  3: Begin
                                           Total := Total + Bolo_Bolacha;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o seu bolo de bolacha então.');
                                         End;
                                      4: Begin
                                           Total := Total + Doce_Casa;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o doce da casa então.');
                                         End;
                                      5: Begin
                                           Total := Total + Cafe;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o seu café então.');
                                         End;
                                      6: Begin
                                           Total := Total + Gelado;
                                           WriteLn;
                                           WriteLn('Iremos trazer agora o seu gelado então.');
                                         End;
                                      else begin
                                        WriteLn;
                                        WriteLn('Opção inválida.');
                                      end;  
                                    end;  

Neste código, além de esteticamente mais apelativo e organizado, o compilador não precisa percorrer todas as opções, avaliando a cada uma se a opção é correta ou não. Entra no case, vai à opção cerca, e faz o que tem a fazer. E ainda ficas com a possibilidade de alertar o utilizador caso a opção escolhida não seja nenhuma das propostas, algo que de contrário precisarias de IFs encadeados para fazer, o que deixaria o código ainda mais frágil.

Eu lembro-me que em outras linguagens de programação usava uma função chamada break, para parar o programa caso por exemplo alguém escolhesse uma opção inválida, mas ainda não encontrei nada parecido aqui, se alguém souber se é possível fazer.

BrunoJnr.

Link to comment
Share on other sites

O Pascal dispõe de 4 comandos para controlo de fluxo não ortodoxo, Break, Continue, Exit e Halt. O Break sai de um ciclo, o Continue passa para a próxima iteração de um ciclo, o Exit sai da função atual e o Halt sai do programa.
Mas a sua disponibilidade depende de qual compilador estás a usar.

De qualquer forma, não recomendo que uses nenhum deles na fase atual em que te encontras, a julgar pelo código que mostraste. Qualquer delas é um pesadelo para debug, e é preciso ter alguma prática para não seres enganado pela sua presença, em caso de ocorrer algum erro que estejas à procura da causa.

Este tipo de programa (menu + seleção de opções) é um exercício muito usado no início exatamente porque te força a detetar os problemas que uma programação básica te trás neste cenário. Todos os problemas que te possam ocorrer para este tipo de programa resolves facilmente com recurso a ciclos e funções: Os ciclos para controlar o fluxo do programa de uma forma mais ortodoxa, e as funções para que possas criar um código 'menos pastoso', em que possas reutilizar código comum sem recurso ao copy/paste (regra de outro da boa programação: pensa 20 vezes antes de fazeres copy/paste de um código. Se estás a fazer copy/paste, há uma boa chance de estares a fazer algo mal).

Pensa no menu como se fosse um mordomo, a perguntar-te o que queres. Ele diz-te as opções e pergunta o que queres. Tu respondes. Mediante a tua resposta, ele vai perguntar oura coisa qualquer, num ciclo que só termina quando a tua opção escolhida for 'sair'.
Assim, se todas as perguntas forem feitas dentro de um loop (o REPEAT...UNTIL é muito bom para isto) e a cada resposta ele chama a função adequada, eventualmente até usando um outro loop para obrigar a que a resposta seja uma das possíveis, o menu funcionará corretamente.

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

  • 3 weeks later...

Ao já referido pelo @nunopicado acrescentaria o seguinte: será boa ideia planear o fluxo do programa em papel antes de o transcrever para código. Durante essa fase de planeamento, deve ser especificado o tipo de dados e o significado de cada variável (apenas e só um por cada variável).

O problema seria assim auto-evidente: não só Quer_Sobremesa_1 nunca seria do tipo de dados Integer ou Real (mas sim Boolean, para representar um valor dicotómico Sim/Não), como seria impossível reutilizar variáveis -- pois obrigaria a dar duas funções/significados a uma variável durante o planeamento referido.

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • 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.