Programa nao salva valores no vetor [RESOLVIDO]

1. Programa nao salva valores no vetor [RESOLVIDO]

Alef Duarte
alef_duarte

(usa Debian)

Enviado em 01/05/2016 - 20:37h

Tenho um programa de ED, e temos que criar um programa que gerencie um cinema. Terminei meu código, está rodando, porém nao importa quantos valores eu insira em meu vetor, quando mando verificar ele sempre está vazio, nao estou conseguindo encontrar a lógica
a biblioteca está assim
typedef struct{
char filme[40];
float valor;
int ingresso;
int sala;
int codigo;
}cinema;

typedef struct{
int primeiro, ultimo;
cinema lugares[250];
}salas;

salas criarsala(){
salas aux;
aux.primeiro = 0;
aux.ultimo = -1;

return aux;
}

void menu(){
printf("\t\t+------------------------------------------------------------------------------+\n");
printf("\t\t|\tEscolha a opção desejada. |\n");
printf("\t\t|\t1. Comprar Ingresso. |\n");
printf("\t\t|\t2. Devolver Ingresso. |\n");
printf("\t\t|\t3. Imprimir todos os ingressos de uma determinada sala. |\n");
printf("\t\t|\t4. Calcular valor total de uma determinada sala. |\n");
printf("\t\t|\t5. Calcular total de lugares ocupados em uma sala; |\n");
printf("\t\t|\t6. Criar um backup da venda do dia ordenando ingressos por sala. |\n");
printf("\t\t|\t7. Calcular total de ingressos tipo meia. |\n");
printf("\t\t|\t8. Fechamento do dia: Limpas vendar e retornar valor total recebido. |\n");
printf("\t\t+------------------------------------------------------------------------------+\n");
printf("\t\t\tOpção: ");
}

// inserir item //


int verificarDisponibilidade(salas aux, int sala){
int i, lugar=0;
for (i=aux.primeiro; i<=aux.ultimo; i++){
if(aux.lugares[i].sala==sala)
lugar++;
}
return lugar;
}

salas inserirCliente(salas aux, int sala){
aux.ultimo++;
aux.lugares[aux.ultimo].sala=sala;
setbuf(stdin, NULL);
printf("\nInsira o nome do filme\n");
scanf("%[^\n]s", &aux.lugares[aux.ultimo].filme);
setbuf(stdin, NULL);
printf("\nInsira o valor do ingresso: R$ ");
scanf("%f", &aux.lugares[aux.ultimo].valor);
printf("\nInsira o tipo do ingresso\n 1. Inteira 2. Meia: ");
scanf("%d", &aux.lugares[aux.ultimo].ingresso);
printf("Insira ou crie o codigo do ingresso: ");
scanf("%d", &aux.lugares[aux.ultimo].codigo);

return aux;
}

int pesquisarItem(salas aux, cinema numero){
int posicao = -1;
int i=0;
for(i= aux.primeiro; i<=aux.ultimo; i++){
if(numero.codigo == aux.lugares[i].codigo){
posicao=i;
}
}

return posicao;
}

salas retirar(salas aux, cinema codigo){
int retorno = pesquisarItem(aux, codigo);
if(retorno == -1){
printf("Ingresso não encontrado! Impossível devolver");
}
else{
int i;
aux.ultimo--;
for(i=retorno; i <= aux.ultimo; i++){
aux.lugares[i] = aux.lugares[i+1];

}
}
return aux;
}

void imprimirSala(salas aux, int sala){
int i, vazio=0;
for(i=aux.primeiro; i<=aux.ultimo; i++){
if(aux.lugares[i].sala==sala){
vazio++;
printf("\nFilme %s", aux.lugares[i].filme);
printf("\nSala %d", aux.lugares[i].sala);
printf("\nValor R$ %.2f", aux.lugares[i].valor);
if(aux.lugares[i].ingresso==1)
printf("Entrada tipo Inteira.");
else
printf("Entrada tipo Meia.");

}
}
if (vazio==0){
printf("Sala Vazia");
}
}

void valorTotal(salas aux, int sala){
int i;
float valortotal=0;
for(i=aux.primeiro; i<aux.ultimo; i++){
if(aux.lugares[i].sala==sala){
valortotal+=aux.lugares[i].valor;
}
}
if (valortotal==0){
printf("Sala Vazia");
}
else
printf ("Valor total é R$: %.2f", valortotal);
}
void totalDeLugares(salas aux, int sala){
int i, repeticao=0;
for(i=aux.primeiro; i<=aux.ultimo; i++){
if(aux.lugares[i].sala==sala){
repeticao++;
}
}
if(repeticao==0)
printf("A sala está vazia");

else
printf("Existem %d lugares na sala", repeticao);
}

salas backup(salas aux){
salas backup;
int sala=1, i, cont=0;
do{
for(i=aux.primeiro; i<aux.ultimo; i++)
if(aux.lugares[i].sala==sala){
backup.lugares[cont]=aux.lugares[i];
cont++;
}
sala++;
}while(sala<=5);
return backup;
}

void imprimirTudo(salas backup){
int i, vazio=0;
for(i=backup.primeiro; i<backup.ultimo; i++){
if(backup.lugares[i].sala==2 || backup.lugares[i].sala==2 || backup.lugares[i].sala==3 ||
backup.lugares[i].sala==4 || backup.lugares[i].sala==5){
vazio++;
printf("\nFilme %s", backup.lugares[i].filme);
printf("\nSala %d", backup.lugares[i].sala);
printf("\nValor R$ %f", backup.lugares[i].valor);
if(backup.lugares[i].ingresso==1)
printf("Entrada tipo Inteira.");
else
printf("Entrada tipo Meia.");
}
}
if (vazio==0){
printf("Backup Vazio");
}
}

void totalMeia(salas aux){
int i, vazio=0;
float valortotal=0;
for(i=aux.primeiro; i<aux.ultimo; i++){
if(aux.lugares[i].ingresso==2){
vazio++;
valortotal+=aux.lugares[i].valor;
}
}
if (vazio==0){
printf("Nenhuma venda do tipo meia até o momento");
}
else
printf ("Valor total de ingressos tipo meia é R$: %f", valortotal);
}

salas fechamentoDoDia(salas aux){
int i;
float valortotal=0;
for(i=aux.primeiro; i<aux.ultimo; i++){
valortotal+=aux.lugares[i].valor;
}
aux.ultimo=-1;
aux.primeiro=0;

if (valortotal==0){
printf("Nenhum ingresso vendido.");
}
else
printf ("Valor total de ingressos é R$: %f", valortotal);
return aux;
}

e o main está desta forma
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include "biblioteca.h"
/*
*
*/
int main() {
setlocale(LC_ALL, "Portuguese");
salas aux;
int op, exit, sala;
do{
// MENU //

menu();
scanf("%d", &op);

if (op==1){
printf("Insira o número da sala: ");
scanf("%d", &sala);
if (verificarDisponibilidade(aux, sala)<50){
inserirCliente(aux, sala);
}
else{
printf("\nNão há mais espaços na sala!");
}
} // fim da primeira opção

else if(op==2){
printf("\nInsira o codigo do filme que deseja devolver: ");
scanf("%d", &codigo.codigo);
retirar(aux, codigo);

} // fim da segunda opçao

else if(op==3){
printf("\nInsira o número da sala: ");
scanf("%d", &sala);
imprimirSala(aux, sala);
} // fim da terceira opção

else if(op==4){
printf("\nInsira o número da sala: ");
scanf("%d", &sala);
valorTotal(aux, sala);
} // fim da quarta opção //

else if(op==5){
printf("\nInsira o número da sala: ");
scanf("%d", &sala);
totalDeLugares(aux, sala);
} // fim da quinta opção //

else if(op==6){
backup(aux);
printf("Backup criado, deseja vê-lo agora?\n1. Sim 2.Nao ");
scanf("%d", &exit);
if(exit==1){
imprimirTudo(backup(aux));
}
} // fim da sexta opção //

else if(op==7){
totalMeia(aux);
} // fim da sétima opção //

else if(op==8){
fechamentoDoDia(aux);
} // fim da oitava opção //

else
printf("Opção Inválida!");

printf("\n\nDeseja fazer outra operação?\n1. Sim 2. Não ");
scanf("%d", &exit);

}while(exit==1);
return 0;
}



  


2. Re: Programa nao salva valores no vetor

Paulo
paulo1205

(usa Ubuntu)

Enviado em 02/05/2016 - 04:34h

Você deve lembrar que os argumentos de funções em C são sempre passados por valor. Em outras palavras, as funções recebem apenas uma cópia do valor correspondente a cada argumento que você passa como parâmetro. Do mesmo modo, o valor retornado por uma função é também uma cópia do valor que você passa ao comando return.

Eu vi que várias das suas funções recebem e devolvem dados do tipo salas. Você poderia, então, corrigir o problema de os dados originais não serem modificados atribuindo o valor de retorno ao dado do tipo salas. Ou seja: você trocaria o primeiro dos códigos abaixo pelo segundo, por exemplo.

// Seu código original
inserirCliente(aux, sala);


// Código alternativo
aux=inserirCliente(aux, sala);


(Uma pausa para um comentário: é impressão minha, ou a principal variável do seu programa, em torno da qual tudo acontece, tem o singelo nome de “aux”? Por que não usar um nome mais significativo?)


Isso pode resolver, mas certamente não é o que você quer. Na sua estrutura você tem um array de 250 elementos que, por sua vez, tem campos com mais de 40 bytes. Eu garanto que você não vai querer ficar gastando CPU com cópias de mais de 10kB na ida e mais outros mais de 10kB no retorno. Você quer, portanto, usar passagem por referência.

Como C só possui passagem de dados por valor (de novo: a função recebe apenas uma cópia do valor original do argumento), a forma de passar uma referência para um determinado objeto é obter o endereço do objeto, e passar esse endereço como argumento para a função. A função, por sua vez, é construída para receber um ponteiro para o dado (i.e. seu endereço), em vez de receber (uma cópia) do seu valor.

Para fazer isso no se programa, você tem de transformar as funções, a fim de fazer com que elas recebam ponteiros, e também modificar o modo de chamar as funções, para passar a elas a referência aos objetos.

Usando novamente a função inserirCliente() como exemplo, eis como você poderia modificar a implementação da função (note que, de quebra, eu corrijo alguns erros que você cometeu na hora de fazer a leitura dos dados, e mostro uma forma mais segura de usar scanf() e de evitar deixar caracteres indesejados no buffer de entrada, que poderiam prejudicar operações de leitura posteriores, sem recorrer a “truques sujos” -- e errôneos -- como chamar setbuf() (o que, por sinal, é uma violação do padrão)).

/*
Note o tipo de retorno “int”. Eu o uso para indicar possíveis
erros de leitura (valor de retorno “EOF”). Se você não tiver inte-
resse em indicar tais erros, pode talvez optar por “void”.

Eu, no entanto, recomendo sempre sinalizar erros, pois bons pro-
gramas devem ser capazes de perceber e tratar situações inespe-
radas que ocorram durante a execução (especialmente num caso
como este, em que você está tratando com dados digitados manual-
mente por um usuário). Ainda que, no fim das contas, o tratamento
mais adequado seja abortar o programa, isso ainda é melhor que
ignorar erros e deixar o programa executar um fluxo indeterminado.
*/
int inserirCliente(salas *p_aux, int sala){
cinema novo_dado;
int n, a, b, c;

novo_dado.sala=sala;

// Lê nome do filme.
while(1){
a=b=0;
printf("\nInsira o nome do filme\n");
/*
O espaço no começo da string de formatação faz com que qualquer
marca de fim de linha presente no buffer seja descartada (e também
impede que o nome do filme seja vazio ou que comece com espaços).

O limite de 39 caracteres é para garantir que o nome do filme não
exceda o espaço reservado de 40 bytes (39 úteis mais 1 byte nulo).

Os medidores de caracteres lidos e a leitura suprimida da marca de
fim de linha são usados para ver se o usuário apertou mesmo <Enter>
ou se a leitura foi interrompida porque foram digitados caracteres demais.
*/
n=scanf(" %39[^\n]%n%*1[\n]%n", novo_dado.filme, &a, &b);
// n conta quantos valores foram lidos. Deve ser igual a 1.
if(n<1)
return EOF; // Erro de leitura.

// a e b são usados para saber se o '\n' veio até a 40ª posição (se não
// tiver vindo, b será igual a a, porque a leitura do '\n' vai consumir zero
// caracteres).
if(a>0 && b>a)
break; // Leitura bem sucedida. Sai do loop.

fprintf(
stderr,
"\nO nome digitado é muito longo.\n"
"Use no máximo 39 caracteres e tecle <Enter>.\n"
);

// Limpa o buffer (descarta caracteres até encontrar um '\n' ou erro).
if(scanf("%*[^\n]%*1[\n]")==EOF)
return EOF; // Erro de leitura.

// Volta ao início do loop para tentar ler o nome de novo.
}

while(1){
a=b=c=0;
printf("\nInsira o valor do ingresso: R$ ");
n=scanf("%f%n%*[^\n]%n%*1[\n]%n", &novo_dado.valor, &a, &b, &c);
if(n<1)
return EOF; // Erro de leitura.

if(a>0 && b==a && c>b)
break; // Leitura bem sucedida. Sai do loop.

fprintf(
stderr,
"\nCaracteres espúrios na entrada.\n"
"Digite um número decimal e tecle <Enter>.\n"
);

// Limpa o buffer (descarta caracteres até encontrar um '\n' ou erro).
if(scanf("%*[^\n]%*1[\n]")==EOF)
return EOF; // Erro de leitura.

// Volta ao início do loop para tentar ler o valor de novo.
}

while(1){
a=b=c=0;
printf("\nInsira o tipo do ingresso\n 1. Inteira 2. Meia: ");
n=scanf("%d%n%*[^\n]%n%*1[\n]%n", &novo_dado.ingresso, &a, &b, &c);
if(n<1)
return EOF; // Erro de leitura.

if(a>0 && b==a && c>b)
break; // Leitura bem sucedida. Sai do loop.

fprintf(
stderr,
"\nCaracteres espúrios na entrada.\n"
"Digite um número decimal e tecle <Enter>.\n"
);

// Limpa o buffer (descarta caracteres até encontrar um '\n' ou erro).
if(scanf("%*[^\n]%*1[\n]")==EOF)
return EOF; // Erro de leitura.

// Volta ao início do loop para tentar ler o valor de novo.
}

while(1){
a=b=c=0;
printf("Insira ou crie o codigo do ingresso: ");
n=scanf("%d%n%*[^\n]%n%*1[\n]%n", &novo_dado.codigo, &a, &b, &c);
if(n<1)
return EOF; // Erro de leitura.

if(a>0 && b==a && c>b)
break; // Leitura bem sucedida. Sai do loop.

fprintf(
stderr,
"\nCaracteres espúrios na entrada.\n"
"Digite um número decimal e tecle <Enter>.\n"
);

// Limpa o buffer (descarta caracteres até encontrar um '\n' ou erro).
if(scanf("%*[^\n]%*1[\n]")==EOF)
return EOF; // Erro de leitura.

// Volta ao início do loop para tentar ler o valor de novo.
}

// Só chega até aqui se todas as leituras foram bem sucedidas.

// Copia o novo dado para o fim da lista de registros.
p_aux->lugares[++p_aux->ultimo]=novo_dado;

// Sai indicando sucesso.
return 1;
}


