Ir para conteúdo

POWERED BY:

Arquivado

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

Alasca

Arquivos e Registros em C

Recommended Posts

Olá

Preciso de ajuda em um programa em C.

O código já está quase pronto, mas ainda quero fazer algumas modificações.

Quero acrescentar no menu a opção de imprimir em ordem alfabética a lista de alunos aprovados. O aluno é considerado aprovado se a media for igual ou superior a 6. Preciso também de ter no menu a opção de imprimir em ordem alfabética o nome de todos os alunos.

 

Estou em dúvida de como posso fazer isso, se alguém puder ajudar, agradeço muito.

 

Segue o código que estou utilizando:

#include <stdio.h>#include <stdlib.h>
#include <string.h>
#ifndef __MSDOS__
#include <search.h>
#endif
#ifdef __linux__
#include <termios.h>
#include <unistd.h>
#define CLEAR_SCREEN "clear"
#define aacute "\xC3\xA1"
#define oacute "\xC3\xB3"
#define uacute "\xC3\xBA"
#define Uacute "\xC3\x9A"
int _getch ();
#else
#include <conio.h>
#define CLEAR_SCREEN "cls"
#define aacute "\240"
#define oacute "\242"
#define uacute "\243"
#define Uacute "\351"
#ifdef __MSDOS__
#define _getch getch
#endif
#endif


typedef struct TDAAluno {
char* matricula;
char* nome;
int idade;
char* serie;
float nota_de_trabalho;
float nota_de_prova;
float media;
} Aluno;


void* arranjo_inserir (void *arranjo, size_t *tamanho, size_t size, const void *dado);
void* arranjo_remover   (void *arranjo, size_t *tamanho, size_t size, const void *dado);
void  arranjo_recorrer (void *arranjo, size_t  tamanho, size_t size, void *parametros, void (*funcion)(void*,void*));
void  pausar        (const char *mensagem);
char* ler_on_line    (const char *mensagem);
char* ler_cadeia   (const char *mensagem, char *cadeia);
int   ler_inteiro   (const char *mensagem);
float ler_decimal  (const char *mensagem);
int   ler_campo (FILE *arquivo, char *campo);
int   comparar_aluno (const Aluno *aluno1, const Aluno *aluno2);
void  imprimir_aluno (Aluno *dado, int *contador);
void  imprimir_en_arquivo (Aluno *dado, FILE *arquivo);


const char *rota = "alunos.dat";


int main ()
{
Aluno *alunos = NULL;
size_t tamanho=0;
Aluno *dado, aluno;
int contador=0, opcao, subopcao;
char campo[255];
FILE *arquivo = fopen (rota, "r");
if (arquivo!=NULL)
{
while (ler_campo (arquivo, campo))
{
aluno.matricula = strdup (campo);
ler_campo (arquivo, campo);
aluno.nome = strdup (campo);
ler_campo (arquivo, campo);
aluno.idade = atoi (campo);
ler_campo (arquivo, campo);
aluno.serie = strdup (campo);
ler_campo (arquivo, campo);
aluno.nota_de_trabalho = atof (campo);
ler_campo (arquivo, campo);
aluno.nota_de_prova = atof (campo);
ler_campo (arquivo, campo);
aluno.media = atof (campo);
alunos = (Aluno*) arranjo_inserir (alunos, &tamanho, sizeof (Aluno), &aluno);
}
fclose (arquivo);
}
do {
system (CLEAR_SCREEN);
printf ("MENU" "\n");
printf ("1.- Inserir novo cadastro\n");
printf ("2.- Consultas\n");
printf ("3.- Atualizacao\n");
printf ("4.- Excluir registros\n");
printf ("5.- Ordenar registros\n");
printf ("6.- Listar registros\n");
printf ("7.- Sair\n");
printf ("Selecione uma opcao\n");
fflush (stdout);
do
opcao = _getch ();
while (opcao<'1' || opcao>'7');
printf ("%c\n\n", opcao);
if (tamanho==0 && opcao!='1' && opcao!='7')
{
pausar ("Nao ha registros.\n");
continue;
}
if (opcao<'5')
{
aluno.matricula = ler_cadeia ("Insira a matricula do aluno", campo);
dado = (Aluno*) lfind (&aluno, alunos, &tamanho, sizeof (Aluno), (int(*)(const void*,const void*))comparar_aluno);
if (dado!=NULL)
{
putchar ('\n');
imprimir_aluno (dado, &contador);
}
}
if (opcao=='1' && dado!=NULL)
printf ("O registro ja existe.\n");
else if (opcao>='2' && opcao<='4' && dado==NULL)
printf ("\nRegistro nao encontrado.\n");
else switch (opcao)
{
case '1':
aluno.matricula = strdup (campo);
aluno.nome = ler_on_line ("Digite o nome do aluno");
aluno.idade = ler_inteiro ("Digite a idade");
aluno.serie = ler_on_line ("Digite a serie");
aluno.nota_de_trabalho = ler_decimal ("Digite a nota de trabalho");
aluno.nota_de_prova = ler_decimal ("Digite a nota de prova");
aluno.media = ler_decimal ("Digite a media");
alunos = (Aluno*) arranjo_inserir (alunos, &tamanho, sizeof (Aluno), &aluno);
printf ("\nRegistro adicionado com sucesso!\n");
break;
case '3':
printf ("Menu de modificacao de campos\n");
printf ("1.- nome\n");
printf ("2.- idade\n");
printf ("3.- serie\n");
printf ("4.- nota de trabalho\n");
printf ("5.- nota de prova\n");
printf ("6.- media\n");
do {
subopcao = ler_inteiro ("Selecione um numero de campo pra modificar");
if (subopcao<1 || subopcao>6)
printf ("Opcao invalida.\n");
} while (subopcao<1 || subopcao>6);
switch (subopcao)
{
case 1:
free (dado->nome);
dado->nome = ler_on_line ("Digite o novo nome");
break;
case 2:
dado->idade = ler_inteiro ("Digite a nova idade");
break;
case 3:
free (dado->serie);
dado->serie = ler_on_line ("Digite a nova serie");
break;
case 4:
dado->nota_de_trabalho = ler_decimal ("Digite a nova nota de trabalho");
break;
case 5:
dado->nota_de_prova = ler_decimal ("Digite a nova nota de prova");
break;
case 6:
dado->media = ler_decimal ("Digite a nova media");
break;
}
printf ("\nRegistro atualizado com sucesso!\n");
break;
case '4':
memcpy (&aluno, dado, sizeof (Aluno));
alunos = (Aluno*) arranjo_remover ((void**)alunos, &tamanho, sizeof (Aluno), dado);
free (aluno.matricula);
free (aluno.nome);
free (aluno.serie);
printf ("Registro excluido com sucesso!\n");
break;
case '5':
qsort (alunos, tamanho, sizeof (Aluno), (int(*)(const void*,const void*))comparar_aluno);
printf ("Registros ordenados com sucesso!.\n");
break;
case '6':
contador = 0;
arranjo_recorrer (alunos, tamanho, sizeof (Aluno), &contador, (void(*)(void*,void*))imprimir_aluno);
printf ("Total de registros: %d.\n", contador);
break;
}
if (opcao!='7')
pausar ("");
} while (opcao!='7');
arquivo = fopen (rota, "w");
if (arquivo!=NULL)
{
arranjo_recorrer (alunos, tamanho, sizeof (Aluno), arquivo, (void(*)(void*,void*))imprimir_en_arquivo);
fclose (arquivo);
}
return EXIT_SUCCESS;
}


void* arranjo_inserir (void *arranjo, size_t *tamanho, size_t size, const void *dado)
{
char *registro;
arranjo = realloc (arranjo, size * (*tamanho+1));
registro = (char*)arranjo + *tamanho * size;
memcpy (registro, dado, size);
(*tamanho)++;
return arranjo;
}


void* arranjo_remover (void *arranjo, size_t *tamanho, size_t size, const void *dado)
{
size_t i;
char *registro = (char*)arranjo;
for (i=0; i<*tamanho && dado!=registro; i++, registro+=size);
if (i<*tamanho)
{
for (i++; i<*tamanho; i++)
{
registro+=size;
memcpy (registro-size, registro, size);
}
(*tamanho)--;
arranjo = realloc (arranjo, size * (*tamanho));
}
return arranjo;
}


void arranjo_recorrer (void *arranjo, size_t tamanho, size_t size, void *parametros, void (*funcion)(void*,void*))
{
char *registro = (char*)arranjo;
if (tamanho>0)
{
funcion (registro, parametros);
arranjo_recorrer (registro+size, tamanho-1, size, parametros, funcion);
}
}


int comparar_aluno (const Aluno *aluno1, const Aluno *aluno2)
{
return aluno1==aluno2 ? 0 : strcmp (aluno1->matricula, aluno2->matricula);
}


void imprimir_aluno (Aluno *dado, int *contador)
{
printf ("matricula       : %s\n", dado->matricula);
printf ("nome            : %s\n", dado->nome);
printf ("idade           : %d\n", dado->idade);
printf ("serie           : %s\n", dado->serie);
printf ("nota de trabalho: %g\n", dado->nota_de_trabalho);
printf ("nota de prova   : %g\n", dado->nota_de_prova);
printf ("media           : %g\n", dado->media);
putchar ('\n');
(*contador)++;
}


void imprimir_en_arquivo (Aluno *dado, FILE *arquivo)
{
fprintf (arquivo, "%s\t", dado->matricula);
fprintf (arquivo, "%s\t", dado->nome);
fprintf (arquivo, "%d\t", dado->idade);
fprintf (arquivo, "%s\t", dado->serie);
fprintf (arquivo, "%g\t", dado->nota_de_trabalho);
fprintf (arquivo, "%g\t", dado->nota_de_prova);
fprintf (arquivo, "%g\n", dado->media);
}


char* ler_on_line (const char *mensagem)
{
char on_line[255];
ler_cadeia (mensagem, on_line);
return strdup (on_line);
}


char* ler_cadeia (const char *mensagem, char *cadeia)
{
printf ("%s: ", mensagem);
scanf ("%[^\r\n]", cadeia);
getchar ();
return cadeia;
}


int ler_inteiro (const char *mensagem)
{
int inteiro;
printf ("%s: ", mensagem);
scanf ("%d", &inteiro);
getchar();
return inteiro;
}


float ler_decimal (const char *mensagem)
{
float decimal;
printf ("%s: ", mensagem);
scanf ("%f", &decimal);
getchar();
return decimal;
}


int ler_campo (FILE *arquivo, char *campo)
{
fscanf (arquivo, "%[^\t\n\r]", campo);
fgetc (arquivo);
return feof (arquivo) == 0;
}


void pausar (const char *mensagem)
{
printf ("%s\nPressione uma tecla para continuar . . . ", mensagem);
fflush (stdout);
_getch ();
}


#ifdef __linux__


int _getch ()
{
int ch;
struct termios oldt, newt;
tcgetattr (STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr (STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr (STDIN_FILENO, TCSANOW, &oldt);
return ch;
}


#endif

Compartilhar este post


Link para o post
Compartilhar em outros sites

Cara, eu dei uma limpada no seu programa, porque não deu pra entender muita coisa. Não implementei tudo, mas acho que você consegue entender e seguir.

Optei por deixar o nome e a matrícula em tamanho fixo p/ facilitar, mas caso seja realmente necessário ter tamanho dinâmico, você pode criar um utils.c com uma implementação de leitura bufferizada usando fgets e realloc (a princípio tomando cuidado de não estourar o heap).

main_aluno.c

#include <stdio.h>
#include "aluno.h"

int main(void) {
	_init_structures();

	int options_return = 0;

	while(options_return != SAIR) {
		menu_operacoes();
		options_return = processar_opcao(&compare_main_options);

		if (options_return == INVALIDO) {
			puts("Opção inválida. Tente novamente.");
		} else {
			struct TDAAluno _tmp;

			switch(options_return) {
				case INSERIR:
					menu_inserir(&_tmp);
					inserir(&_tmp);
					break;
				case ORDENAR:
					menu_ordenar();
					options_return = processar_opcao(&compare_sort_options);

					if (options_return == INVALIDO) {
						puts("Opção inválida. Tente novamente.");
					} else if (options_return == SAIR) {
						options_return = INVALIDO; // Precisamos redefinir a opção para que o laço principal  não termine.
					} else ordenar(options_return);


					break;
				case LISTAR:
					imprimir();
					break;
			}
		}
	}
	return 0;
}

aluno.h

#define INVALIDO -1
enum OPCAO_OPERACAO_INICIAL{INSERIR = 1, CONSULTAR, ATUALIZAR, EXCLUIR, ORDENAR, LISTAR, SAIR};
enum OPCAO_ORDENACAO{MATRICULA = 1, NOME};

#define  _LEN_MATRICULA 5
#define  _LEN_NOME      30


struct TDAAluno {
	char matricula[_LEN_MATRICULA];
	char nome[_LEN_NOME];
	int idade;
	float nota_trabalho;
	float nota_prova;
};


// Internal
void _init_structures();


void menu_operacoes();
int processar_opcao(int (*func)(int option));

// Insert-related
void menu_inserir(struct TDAAluno * _tmp);
size_t inserir(struct TDAAluno * _tmp);

// Search-related
// We use a function pointer to pass custom comparison functions.
int existe_aluno(struct TDAAluno * _tmp, int (*func)(struct TDAAluno * a, struct TDAAluno * b));
int compare_by_nome(struct TDAAluno * src, struct TDAAluno * current);
int compare_by_matricula(struct TDAAluno * src, struct TDAAluno * current);

// Sort-related
void menu_ordenar();
void ordenar(int  sort_option);

// Option comparison Sort-related
int compare_main_options(int option);
int compare_sort_options(int option);

// Listing
void imprimir();

aluno.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "aluno.h"

size_t _LEN_LISTA = 0;
struct TDAAluno * _lista;

void _init_structures() {
	_lista = malloc(0);
	if (!_lista) {
		printf("[ERRO] %s: %s\n", __func__, strerror(errno)); // http://stackoverflow.com/questions/15349761/get-called-function-name-as-string
		exit(EXIT_FAILURE);
	}
}

void menu_operacoes() {
	puts("********************");
	puts("  LISTA DE ALUNOS   ");
	puts("********************");

	puts("1.- Inserir novo cadastro");
	puts("2.- Consultas");
	puts("3.- Atualização");
	puts("4.- Excluir registros");
	puts("5.- Ordenar registros");
	puts("6.- Listar registros");
	puts("7.- Sair");

	printf("Selecione uma opção: ");
}

int compare_main_options(int opcao) {
	if (opcao < INSERIR || opcao > SAIR) return INVALIDO;
	return opcao;
}

int compare_sort_options(int opcao) {
	if (opcao < NOME || opcao > SAIR) return INVALIDO;
	return opcao;
}

int processar_opcao(int (*func)(int option)) {
	int opcao;
	scanf("%d%*c", &opcao);
	return func(opcao);
}


void menu_inserir(struct TDAAluno * _tmp) {
	puts(">>> INSERIR ALUNO <<<");
	printf("Informe o nome: ");
	fgets(_tmp->nome, _LEN_NOME, stdin);
	_tmp->nome[strlen(_tmp->nome)-1] = '\0';

	printf("Informe a matrícula: ");
	fgets(_tmp->matricula, _LEN_MATRICULA, stdin);
	_tmp->matricula[strlen(_tmp->matricula)-1] = '\0';

	printf("Informe a idade: ");
	scanf("%d%*c", &(_tmp->idade));

	printf("Informe a nota do trabalho: ");
	scanf("%f%*c", &(_tmp->nota_trabalho));

	printf("Informe a nota da prova: ");
	scanf("%f%*c", &(_tmp->nota_prova));
}

int compare_by_nome(struct TDAAluno * src, struct TDAAluno * current) {
	return strcmp(src->nome, current->nome);
}

int compare_by_matricula(struct TDAAluno * src, struct TDAAluno * current) {
	return strcmp(src->matricula, current->matricula);
}

int existe_aluno(struct TDAAluno * _tmp, int (*func)(struct TDAAluno * a, struct TDAAluno * b)) {
	size_t i;
	for(i=0; i<_LEN_LISTA && func(_tmp, &_lista[i]); i++);
	return i<_LEN_LISTA;
}

size_t inserir(struct TDAAluno * _tmp) {
	if (!existe_aluno(_tmp, &compare_by_nome) && 
		!existe_aluno(_tmp, &compare_by_matricula)) {

		_lista = realloc(_lista, (_LEN_LISTA + 1) * sizeof(struct TDAAluno));
		
		/***** VERIFIQUE SE O RETORNO DE REALLOC É NULL E TRATE *****/

		strncpy(_lista[_LEN_LISTA].nome, _tmp->nome, strlen(_tmp->nome));
		strncpy(_lista[_LEN_LISTA].matricula, _tmp->matricula, strlen(_tmp->matricula));
		_lista[_LEN_LISTA].idade = _tmp->idade;
		_lista[_LEN_LISTA].nota_trabalho = _tmp->nota_trabalho;
		_lista[_LEN_LISTA].nota_prova = _tmp->nota_prova;
		
		_LEN_LISTA++;
	}
	return _LEN_LISTA;
}


void menu_ordenar() {
	puts("***************************");
	puts("  CRITÉRIOS DE ORDENAÇÃO   ");
	puts("***************************");

	puts("1.- Por matrícula");
	puts("2.- Por nome");
	puts("7.- Sair"); // Reutilizamos a opção SAIR definida em outra ENUM.

	printf("Selecione uma opção: ");
}

void ordenar(int sort_option) {
	if (sort_option == NOME) {
		qsort(_lista, _LEN_LISTA, sizeof(struct TDAAluno), &compare_by_nome); /* http://stackoverflow.com/questions/2561697/warning-when-using-qsort-in-c */
	} else if (sort_option == MATRICULA)
		qsort(_lista, _LEN_LISTA, sizeof(struct TDAAluno), &compare_by_matricula);
};

void imprimir() {
	for(size_t i=0; i<_LEN_LISTA; i++) {
		puts("--------------------------------------------");
		printf("X Nome: %s\n",_lista[i].nome);
		printf("X Matrícula: %s\n", _lista[i].matricula);
		printf("X Idade: %d\n", _lista[i].idade);
		printf("X Nota no trabalho: %.2f\n", _lista[i].nota_trabalho);
		printf("X Nota na prova: %.2f\n", _lista[i].nota_prova);
		puts("--------------------------------------------\n");
	}
}

Utilizei ponteiros p/ funções porque 2 delas, as de comparação de nome e matrícula, por serem utilizadas tanto na busca de um elemento existente na lista quanto na ordenação (como critério) não precisam ser reimplementadas toda hora. No fonte tem um link explicativo. (No começo assusta, mas depois que você entende o que é e o que dá pra ser feito com isso é uma mão na roda).

A compilação foi feita com gcc -Wall -Wextra -std=c99 main_aluno.c aluno.c. O GCC emite 2 warnings sobre o último argumento passado pro qsort,mas não captei como se arruma isso.

PS: Coloque os frees antes de terminar o programa. Acabei esquecendo disso.

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.