compila, mas algo não está certo. [RESOLVIDO]

1. compila, mas algo não está certo. [RESOLVIDO]

daniel s. filho
westbill

(usa Fedora)

Enviado em 07/05/2015 - 19:44h

Olá.
Estou iniciando no linux com o fedora, curso primeiro ano em ciência da computação e estou tendo problemas para executar simples programinhas.
É simples, o usuário entra com o código de compra e a partir deste há um desconto.
Mando repetir três vezes, mas na segunda vez na repetição não retorna a opção para entrar com o código de compras.
Será que é algum problema com meu compilador ou algo assim?

Segue o código a baixo:

#include <stdio.h>

int main()
{
char cod;
int contador;
float valor, valor_desconto;
for (contador=1; contador<=3; contador = contador + 1)
{
printf("Digite o codigo do pagamento: \n");
fflush(stdin);
scanf("%c", &cod);
printf("Digite o valor da compra: \n");
scanf("%f", &valor);
if( cod=='A' || cod=='a')
{
valor_desconto = valor - (valor * 0.5);
printf(" codigo valor valor com desconto\n");
printf(" %c %.2f %.2f\n\n\n", cod, valor, valor_desconto);
}
else
{
if(cod=='B' || cod=='b')
{
valor_desconto = valor - (valor * 0.3);
printf(" codigo valor valor com desconto\n");
printf(" %c %.2f %.2f\n\n\n", cod, valor, valor_desconto);
}
else
{
valor_desconto = valor - (valor * 0.1);
printf(" codigo valor valor com desconto\n");
printf(" %c %.2f %.2f\n\n\n", cod, valor, valor_desconto);
}
}
}
}


  


2. MELHOR RESPOSTA

Thiago Henrique Hüpner
Thihup

(usa Manjaro Linux)

Enviado em 07/05/2015 - 21:42h

Amigo, o que acontece é "sujeira de buffer".

Procure a respeito, mas em suma, seria uma "sujeirinha" (geralmente é um '\n', mas pode ser outra coisa) e quando chega a hora de pedir novamente ele pega o valor que tem no "buffer" e coloca na variavel.

O que fazer?

Procure métodos mais eficientes, mas esse é apenas um quebra-galho : colocar um getchar()

Segue código indentado e "corrigido":


#include <stdio.h>

int main() {
char cod;
int contador;
float valor, valor_desconto;
for (contador=1; contador<=3; contador = contador + 1) {
printf("Digite o codigo do pagamento: \n");
fflush(stdin);
scanf("%c", &cod);
printf("Digite o valor da compra: \n");
scanf("%f", &valor);
if( cod=='A' || cod=='a') {
valor_desconto = valor - (valor * 0.5);
printf(" codigo valor valor com desconto\n");
printf(" %c %.2f %.2f\n\n\n", cod, valor, valor_desconto);
} else {
if(cod=='B' || cod=='b') {
valor_desconto = valor - (valor * 0.3);
printf(" codigo valor valor com desconto\n");
printf(" %c %.2f %.2f\n\n\n", cod, valor, valor_desconto);
} else {
valor_desconto = valor - (valor * 0.1);
printf(" codigo valor valor com desconto\n");
printf(" %c %.2f %.2f\n\n\n", cod, valor, valor_desconto);
}
}

getchar();
}
return 0;
}



Espero ter ajudado

Se ajudei, marque o tópico como resolvido e clique em melhor resposta!

[]'s

T+

NOTA: Coloque o código entre as tags [code] e [/code], ficando algo assim:

[code]"aqui vai o código"[/code]

3. Obrigado pela ajuda e dica.

daniel s. filho
westbill

(usa Fedora)

Enviado em 08/05/2015 - 12:49h

Thiago muito obrigado, funcionou perfeitamente.
Antes de tentar o fórum perguntei a minha professora, por e-mail e a resposta foi simplesmente que funcionava.
Estou no primeiro ano de Ciência da computação, nunca programei e estou começando a usar linux, você tem alguma dica de livro para que eu possa aprender esses macetes?
Obrigado novamente.




4. Re: compila, mas algo não está certo. [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 08/05/2015 - 16:07h

Não é bem macete. A questão é que scanf() é uma função complexa mesmo -- das mais complexas das funções padronizadas junto com a linguagem C. É uma infelicidade quando se trata de ser apresentada -- e mal apresentada -- logo num curso introdutório.

O que você precisa saber sobre entrada e saída é que as funções padronizadas do C tratam entrada e saída de dados como um fluxo contínuo de caracteres, que podem ser letras, algarismos, sinais de pontuação, espaços em branco (incluindo um caráter que representa o fim da linha) ou até mesmo caracteres de controle.

No caso das funções de entrada, elas consomem bytes do fluxo até satisfazerem algum critério, e deixam intocado tudo aquilo que não consumirem. Existem funções para leitura caráter a caráter, como getchar() e fgetc(), funções para leitura de blocos de dados, como fread(), funções para leitura de texto, como fgets(), e funções que tentam extrair informações a partir de um determinados formatos de dados esperados na entrada, como scanf().

scanf é uma abreviação de scan formatted (data), ou seja: procure (dados) formatados. Durante a procura, ela pode (mas não necessariamente tem de) converter parte dos dados lidos e atribuir o resultado a uma ou mais variáveis. O comportamento da função depende da especificação de formato que é passada como parâmetro à função. Por exemplo, eu posso usar o seguinte código para ver se o usuário digitou exatamente o texto "Paulo" seguido do fim de linha, sem ter de guardar esses seis caracteres em lugar nenhum do programa.

int consumed_chars=0;
if(scanf("Paulo%*1[\n]%n", &consumed_chars)==0 && consumed_chars==6){
/* Os próximos 6 caracteres correspondem exatamente a "Paulo\n". */
}


A explicação é a seguinte:

1) A função scanf() começa a executar pegando o primeiro caráter da entrada e comparando-o com 'P'. Se for igual, prossegue; se não, devolve o caráter lido para o fluxo de entrada, para que possa ser aproveitado pela próxima operação de leitura, e encerra a execução função, já que foi encontrada uma não correspondência entre a entrada e a string de formatação.