E eis como chamar a função lá no bloco de main().

// Note o uso de “&”, para obter o endereço e copiar tal endereço
// para a função. Note também o teste do valor retornado.
if(inserirCliente(&aux, sala)==EOF){
// Dá algum tratamento dado em caso de erro de leitura.
}



3. Re: Programa nao salva valores no vetor [RESOLVIDO]

Alef Duarte
alef_duarte

(usa Debian)

Enviado em 02/05/2016 - 05:44h

Muito obrigado paulo1205, Ainda não cheguei a estudar ponteiros, por isso nenhum das minhas funções tem ponteiros. Você usou um printf bem diferente do que eu tenho costume. Vou analisá-lo direitinho e com isso já aprendi muito mais. Obrigado pelos comentários e por reestruturar o código. Vai me ajudar bastante.


4. Re: Programa nao salva valores no vetor [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 02/05/2016 - 13:05h

ATENÇÃO: Havia um erro no código acima, que eu acabei de corrigir (a leitura do nome não estava sendo feita para novo_dado, mas sim para uma posição errada no vetor de salas)..

Você disse que nunca usou printf() do jeito como eu mostrei. Você não quis dizer scanf()? Ocorre que scanf() é uma das funções mais complexas da biblioteca padrão do C. É uma infelicidade que os cursos introdutórios saiam logo de cara jogando-a em cima dos alunos, sem tomar o mínimo cuidado para explicar direito como ela funciona. Eu recomendo fortemente que você leia uma documentação decente da função (a que vem com o Linux é muito boa, por sinal; se você não usar Linux, pode ver na web em vários sites, como, por exemplo, em http://linux.die.net/man/3/scanf).

O código que eu postei acima acabou ficando muito mais extenso em função dos cuidados com a entrada de dados, inclusive com código repetido executando operações semelhantes. Tais operações semelhantes poderiam ser agrupadas em funções, que depois poderiam ser chamadas de modo mais simples. Por exemplo:

#Include <stdbool.h>

/*
Função para ler um valor inteiro, exigindo que ele seja a única coisa presente
na linha digitada (i.e. o usuário deve digitar apenas o número e apertar <Enter>).
Se houver outros caracteres, tudo o que se tiver digitado será desprezado.

O primeiro parâmetro é um ponteiro para a string com a mensagem a ser exibida
antes da digitação do valor. O valor digitado é armazenado no endereço indicado
no segundo parâmetro. O terceiro é um booleano que indica se a leitura deve
ser repetida em caso de valor digitado inválido.

O valor retornado será falso em caso de erro, e verdadeiro se a leitura for bem
sucedida.
*/
bool le_int(const char *prompt, int *var, bool retentar){
int valor;
int n, a, b, c, d;
do {
if(prompt!=NULL){
printf("%s", prompt);
fflush(stdout);
}
a=b=c=d=0;
n=scanf(" %n%d%n%*[^\n]%n%*1[\n]%n", &a, &valor, &b, &c, &d);
// a para ver se houve espaços antes do número, b para ver onde acabou
// o número, c para ver se há lixo antes do '\n', e d para garantir que houve
// o '\n'. Tudo depende também de n ser igual a 1 (uma variável lida com
// sucesso).
if(n==EOF)
return false; // Erro de leitura. Não dá nem para tentar de novo.

if(n==1 && a==0 && b>a && c==b && d>c){
// Leitura bem sucedida.
if(var!=NULL)
*var=valor; // Permite ser rígido com a leitura, mas descarta valor se var==NULL.
return true;
}

fprintf(stderr, "ERRO: Valor digitado contém caracteres inválidos.\n\n");

// Limpa o buffer (e aborta em caso de erro).
if(scanf("%*[^\n]%*1[\n]")==EOF)
return false;
} while(retentar);

// Se chegou aqui, é porque o formato é inválido e não se deve retentar.
return false;
}

/*
Idem, mas para números de ponto flutuante (com float).
*/
bool le_float(const char *prompt, float *var, bool retentar){
float valor;
int n, a, b, c, d;
do {
if(prompt!=NULL){
printf("%s", prompt);
fflush(stdout);
}
a=b=c=d=0;
n=scanf(" %n%f%n%*[^\n]%n%*1[\n]%n", &a, &valor, &b, &c, &d);
if(n==EOF)
return false;
if(n==1 && a==0 && b>a && c==b && d>c){
if(var!=NULL)
*var=valor;
return true;
}
fprintf(stderr, "ERRO: Valor digitado contém caracteres inválidos.\n\n");
if(scanf("%*[^\n]%*1[\n]")==EOF)
return false;
} while(retentar);
return false;
}

/*
Lê linha de texto, limitada a um tamanho máximo, e descartando o '\n'. A linha
pode ser vazia (se houver '\n' sobrando no buffer de entrada, eles têm de ser
removidos antes desta função; as funções de leitura acima garantem que não
haverá).

Strings em geral têm forma mais ou menos livre (há usos válidos para strings
vazias, ou começando com espaços, ou contendo apenas espaços), então a
única condição que faz esta função retentar a leitura é se o tamanho lido ex-
ceder o máximo.

O tamanho da linha inclui espaço para o byte nulo que termina a string.

Ao contrário das funções acima, esta não lê para uma variável local antes de
copiar o valor para o ponteiro. Logo, o ponteiro para os caracteres da linha
tem de ser válido, e tem de ter realmente o tamanho informado (ou mais).
*/
bool le_linha(const char *prompt, char *linha, size_t tam_linha, bool retentar){
if(linha==NULL){
errno=EINVAL;
return false;
}
if(tam_linha<1){
errno=ERANGE;
return false;
}
do {
size_t tam_lido;
if(prompt!=NULL){
printf("%s", prompt);
fflush(stdout);
}
if(fgets(linha, tam_linha, stdin)==NULL)
return false;
tam_lido=strlen(linha);
// Vê se o '\n' foi lido para dentro da linha. Se sim, remove-o.
if(linha[tam_lido-1]=='\n')
linha[--tam_lido]='\0';
if(tam_lido<tam_linha-1){
return true;
}
else {
// Linha com tamanho máximo e não tinha o '\n'. Tudo bem
// se o próximo caráter for '\n'. Se não for, então o tamanho
// máximo certamente foi excedido.
int prox_char;
prox_char=fgetc(stdin);
if(prox_char=='\n' || prox_char==EOF)
return true;
}
fprintf(stderr, "ERRO: Linha digitada excede tamanho máximo (%d caracteres).\n\n", tam_linha-1);
if(scanf("%*[^\n]%*1[\n]")==EOF)
return false;
} while(retentar);
return false;
}

/* ... */

/*
Nova versão de inserirCliente, usando as funções de leitura acima.
Retorna true se a leitura de todos os campos for bem sucedida, e
false em caso de erro.
*/
bool inserirCliente(salas *p_aux, int sala){
cinema novo_dado;
novo_dado.sala=sala;
if(
le_linha("Digite o nome do filme: ", novo_dado.filme, sizeof novo_dado.filme, true) &&
le_float("Digite o valor do ingresso: ", &novo_dado.valor, true) &&
le_int("Digite o tipo do ingresso (1: Inteira, 2: Meia): ", &novo_dado.ingresso, true) &&
le_int("Digite o código do ingresso: ", &novo_dado.codigo, true)
){
p_aux->lugares[++p_aux->ultimo]=novo_dado;
return true;
}
return false;
}



5. Re: Programa nao salva valores no vetor [RESOLVIDO]

Alef Duarte
alef_duarte

(usa Debian)

Enviado em 03/05/2016 - 15:17h

Ficou bem maior o código. Era o scanf() mesmo, vou dar uma lida sobre ele, não sabia que era tao complexo. E assim que aprender ponteiros vou reanalisar o seu código para entender melhor.
e mais um vez.
Muito obrigado






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts