Jump to content
Earendil010102

Lista de livros

Recommended Posts

Earendil010102

Estou criando uma lista de cadastro de livros. Quado digito a opção 2 ele deve dizer que não ha nada cadastrado, caso não tenha cadastrado nenhum livro. Mas quando digito 1 não retorna para opção 1. O que estou fazendo de errado?

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct inform {
	int cod;
	char autor[30], obra[30], editora[10];
};
void menu () {
	printf("\n-----------MENU----------------");
	printf("\nDigite uma opção:");
	printf("\n1 - Inserir um novo cadastro");
	printf("\n2 - Mostrar todos os cadastros");
	printf("\n0 - Encerrar");
	printf("\n-----------MENU----------------");
}
int main(int argc, char *argv[]) {
	setlocale (LC_ALL, "Portuguese");
	//---------------variaveis
	struct inform livro[5];
	int opc, i, cont, valor;
	valor = 0;	
	char resp;						//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,
	//inicialização
	menu();
	printf("\n\n");
	scanf("%d", &opc);
	fflush(stdin);
	system("pause");
	system("cls");
	i = 0;
	cont = 0;
	switch (opc) {
		case 1 :  
		//inicio opcao 1
		valor = 1;
		do {
			printf("\nDigite o nome do livro: ");
			gets(livro[i].obra);
			fflush(stdin);
			printf("\nDigite o nome do autor: ");
			gets(livro[i].autor);
			fflush(stdin);
			printf("\nDigite o nome da editora: ");
			gets(livro[i].editora);
			fflush(stdin);
			livro[i].cod = i+1;
			menu();
			scanf("%d", &opc);
			fflush(stdin);
			i++;
			cont++;
	} while (opc == 1 && i<5);
		if (i == 5) { //inicio do primeiro if
			system("cls");
			printf("\n\nSistem de cadstro lotado. Não é possivel armazenar mais informações\n");
			printf("Digite outra opção.\n\n");
			menu();
			scanf("%d", &opc);
			system("pause");
			system("cls");
		}  //fim do primeiro if
	 //fim da opcao 1 
	 
	 case 2 : 
	 //inicio opcao 2
				while (valor == 0) {
					printf("\nLista vazia"); 
					printf("\nDigite outra opcao\n\n");	
					menu();
					scanf("%d", &opc);
				}
					for (i=0; i<cont; i++) { // impressao
						printf("\n autor: %s", livro[i].autor);
						printf("\n obra: %s", livro[i].obra);
						printf("\n editora: %s", livro[i].editora);
						printf("\n código: %d\n\n", livro[i].cod);
					}						//impressao
				
			 //fim pocao 2
			 break;
			 case 0 : 
			 //inicio opcao 0
			 system("cls");
				printf("\nSAINDO...\n\n");
			//fim opcao 0
			break;
			default :
				printf("\nNumero invalido");
				printf("\nDigite outro valor");
				menu();
			scanf("%d", &opc);
				
	}		
	return 0;
}

 

Share this post


Link to post
Share on other sites
pwseo

@Earendil010102,

Pela tua descrição, não é completamente claro o problema que estás a ter. Por favor exemplifica, mostrando o comportamento actual do programa e o comportamento que pretendes que o programa tenha.

Existem vários aspectos a melhorar no teu código, mas podemos tratar disso depois de resolvermos os problemas que identificaste.

Share this post


Link to post
Share on other sites
pwseo

Estive a ver o teu código com alguma atenção.

No teu código original, onde tens o case 2, tens um ciclo que é repetido enquanto a variável valor for zero (while (valor == 0) { ... }). O problema é que dentro desse ciclo não há nada que faça valor assumir outro valor que não o 0 inicial (tens apenas duas invocações de printf(), uma invocação de menu() e uma de scanf()). O scanf() final está a armazenar o seu resultado em opc.

Mesmo que valor fosse alterado correctamente, não podemos esquecer-nos que a estrutura de decisão switch/case já foi activada e não existe nenhum mecanismo que volte ao início da mesma; ie. o teu código actual não consegue voltar ao case 1.

Portanto: sugiro que revejas bem o fluxo do programa e o papel das variáveis que estás a utilizar. O que acontece quando chegas ao fim de um case? Para que servem cont, opc e valor?

Share this post


Link to post
Share on other sites
Earendil010102

Já terminei o código, mas vou deixar o resultado final aqui para falar o que acha. Acredito que tenha ficado bem melhor que o anterior.

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct inform {
	int cod;
	char autor[30]; 
	char obra[30]; 
	char editora[10];
};
void menu () {
	printf("\n-----------MENU----------------");
	printf("\nDigite uma opção:");
	printf("\n1 - Inserir um novo cadastro");
	printf("\n2 - Mostrar todos os cadastros");
	printf("\n0 - Encerrar");
	printf("\n-----------MENU----------------");
}
int main(int argc, char *argv[]) { 
	setlocale (LC_ALL, "Portuguese");
	
	struct inform livro[5];
	int opc, i, cont;
	cont = 0;
	i = 0;
								
	menu ();
	scanf("%d", &opc);
	fflush(stdin); 

	while (opc != 0) { 
	
		while (opc > 2) { 
			system("cls");
			printf("\n----------------------\n");
			printf("ERRO: OPÇÃO INVÁLIDA!\n");
			printf("----------------------\n\n");
			menu ();
			scanf("%d", &opc);
			fflush(stdin);
		}  
		
		if (opc == 1) { 
			while (opc == 1 && i<5) {
				system("cls");
				printf("\n----------------------\n");
				printf("CADSTRO DE LIVROS:\n");
				printf("----------------------\n");
				printf("\nDigite o nome do livro: ");
				gets(livro[i].obra);
				fflush(stdin);
				printf("\nDigite o nome do autor: ");
				gets(livro[i].autor);
				fflush(stdin);
				printf("\nDigite o nome da editora: ");
				gets(livro[i].editora);
				fflush(stdin);
				livro[i].cod = i+1;
				system("cls");
				menu();
				scanf("%d", &opc);
				fflush(stdin);
				i++;
				cont++;
			} 
			while (i == 5 && opc == 1) { 
				system("cls");
				printf("\n\nSistem de cadatro lotado. Não é possível armazenar mais informações\n");
				printf("Digite outra opção.\n\n");
				menu();
				scanf("%d", &opc);
				fflush(stdin);
				system("pause");
				system("cls");
			}  
		} 
		
		if (opc == 2) { 
			while (opc == 2 && (strcmp(livro[0].obra, "") == 0)) { 
				system("cls");
				printf("\nLista vazia!\n");
				menu ();
				scanf("%d", &opc);
				fflush(stdin); 
			}  
			system("cls");
			for (i=0; i<cont; i++) { 
				printf("\n Autor: %s", livro[i].autor);
				printf("\n Obra: %s", livro[i].obra);
				printf("\n Editora: %s", livro[i].editora);
				printf("\n Código: %d\n\n", livro[i].cod);
			} 
			menu();
			scanf("%d", &opc);
			fflush(stdin);
		}
		
	} 
	system("cls");
	printf("\n----------------------\n");
	printf("ENCERRANDO...\n");
	printf("----------------------\n");
	return (0); 
} 

 

Share this post


Link to post
Share on other sites
pwseo

@Earendil010102, sim, agora o teu código funciona como pretendias, mas permite-me deixar alguns comentários sobre o código em si:

  • Declaras a função main() com os parâmetros argc e argv, mas nunca são utilizados. O mais correcto seria declarares simplesmente int main(void) { ... }.
  • fflush(stdin) é uma expressão cujo comportamento não está definido pelo standard da linguagem C; em suma, não é uma forma correcta de limpar o buffer de input.
  • O fluxo do teu programa aparenta funcionar correctamente, mas não é a forma mais lógica de o definir. Experimenta rever bem os ciclos que tens lá (p ex. não faz sentido uma operação que se executa apenas uma vez -- mostrar que a lista está vazia -- esteja dentro de um ciclo while). Acabas por utilizar ciclos while onde podias simplificar e simplesmente utilizar condições.
  • Podias tentar separar a lógica do teu programa e criar uma função para as duas opções principais do menu, em vez de teres tudo dentro da main().
  • Vote 2

Share this post


Link to post
Share on other sites
Earendil010102

@pwseo, o que acontece é o seguinte: esse código é um trabalho de faculdade. Os parâmetros argc e arfc foram usados porque eu estava executando em modo debug, mas normalmente eu uso o main(), como você falou. Quanto ao fflush(stdin), eu já perguntei aos meus professores e todos disseram que esse é o melhor método para limpar o buffer, mas se você souber de algum melhor, por gentileza, deixe nos comentário que eu irei testar. 

Com relação ao comando "mostrar lista vazia", foi feito desse modo, pois na atividade está escrito que enquanto o usuário não digitar outra opção, essa tela deve se repetir, por isso usei o while. 

E, finalmente, eu pensei em fazer uma função para cada opção, mas tive que refazer aquele código que eu enviei, praticamente do zero. Então optei por deixar tudo dentro do main para garantir que o código funcionaria corretamente, mas acredito que com uma função para cada opção ficaria melhor. 

Edited by Earendil010102

Share this post


Link to post
Share on other sites
pwseo

@Earendil010102,

Vamos por partes:

Não percebo qual o motivo para os parâmetros argc e argv estarem relacionados com a execução «em modo debug». Se o teu código não depende dos argumentos passados na linha de comandos, não são necessárias essas variáveis. Outro pormenor: em C, dizer main() é diferente de main(void); o primeiro indica que main aceita um número indefinido de argumentos, o segundo indica que main não aceita argumentos (em C++ não é assim).

Relativamente ao fflush(stdin), não só não é a melhor maneira de limpar o buffer, é precisamente um dos erros mais conhecidos e documentados pela comunidade que programa em C. O comportamento de fflush(stdin) é indefinido segundo o próprio standard, o que significa que cada compilador é livre de fazer o que quiser com isso. Por exemplo no meu sistema, essa linha não funciona porque o GCC assim o escolheu.

A forma correcta de limpar o buffer é ler o seu conteúdo através de chamadas a getchar() até que seja devolvido um '\n' ou até que o input seja esgotado (EOF). Aqui fica uma função que faz precisamente isso (poderia ser abreviada, mas assim percebe-se melhor a sua intenção):

void clear_stdin(void)
{
        int c;
        do {
                c = getchar();
        } while (c != '\n' && c != EOF);
}

Apenas a título de curiosidade, fiz dois exemplos no Ideone.com onde podemos ver o comportamento de um determinado programa que aceita um número e uma letra e os devolve ao utilizador; esta versão utiliza fflush(stdin) para limpar o buffer, e esta versão utiliza a função clear_stdin() acima. Como podes ver, a versão que utiliza fflush(stdin) não limpa o buffer correctamente, e como resultado a «letra» lida é a tecla RETURN, que se reflecte no output (uma mudança de linha entre as aspas).

Em relação aos restantes pontos, acho que seria interessante (e benéfico para ti) revisitar o código após entregar o trabalho. Desta forma poderás decidir que aspectos deverias melhorar, nomeadamente a tal separação do código em funções diferentes. A longo prazo, esta será uma das capacidades mais importantes a desenvolver, uma vez que a complexidade do código aumenta muito rapidamente com o seu tamanho; é fulcral desenvolver código correcto, compacto e legível que interaja de uma forma simples e explícita com o restante projecto.

  • Vote 1

Share this post


Link to post
Share on other sites
Earendil010102
Em 13/07/2019 às 11:09, pwseo disse:

@Earendil010102,

Vamos por partes:

Não percebo qual o motivo para os parâmetros argc e argv estarem relacionados com a execução «em modo debug». Se o teu código não depende dos argumentos passados na linha de comandos, não são necessárias essas variáveis. Outro pormenor: em C, dizer main() é diferente de main(void); o primeiro indica que main aceita um número indefinido de argumentos, o segundo indica que main não aceita argumentos (em C++ não é assim).

Relativamente ao fflush(stdin), não só não é a melhor maneira de limpar o buffer, é precisamente um dos erros mais conhecidos e documentados pela comunidade que programa em C. O comportamento de fflush(stdin) é indefinido segundo o próprio standard, o que significa que cada compilador é livre de fazer o que quiser com isso. Por exemplo no meu sistema, essa linha não funciona porque o GCC assim o escolheu.

A forma correcta de limpar o buffer é ler o seu conteúdo através de chamadas a getchar() até que seja devolvido um '\n' ou até que o input seja esgotado (EOF). Aqui fica uma função que faz precisamente isso (poderia ser abreviada, mas assim percebe-se melhor a sua intenção):


void clear_stdin(void)
{
        int c;
        do {
                c = getchar();
        } while (c != '\n' && c != EOF);
}

Apenas a título de curiosidade, fiz dois exemplos no Ideone.com onde podemos ver o comportamento de um determinado programa que aceita um número e uma letra e os devolve ao utilizador; esta versão utiliza fflush(stdin) para limpar o buffer, e esta versão utiliza a função clear_stdin() acima. Como podes ver, a versão que utiliza fflush(stdin) não limpa o buffer correctamente, e como resultado a «letra» lida é a tecla RETURN, que se reflecte no output (uma mudança de linha entre as aspas).

Em relação aos restantes pontos, acho que seria interessante (e benéfico para ti) revisitar o código após entregar o trabalho. Desta forma poderás decidir que aspectos deverias melhorar, nomeadamente a tal separação do código em funções diferentes. A longo prazo, esta será uma das capacidades mais importantes a desenvolver, uma vez que a complexidade do código aumenta muito rapidamente com o seu tamanho; é fulcral desenvolver código correcto, compacto e legível que interaja de uma forma simples e explícita com o restante projecto.

Testei seu código, mas não sei se fiz da maneira correta. Vou anexá-lo para dizer o que acha.

#include <stdlib.h>
#include <stdio.h>
void clear_stdin(void)
{
        int c;
        do {
                c = getchar();
        } while (c != '\n' && c != EOF);
}

int main() {
	char n[30];
	printf("digite uma letra: ");
	scanf("%s", n);
	clear_stdin();
	return(0);
}

@pwseo, testei com o gets no lugar do scanf mas não funcionou. Para ler caractere simples usando o scanf("%c"), também funcionou.

Edited by Earendil010102

Share this post


Link to post
Share on other sites
thoga31

A forma mais reconhecida pela comunidade (que eu tenha conhecimento) para ler uma string em C é esta:

fgets(s, 30, stdin);  // exemplo para ler ATÉ 30 caracteres

Já agora, creio que o @pwseo estava a apontar casos em que o while está a ser usado como se se tratasse de um if, e não nos casos em que de facto o ciclo while é necessário.

Cumprimentos.


Knowledge is free!

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • 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.