2) Pega o próximo caráter da entrada e compara-o com 'a'. Se for igual, prossegue; se não, devolve o caráter lido para o fluxo de entrada, para que possa ser aproveitado pela próxima operação de leitura (mas o caráter 'P' que já tinha sido consumido será perdido), e encerra a execução função, já que foi encontrada uma não-correspondência entre a entrada e a string de formatação.

3) Pega o próximo caráter da entrada e compara-o com 'u'. Se for igual, prossegue; se não, devolve o caráter lido para o fluxo de entrada, para que possa ser aproveitado pela próxima operação de leitura (mas os caracteres que já tinham sido consumidos serão perdidos), e encerra a execução função, já que foi encontrada uma não-correspondência entre a entrada e a string de formatação.

4) Pega o próximo caráter da entrada e compara-o com 'l'. Se for igual, prossegue; se não, devolve o caráter lido para o fluxo de entrada, para que possa ser aproveitado pela próxima operação de leitura (mas os caracteres que já tinham sido consumidos serão perdidos), e encerra a execução função, já que foi encontrada uma não-correspondência entre a entrada e a string de formatação.

5) Pega o próximo caráter da entrada e compara-o com 'o'. Se for igual, prossegue; se não, devolve o caráter lido para o fluxo de entrada, para que possa ser aproveitado pela próxima operação de leitura (mas os caracteres que já tinham sido consumidos serão perdidos), e encerra a execução função, já que foi encontrada uma não-correspondência entre a entrada e a string de formatação.

6) Não dá para fazer o mesmo com o caráter '\n' (marca de fim de linha) porque espaços em branco na string de formatação de scanf() significa "consuma uma quantidade qualquer (0 ou mais) de espaços em branco". Então eu uso a conversão %[], que serve para ler strings formadas pelos caracteres entre colchetes, colocando o '\n' entre os colchetes, mas limitando a largura máxima em 1 ('1'), e mandando suprimir a atribuição dos caracteres lidos durante essa operação ('*'). O efeito final é pegar o próximo caráter da entrada e compará-lo com '\n'. Se foi igual, consome-o; se não, devolve o caráter lido para o fluxo de entrada, para que possa ser aproveitado pela próxima operação de leitura (mas os caracteres que já tinham sido consumidos serão perdidos), e encerra a execução função, já que foi encontrada uma não-correspondência entre a entrada e a string de formatação.

7) A indicação "%n" faz com que o número de caracteres consumidos pela função até o momento seja armazenado no endereço indicado no próximo argumento da função (&consumed_chars). É a maneira que eu uso para saber se a string lida no passo 6 teve tamanho zero ou um.

8) Ao encontrar o fim da string de formatação, a função scanf() necessariamente retorna.

9) Quando scanf() retorna o valor retornado por ela pode ser EOF (que geralmente vale -1) ou o número de conversões com atribuição não-suprimida realizadas. No nosso caso, esse número tem de ser zero, pois só há uma conversão ("%[]"), mas a atribuição de valores a ela correspondentes foi suprimida, e "%n", apesar de fazer uma atribuição de valor, não é considerada uma conversão. Se o valor retornado não for zero, certamente ele será EOF, indicando a ocorrência de um erro de leitura.

10) O valor de consumed_chars terá sido modificado para 6 se os caracteres "Paulo\n" tiverem sido lidos. Qualquer outro valor indica que scanf() consumiu menos bytes do que o esperado, podendo ser por não ter encontrado uma das cinco letras na ordem esperada (qualquer valor menor do que 5), ou por ter faltado a marca de fim de linha o final da leitura (valor 5).


scanf() e suas irmãs são funções muito poderosas, mas também muito complexas. Eu recomendo a você ler com bastante cuidado a documentação dela. A manpage de scanf() no Linux é muito detalhada, e eu a recomendo como fonte de referência (com uma ressalva: existem algumas funcionalidades além do que prescreve o padrão do C; se você estiver usando outra plataforma, que não Linux com glibc, deve se abster de usar essas extensões).


5. Re: compila, mas algo não está certo. [RESOLVIDO]

daniel s. filho
westbill

(usa Fedora)

Enviado em 10/05/2015 - 19:05h

Obrigado pelo esclarecimento Paulo, essas informações foram muito úteis para mim






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts