Gabarito da Lista 8
M�dulo 8: Aula 10: Tipos de dados avan�ados
Aula 11: Tipos de dados definidos pelo usu�rio
Exerc�cio 1: P�gina ca20.html
Considerando o conceito e finalidade dos modificadores de tipo, relacione as afirmativas com as palavras reservadas correspondentes (todas as afirmativas devem ser preenchidas com o
n�mero relacionado ao modificador correspondente, e existe pelo menos uma afirmativa para cada modificador):
(1)const (3)extern (5)register (7)void
(2)volatile (4)static (6)auto
( 1 ) informa ao
compilador que o valor da vari�vel n�o pode ser alterado por nenhum comando do programa, mas que pode ser inicializado
( 7 ) informa ao compilador que nenhum valor ser� devolvido pela fun��o
( 2 ) informa ao compilador que a vari�vel pode ser modificada por algum evento que n�o est� sob o controle do programa
( 3 ) avisa ao compilador que as vari�veis que o seguem j� foram declaradas em outro lugar
( 4 ) torna a vari�vel
permanente, mantendo seu valor entre chamadas
( 4 ) �til ao escrever fun��es generalizadas e fun��es de biblioteca que podem ser usadas por outros programadores, pois permite esconder por��es do programa de outras partes do c�digo, evitando assim o uso de vari�vel global
( 1 ) quando apontadores forem passados para a fun��o, garante que nenhum c�digo na fun��o poder� modificar os objetos apontados
( 5 ) armazena o valor da
vari�vel em um registrador da CPU, acelerando opera��es
( 6 ) usada para declarar vari�veis locais autom�ticas, mas muito pouco usada por j� ser o padr�o (default)
( 5 ) avisa ao compilador que a vari�vel em quest�o sera largamente usada e deve permanecer acess�vel da forma mais eficiente poss�vel
( 3 ) permite ao compilador conhecer a vari�vel sem criar armazenamento para ela novamente em outro modulo
Exerc�cio 2: P�gina ca60.html
Enunciado:
Refa�a o exemplo desta p�gina, mas ao inv�s de trabalhar com um vetor de inteiros, use um vetor de strings (ou uma matriz de char, como voc� preferir). Fa�a leituras e apresente os resultados na tela.Solu��o:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TAM 5
#define MAX 80
int main ()
{
/* Declarando um vetor de apontadores */
char *mat[TAM];
/* Declara um buffer para efetuar a leitura */
char buffer[MAX];
int i,j;
printf("\nEntre com %d Frases:\n\n", TAM);
for (i=0; i<TAM; i++)
{
gets(buffer);
/* Aloca em mat[i] a quantidade de caracteres suficiente para armazenar o buffer */
mat[i]=(char *) calloc((strlen(buffer)+1), sizeof(char));
/* Testa se a aloca��o teve sucesso */
if (!mat)
{
printf ("** Erro: Memoria Insuficiente **");
for(j=0; j < i; j++)
free(mat[j]);
exit(1);
}
/* Copia a string, do buffer para o vetor de strings */
strcpy(mat[i],buffer);
}
printf("\nFrases digitadas");
for(i=0; i<TAM; i++)
printf("%s\n", mat[i]);
for(j=0; j<TAM; j++)
free(mat[j]);
}
Note que neste programa estamos usando uma string (buffer) apenas para efetuar a leitura de cada string. Ap�s efetuada a leitura, alocamos no vetor de ponteiros para char a quantidade exata de caracteres necess�rios para o armazenamento da string lida e efetuamos a sua c�pia para esta regi�o de mem�ria usando strcpy.
Exerc�cio 3: P�gina ca70.html
Faca um programa que multiplique duas matrizes. O programa devera' estar estruturado de maneira que:
1- o usuario forneca as dimensoes das matrizes (teste se as dimensoes sao compativeis, isto e', se as matrizes podem ser multiplicadas);
2- as matrizes sejam alocadas dinamicamente (voce pode usar a funcao vista nesta pagina para isto);
3- as matrizes sejam lidas pelo teclado (faca uma funcao para leitura das matrizes);
4- as matrizes sejam, entao, multiplicadas (faca uma funcao para a multiplicacao);
5- a matriz resultante seja apresentada em tela (faca uma funcao para apresentar a matriz na tela).
Enunciado:
Faca um programa que multiplique duas matrizes. O programa devera' estar estruturado de maneira que:1- o usuario forneca as dimensoes das matrizes (teste se as dimensoes sao compativeis, isto e', se as matrizes podem ser multiplicadas);
2- as matrizes sejam alocadas dinamicamente (voce pode usar a funcao vista nesta p�gina para isto);
3- as matrizes sejam lidas pelo teclado (faca uma funcao para leitura das matrizes);
4- as matrizes sejam, entao, multiplicadas (faca uma funcao para a multiplicacao);
5- a matriz resultante seja apresentada em tela (faca uma funcao para apresentar a matriz na tela).OBS:
a) Faca, tambem, alocacao dinamica da matriz resultante.
b) Caso algu�m n�o conhe�a o procedimento para a multiplica��o de matrizes, segue aqui a orienta��o.
Suponha as matrizes A(mXn)| a11 a12 ... a1n |
A = | a21 a22 ... a2n |
| : |
| am1 am2 ... amn |e B(nXt)
| b11 b12 ... b1t |
B = | b21 b22 ... b2t |
| : |
| bn1 bn2 ... bnt |O elemento ij da matriz C � resultante da multiplica��o da linha i de A pela coluna j de B. Portanto, a matriz C
(mXt) = A*B ser� da seguinte forma:C =
| a11*b11 +a12*b21 + ... +a1n*bn1 a11*b12 +a12*b22 + ... + a1n*bn2 ... a11+b1t +a12*b2t + ... + a1n*bnt |
| a21*b11 +a22*b21 + ... +a2n*bn1 a21*b12 +a22*b22 + ... + a2n*bn2 ... a21+b1t +a22*b2t + ... + a2n*bnt |
| ... ... ... ... |
| am1*b11 +am2*b21 +...+amn*bn1 am1*b12 +am2*b22 +...+ amn*bn2 ... am1+b1t +am2*b2t +...+amn*bnt |Solu��o:
#include <stdio.h>
#include <stdlib.h>float **Alocar_matriz_real (int m, int n)
{
float **v; /* ponteiro para a matriz */
int i; /* variavel auxiliar */
if (m < 1 || n < 1) { /* verifica parametros recebidos */
printf ("** Erro: Parametro invalido **\n");
return (NULL);
}
/* aloca as linhas da matriz */
v = (float **) calloc (m, sizeof(float *));
if (v == NULL) {
printf ("** Erro: Memoria Insuficiente **");
return (NULL);
}
/* aloca as colunas da matriz */
for ( i = 0; i < m; i++ ) {
v[i] = (float*) calloc (n, sizeof(float));
if (v[i] == NULL) {
printf ("** Erro: Memoria Insuficiente **");
return (NULL);
}
}
return (v); /* retorna o ponteiro para a matriz */
}float **Liberar_matriz_real (int m, int n, float **v)
{
int i; /* variavel auxiliar */
if (v == NULL) return (NULL);
if (m < 1 || n < 1) { /* verifica parametros recebidos */
printf ("** Erro: Parametro invalido **\n");
return (v);
}
for (i=0; i<=m; i++) free (v[i]); /* libera as linhas da matriz */
free (v); /* libera a matriz */
return (NULL); /* retorna um ponteiro nulo */
}void Le_matriz_real(int linhas, int colunas, float **matriz)
{
int i, j;
for (i = 0; i < linhas; i++)
{
printf("\nlinha %d: \n", i+1);
for (j= 0; j<colunas; j++)
scanf("%f", &matriz[i][j]);
}
}void Multiplica_matriz_real(int linha3, int coluna3, int linha2, float **mat1,float **mat2, float **mat3)
{
int i, j, t;
for(i=0; i< linha3; i++)
for(j=0; j< coluna3; j++)
{
mat3[i][j] = 0;
for(t=0; t< linha2; t++) /* linha2, que e igual a coluna1.. */
mat3[i][j] += mat1[i][t]*mat2[t][j];
}
}
void Imprime_matriz_real(int linha,int coluna,float **mat)
{
int i,j;
for (i =0; i < linha; i++)
{
for (j=0; j<coluna; j++)
printf("%f\t", mat[i][j]);
printf("\n");
}
}void main (void)
{
float **mat1, **mat2, **mat3; /* matrizes a serem alocadas */
int linha1, coluna1; /* Dimensoes das matrizes */
int linha2, coluna2;
int linha3, coluna3;
int i, j, t, erro=0;printf("\n\n-------- Multiplicacao de Matrizes: -----------\n");
printf(" Alocacao Dinamica de Memoria\n");
printf("------------------------------------------------\n");
/* Le e compara as dimensoes das matrizes.
So abandona o loop se as dimensoes forem validas
Atencao aa condicao... */
do
{
printf("\nDimensoes da matriz 1 (linhas e colunas): ");
scanf("%d%d", &linha1, &coluna1);
printf("\nDimensoes da matriz 2 (linhas e colunas): ");
scanf("%d%d", &linha2, &coluna2);
if ( coluna1 != linha2 )
printf("\nDimensoes Invalidas! Tente de novo..\n");
} while ( coluna1 != linha2 );
/* Dimensoes da matriz de resposta: */
linha3 = linha1;
coluna3 = coluna2;
/* Aloca a memoria para as matrizes: */
if ((mat1 = Alocar_matriz_real (linha1, coluna1))== NULL) erro = 1;
if ((mat2 = Alocar_matriz_real (linha2, coluna2))== NULL) erro = 1;
if ((mat3 = Alocar_matriz_real (linha3, coluna3))== NULL) erro = 1;
if (erro)
{
printf("\n Memoria Insuficiente! Abortando..\n");
exit(1);
}/* Le a Matriz 1: */
printf("\n\nDigite a Matriz 1:\n");Le_matriz_real(linha1,coluna1,mat1);
/* Le a Matriz 2: */
printf("\n\nDigite a Matriz 2:\n");
Le_matriz_real(linha2,coluna2,mat2);
/* Imprime as matrizes lidas */
printf ("\n\n==>Matriz 1\n");
Imprime_matriz_real(linha1,coluna1,mat1);
printf ("\n\n==>Matriz 2\n");
Imprime_matriz_real(linha2,coluna2,mat2);
/* --------------------- Multiplicacao..*/
Multiplica_matriz_real(linha3,coluna3,linha2,mat1,mat2,mat3);
/* ------------- Imprime a Matriz Calculada... */
printf("\n\n==> Matriz 3 , Resultado da multiplicacao:\n");
Imprime_matriz_real(linha3,coluna3,mat3);Liberar_matriz_real (linha1, coluna1, mat1);
Liberar_matriz_real (linha2, coluna2, mat2);
Liberar_matriz_real (linha3, coluna3, mat3);
}
Exerc�cio 4: P�gina cb10.html
Enunciado:
Escreva um programa fazendo o uso de struct's. Voc� dever� criar uma struct chamada Ponto, contendo apenas a posi��o x e y (inteiros) do ponto. Declare 2 pontos, leia a posi��o (coordenadas x e y) de cada um e calcule a dist�ncia entre eles. Apresente no final a dist�ncia entre os dois pontos.Solu��o:
#include <stdio.h>
#include <math.h> /* Para as funcoes de raiz e potencia */
struct ponto {
int x;
int y;
};
void le_ponto(struct ponto *p, char *);
float dist(struct ponto p1, struct ponto p2);void main(void)
{
struct ponto p1, p2;
printf("\nDistancia entre os pontos:\n");
le_ponto(&p1, "primeiro");
le_ponto(&p2, "segundo");
printf("\n\nDistancia entre os pontos: %5.2f\n", dist(p1, p2));
}
void le_ponto(struct ponto *p, char *s)
{
int x, y;
printf("Digite as coordenadas do %s ponto (x,y): ", s);
scanf("%d%d", &x, &y);
p->x = x;
p->y = y;
}
float dist(struct ponto p1, struct ponto p2)
{
float s1, s2;
s1 = pow((p1.x-p2.x), 2); /* Funcao pow(x,y) retorna x^y */
s2 = pow((p1.y-p2.y), 2);
return sqrt( s1 + s2); /* Funcao sqrt(x) retorna a
raiz quadrada de x */
}
Exerc�cio 5: P�gina cb20.html
Enunciado:
Seja a seguinte struct que � utilizada para descrever os produtos que est�o no estoque de uma loja :
struct Produto {
char nome[30]; /* Nome do produto */
int codigo; /* Codigo do produto */
double preco; /* Preco do produto */
};a) Escreva uma instru��o que declare uma matriz de Produto com 10 itens de produtos;
b) Atribua os valores "Pe de Moleque", 13205 e R$0,20 aos membros da posi��o 0 e os valores "Cocada Baiana", 15202 e R$0,50 aos membros da posi��o 1 da matriz anterior;
c) Fa�a as mudan�as que forem necess�rias para usar um ponteiro para Produto ao inv�s de uma matriz de Produtos. Fa�a a aloca��o de mem�ria de forma que se possa armazenar 10 produtos na �rea de mem�ria apontada por este ponteiro e refa�a as atribui��es da letra b;
d) Escreva as instru��es para imprimir os campos que foram atribu�dos na letra c.Solu��o:
a) struct Produto prod[10]; /* Declara prod como um vetor que armazena 10 produtos */
b) O programa a seguir faz o que foi pedido:
#include <string.h>
struct Produto {
char nome[30]; /* Nome do produto */
int codigo; /* Codigo do produto */
double preco; /* Preco do produto */
};int main()
{
struct Produto prod[10];
strcpy(prod[0].nome,"Pe de Moleque");
prod[0].codigo = 13205;
prod[0].preco = 0.20;
strcpy(prod[1].nome,"Cocada Baiana");
prod[1].codigo = 15202;
prod[1].preco = 0.50;
return(0);
}
c) e d) O programa a seguir faz o que foi pedido, incluindo a impress�o:#include <string.h>
#include <stdlib.h>
#include <stdio.h>struct Produto {
char nome[30]; /* Nome do produto */
int codigo; /* Codigo do produto */
double preco; /* Preco do produto */
};int main()
{
struct Produto *prod;
int i;
prod = (struct Produto *) malloc(10*sizeof(struct Produto));
if (prod ==NULL)
{
printf("\n Memoria Insuficiente");
exit(1);
}
strcpy(prod[0].nome,"Pe de Moleque");
prod[0].codigo = 13205;
prod[0].preco = 0.20;
strcpy(prod[1].nome,"Cocada Baiana");
prod[1].codigo = 15202;
prod[1].preco = 0.50;
printf("Quitanda do Manuel: Lista de Produtos");
for(i=0; i <= 1; i++)
{
printf("\n\nProd %d: %s",i+1, prod[i].nome);
printf("\nCodigo: %d",prod[i].codigo);
printf("\nPreco : R$ %.2f", prod[i].preco);
}
return 0;
}
Exerc�cio 6: P�gina cb70.html:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 100typedef struct tag_restaurante { char *nome; char *endereco; char tipo_comida; int nota; struct tag_restaurante *proximo; } Restaurante;/* Prototipos das funcoes */void inserir(Restaurante **cabeca); /* Insere um restaurante na lista */ void listar (Restaurante *cabeca, FILE *arquivo); /* Apresenta todos os restaurantes na tela ou em um arquivo*/ Restaurante* le_arquivo(FILE *arquivo); /* Le a lista de restaurantes a partir de um arquivo */ void listar_seletivamente(Restaurante *cabeca, char *criterio, char *valor); /* Apresenta somente os restaurantes que satisfa�am determinado crit�rio */ FILE * abre_arquivo(FILE *arquivo, const char * modo); void le_dados_no(Restaurante *novono); void imprime_no( FILE *arquivo, Restaurante * noatual); Restaurante* desaloca_lista(Restaurante* cabeca); void aloca_copia(char ** , char* );int main() { Restaurante *cabeca = NULL; /* Ponteiro para a cabeca da lista */ char q; /* Caractere para receber a opcao do usuario */ FILE *arquivo = NULL; /* Ponteiro para FILE: arquivo que ser� lido ou escrito */ char nota[5]; /* nota para comparacao vai ser lida como char */ do { printf("\n\nOpcoes: \ \nI -> para inserir novo restaurante; \ \nL -> para listar todos Restaurantes; \ \nA -> para ler lista de restaurantes de um arquivo;\ \nG -> para gravar lista de Restaurantes para arquivo; \ \nN -> Para listar os restaurantes com nota superior a um valor; \ \nT -> Para listar os restaurantes de determinado tipo; \ \nS -> para sair \n:"); fflush(stdin); /* Limpa o buffer de entrada */ scanf("%c", &q); /* Le a opcao do usuario */ fflush(stdin); /* Limpa o buffer de entrada */ switch(q) { case 'i': case 'I': /* Inserir novo no na lista */ inserir(&cabeca); break; case 'l': case 'L': /* Listar no video a lista de restaurantes */ listar(cabeca, stdout); printf("\n Aperte <enter> para continuar"); fflush(stdin); scanf("%c",&q); fflush(stdin); break; case 'a': case 'A': /* Ler a lista a partir de arquivo */ arquivo = abre_arquivo(arquivo, "r"); if(arquivo) { cabeca = desaloca_lista(cabeca); /* Se havia lista anterior, ela e' desalocada */ cabeca = le_arquivo(arquivo); /* Le arquivo e retorna ponteiro para cabeca da lista */ fclose(arquivo); /* Fecha o arquivo, pois nao precisa mais dele */ } break; case 'g':case 'G': /* Grava a lista para um arquivo */ arquivo = abre_arquivo(arquivo,"w"); if(arquivo) { listar(cabeca, arquivo); /* Grava o arquivo */ fclose(arquivo); /* Fecha o arquivo */ } break; case 'n': case 'N': /* Lista restaurantes com nota superior a um valor */ printf("\n\nNota do restaurante deve ser superior a:"); gets(nota); listar_seletivamente(cabeca, "nota", nota); break; case 't': case 'T': /* Lista restaurantes por tipo de comida */ printf("\n\nQual tipo de comida?: \ \nB -> Brasileira; \ \nC -> Chinesa; \ \nF -> Francesa; \ \nI -> Italiana; \ \nJ -> Japonesa; \ \nO -> Outro tipo.\n:"); fflush(stdin); scanf("%c", &q); fflush(stdin); listar_seletivamente(cabeca, "tipo_comida", &q); break; case 's': case 'S': /* Sair do programa */ break; default: printf("\n\n Opcao nao valida"); } } while ((q != 's') && (q != 'S') ); cabeca = desaloca_lista(cabeca); /* Saindo do programa, desaloca a lista alocada */}/* Desaloca a memoria alocada para os elementos da lista */Restaurante* desaloca_lista(Restaurante* cabeca) { Restaurante* noatual; noatual = cabeca; while (noatual != NULL) { cabeca = noatual->proximo; /* Armazena em cabeca o proximo no */ free(noatual->nome); /* Nao esquecer de desalocar nome */ free(noatual->endereco); /* e endereco */ free(noatual); /* Desaloca o no atual */ noatual = cabeca; /* Faz no atual apontar para o proximo no */ } return cabeca; }/* Lista todos os elementos presentes na lista encadeada */ void listar (Restaurante *noatual, FILE *arquivo) { while( noatual != NULL) /* Enquanto nao chega no fim da lista */ { imprime_no(arquivo,noatual); /* Imprime o no atual */ noatual = noatual->proximo; /* Faz noatual apontar para o proximo no */ } }/* Lista os elementos de maneira seletiva, seguindo criterios especificados em criterio e dependentes do valor */void listar_seletivamente(Restaurante *noatual, char *criterio, char *valor) { while( noatual != NULL) /* Enquanto nao chega no fim da lista */ { if(!strcmp(criterio,"tipo_comida")) /* Criterio de comparacao e' o tipo de comida */ { if(*valor == noatual->tipo_comida) imprime_no(stdout, noatual); } else { if(!strcmp(criterio,"nota")) /* Criterio de comparacao e' a nota */ if(atoi(valor) <= noatual->nota) imprime_no(stdout,noatual); } noatual = noatual->proximo; /* Faz noatual apontar para o proximo no */ } }/* Imprime um no da lista no arquivo especificado */void imprime_no( FILE *arquivo, Restaurante * noatual) { fprintf(arquivo,"\nNome : %s", noatual->nome); fprintf(arquivo,"\nEndereco: %s", noatual->endereco); fprintf(arquivo,"\nCozinha : %c", noatual->tipo_comida); fprintf(arquivo,"\nNota : %d\n", noatual->nota); }/* Funcao para abrir arquivo */FILE* abre_arquivo(FILE* arquivo, const char* modo) { static char nome[20]=""; char novonome[20]; if(strlen(nome))printf("Nome atual = %s , se quiser mante-lo responda com um enter", nome); printf("\nEntre com o nome do arquivo:"); gets(novonome); if(strlen(novonome)) strcpy(nome,novonome); arquivo = fopen (nome, modo); if(!arquivo) printf("Problema na abertura do arquivo %s", nome); return arquivo; }/* Funcao para inserir um novo no, ao final da lista */void inserir (Restaurante **cabeca) /* Veja que o parametro e' um ponteiro duplo ... */ { Restaurante *noatual, *novono; if (*cabeca == NULL) /* Se ainda nao existe nenhum Restaurante na lista */ { /* cria o no cabeca */ *cabeca = (Restaurante *) malloc(sizeof(Restaurante)); novono = *cabeca; } else { /* Se ja existem elementos na lista, deve percorre-la ate' o seu final e inserir o novo elemento */ noatual = *cabeca; while(noatual->proximo != NULL) noatual = noatual->proximo; /* Ao final do while, noatual aponta para o ultimo no */ novono = (Restaurante *) malloc(sizeof(Restaurante));/* Aloca memoria para o novo no */ noatual->proximo = novono; /* Faz o ultimo no apontar para o novo no */ } le_dados_no(novono); }/* Entra com os dados via teclado e armazena no no da lista */void le_dados_no(Restaurante *novono) { char buffer[MAX]; printf("\nNome do Restaurante:"); gets(buffer); novono->nome = (char *) malloc((strlen(buffer)+1)*sizeof(char)); strcpy(novono->nome,buffer); printf("\nEndereco do Restaurante:"); gets(buffer); novono->endereco = (char *) malloc((strlen(buffer)+1)*sizeof(char)); strcpy(novono->endereco,buffer); printf("\n\nQual tipo de comida?: \ \nB -> Brasileira; \ \nC -> Chinesa; \ \nF -> Francesa; \ \nI -> Italiana; \ \nJ -> Japonesa; \ \nO -> Outro tipo.\n:"); fflush(stdin); scanf("%c",&(novono->tipo_comida)); fflush(stdin); printf("\n\n Nota para o restaurante:"); scanf("%d",&(novono->nota)); novono->proximo = NULL; }/* Le a lista de restaurantes, armazenada em um arquivo Retorna o ponteiro para o no cabeca da lista */Restaurante* le_arquivo(FILE *arquivo) { char buffer[MAX+10], nome[MAX],endereco[MAX]; char comida; Restaurante *cabeca = NULL; Restaurante *noatual = NULL; int nota; while(!feof(arquivo)) { fgets(buffer,MAX,arquivo); if(strstr(buffer,"Nome :"))strcpy(nome,buffer+10); /*strstr verifica se a string2 ocorre na string1: esta' em string.h */ else if(strstr(buffer,"Endereco:")) strcpy(endereco,buffer+10); else if(strstr(buffer,"Cozinha :")) comida = buffer[10]; else if(strstr(buffer, "Nota :")) { nota = atoi(buffer+9); if(cabeca == NULL) { /* cria o no cabeca */ cabeca = (Restaurante *) malloc(sizeof(Restaurante)); noatual = cabeca; } else { noatual->proximo = (Restaurante *) malloc(sizeof(Restaurante)); noatual = noatual->proximo; } aloca_copia(&(noatual->nome),nome); aloca_copia(&(noatual->endereco), endereco); noatual->tipo_comida = comida; noatual->nota = nota; noatual->proximo = NULL; } } return cabeca; }/* Esta funcao, ao mesmo tempo que aloca uma string com tamanho igual a da segunda string, faz a copia da segunda string para a primeira */void aloca_copia(char ** str_alocada, char* str_copiada) { int i; *str_alocada = (char *) malloc((strlen(str_copiada)+1)*sizeof(char)); for(i=0; (str_copiada[i] && (str_copiada[i] != '\n')); i++) *((*str_alocada)+i) = str_copiada[i]; *((*str_alocada)+i) = 0; }Enunciado:
Crie uma struct para descrever restaurantes. Os campos devem armazenar o nome do restaurante, o endere�o, o tipo de comida (brasileira, chinesa, francesa, italiana, japonesa, etc) e uma nota para a cozinha (entre 0 e 5). Crie uma lista encadeada com esta struct e escreva um programa que:
a) Insira um novo restaurante na lista;
b) Leia uma lista de restaurantes a partir de um arquivo;
c) Grave a lista de restaurantes para um arquivo;
d) Liste todos os restaurantes na tela;
e) Liste os restaurantes com cozinha com nota superior a um determinado valor, determinado pelo usu�rio;
f) Liste todos os restaurantes com determinado tipo de comida, determinado pelo usu�rio.
Solu��o:
Exerc�cios de Fixa��o:
Exerc�cio 1:
Prosseguindo o exerc�cio da pagina cb10.html, crie uma estrutura chamada ret�ngulo, que possua duas estruturas ponto (o ponto superior esquerdo e o ponto inferior direito). Fa�a um programa que receba (via teclado ou arquivo) as informa��es acerca de um ret�ngulo (as coordenadas dos dois pontos), e informe dados interessantes sobre o ret�ngulo, como a �rea, o comprimento da diagonal e o comprimento de cada aresta.
Solu��o:
#include <stdio.h>
#include <math.h>
typedef struct _ponto /* Aqui usa-se typedef para dar o nome */
{
/* desejado ao tipo */
int x;
int y;
} ponto;
typedef struct _retangulo /* Idem anterior */
{
ponto sup_esq;
ponto inf_dir;
} retangulo;
void le_ponto(ponto *p, char *);
float diagonal(retangulo
r);
int area(retangulo r);
void arestas(retangulo r);
void main(void)
{
retangulo r;
printf("\nPontos do retangulo:\n");
le_ponto(&(r.sup_esq), "primeiro");
le_ponto(&(r.inf_dir), "segundo");
printf("\n\nComprimento da diagonal do retangulo: %5.2f\n", diagonal(r));
printf("\nArea do retangulo: %d", area(r));
arestas(r);
}
void le_ponto(ponto *p, char *s)
{
int x, y;
printf("Digite a posicao do %s ponto (x,y): ", s);
scanf("%d%d", &x, &y);
p->x = x;
p->y = y;
}
float diagonal(retangulo r)
{
float s1, s2;
s1 = pow(r.sup_esq.x - r.inf_dir.x, 2);
s2 = pow(r.sup_esq.y - r.inf_dir.y, 2);
return sqrt( s1 + s2);
}
int area(retangulo r)
{
return ((r.sup_esq.x - r.inf_dir.x) * (r.sup_esq.y - r.inf_dir.y));
}
void arestas(retangulo r)
{
printf("\nComprimento das arestas:");
printf("\nAresta 1: %d", abs(r.sup_esq.x-r.inf_dir.x));
printf("\nAresta 2: %d", abs(r.sup_esq.y-r.inf_dir.y));
}
Coment�rios:
A fun��o abs(x) retorna o m�dulo (valor absoluto) de x. Est� na biblioteca <math.h>.
Exerc�cio 2:
Fa�a um
exerc�cio usando enumera��o. Crie uma enumera��o de meses do ano, e a use para indexar um vetor de nomes dos meses. Desta forma, apresente os nomes dos meses do ano na tela.
Solu��o:
#include <stdio.h>
enum mes { JAN, FEV, MAR, ABR, MAI, JUN, JUL, AGO, SET, OUT, NOV, DEZ };
void main()
{
enum mes index;
char *meses[12] = { "Janeiro", "Fevereiro", "Marco",
"Abril", "Maio", "Junho",
"Julho", "Agosto", "Setembro",
"Outubro", "Novembro", "Dezembro" };
for (index = JAN; index <= DEZ; index++)
printf("\n%s", meses[index]);
}
Exerc�cio 3:
Refa�a o exerc�cio 1 usando aloca��o din�mica de mem�ria. Use o
comando typedef para definir os tipos ponto e ret�ngulo.
Solu��o:
#include <stdio.h>#include <math.h>
typedef struct _ponto {
int x;
int y;
} ponto;
typedef struct _retangulo {
ponto sup_esq;
ponto inf_dir;
} retangulo;
ponto le_ponto(char *);
float diagonal(retangulo *);
int area(retangulo *);
void arestas(retangulo *);
void main(void)
{
retangulo *r;
if ((r = (retangulo *) malloc(sizeof(retangulo))) == NULL)
{
printf("\nMemoria insuficiente! Abortando\n");
exit(0);
}
printf("\nPontos do retangulo:\n");
r->sup_esq = le_ponto("primeiro");
r->inf_dir = le_ponto("segundo");
printf("\n\nDiagonal do retangulo: %5.2f\n", diagonal(r));
printf("\nArea do retangulo: %d", area(r));
arestas(r);
}
ponto le_ponto(char *s)
{
ponto p;
printf("Digite a posicao do %s ponto (x,y): ", s);
scanf("%d%d", &(p.x), &(p.y));
return p;
}
float diagonal(retangulo *r)
{
float s1, s2;
s1 = pow(r->sup_esq.x - r->inf_dir.x,
2);
s2 = pow(r->sup_esq.y - r->inf_dir.y, 2);
return sqrt( s1 + s2);
}
int area(retangulo *r)
{
return ((r->sup_esq.x - r->inf_dir.x) * (r->sup_esq.y - r->inf_dir.y));
}
void arestas(retangulo *r)
{
printf("\nArestas:");
printf("\nAresta 1: %d",
abs(r->sup_esq.x-r->inf_dir.x));
printf("\nAresta 2: %d", abs(r->sup_esq.y-r->inf_dir.y));
}
Coment�rios:
O comando typedef j� tinha sido usado no exerc�cio 1 da lista. Assim sendo, a �nica mudan�a realizada foi a inclus�o da aloca��o din�mica de mem�ria. Agora, r � um apontador para ret�ngulo, e todas as altera��es no programa foram feitas para suportar isto.
DESAFIO:
Exerc�cio 4:
Use as estruturas declaradas no exemplo da pagina cb10.html (ficha_pessoal e tipo_endereco). Fa�a um programa que controle um arquivo, contendo informa��es sobre pessoas. O programa dever� incluir novos nomes no arquivo, ler e alterar nomes que estejam armazenados.
Solu��o:
#include <stdio.h>
#include <string.h>
/* -------- Definicao dos tipos a serem usados */
typedef struct tipo_endereco /* Tipo tEndereco: */
{ /* Dados relativos ao endereco */
char rua [50];
int numero;
char bairro [20];
char cidade [30];
char sigla_estado [4];
long int CEP;
} tEndereco;
typedef struct ficha_pessoal /* Tipo tPessoal: */
{ /* Dados da pessoa */
char nome [50];
/* A ficha da pessoa sera */
char telefone[20]; /* uma variavel do tipo tPessoal */
tEndereco endereco;
} tPessoal;
typedef struct _lista /* Tipo tLista: */
{
/* Armazena uma lista de fichas. */
tPessoal *fichas; /* *Nao* e uma implementacao */
int tamanho; /* de uma lista encadeada */
} tLista;
/* ----------- Prototipos das funcoes */
tLista
ad_reg(tLista);
void find(tLista);
void altera(tLista);
tLista le_arquivo(FILE *);
void salva(FILE *, tLista);
void le_reg(tPessoal *);
void le_str(char *s, int n, FILE *arq);
void imprime(tPessoal);
/* ----------------------------------------------------------
Programa principal
---------------------------------------------------------- */
void main(void)
{
char n_arq[30]; /* Nome do arquivo a ser manipulado */
FILE *fonte; /* Arquivo a ser manipulado */
int opcao; /* Opcao escolhida no Menu */
tLista lista; /* Lista de registros (ver definicao de tLista
*/
char c; /* Utilidade geral */
printf("\n\n Gerenciador de dados: Versao 1.0");
printf("\n --------------------------------");
/* --> Le o nome da lista com a qual vai trabalhar */
do
{
printf("\n\n Entre com o nome do arquivo de dados: ");
gets(n_arq);
fonte =
fopen(n_arq, "r");
}
while (fonte == NULL);
/* --> Le o arquivo e guarda na memoria */
lista = le_arquivo(fonte);
fclose(fonte);
if (lista.fichas == NULL)
{
printf("\nErro! Nao e possivel ler e armazenar a lista!!");
exit(0);
}
/* --> Comeca o loop principal */
do
{
printf("\n\n 1 - Insere novo registro");
printf("\n 2 - Procura registro gravado");
printf("\n 3 - Altera registro");
printf("\n 0 - Abandona a execucao");
printf("\n\n Entre com sua opcao: ");
scanf("%d%c", &opcao, &c); /* Le a opcao */
switch(opcao)
{
case 1:
lista = ad_reg(lista);
break;
case 2:
find(lista);
break;
case 3:
altera(lista);
break;
}
}
while (opcao != 0);
/* --> Salva arquivo na saida */
if ((fonte = fopen(n_arq, "w")) != NULL)
{
salva(fonte, lista);
fclose(fonte);
}
else
printf("\n\nERRO! Alteracoes nao foram salvas!!\n");
}
/* ---------------------------------------------------------
Definicao das funcoes:
--------------------------------------------------------- */
/* ---------------------------------------------------------
Funcao ad_reg: Adiciona um registro a lista
Para tanto, ela cria uma segunda lista com o novo registro
no topo e os demais sao copiados nas posicoes seguintes. */
tLista ad_reg(tLista lista)
{
tPessoal ficha;
tLista nova_lista;
int i;
/* Le o novo registro */
printf("\n\n---------Inserir Registro:");
le_reg(&ficha);
/* Primeiro aloca a memoria necessaria para a nova lista... */
nova_lista.tamanho = lista.tamanho + 1;
if ((nova_lista.fichas = (tPessoal *) calloc(nova_lista.tamanho, sizeof(tPessoal))) == NULL)
{
printf("\n\nProblemas de memoria: Impossivel acrescentar o registro..\n");
return lista;
}
/* Copia o novo registro... */
memcpy(&(nova_lista.fichas[0]), &ficha, sizeof(tPessoal));
/* Copia os registros antigos... */
for( i=1; i<nova_lista.tamanho; i++)
memcpy(&(nova_lista.fichas[i]), &(lista.fichas[i-1]), sizeof(tPessoal));
/* Libera a
memoria da primeira lista.. */
free(lista.fichas);
/* retorna a nova lista */
return nova_lista;
}
/* -------------------------------------------------------
Funcao find: Encontra uma expressao de procura na lista.
A expressao sera comparada somente com o campo nome. */
void find(tLista lista)
{
int i,
resp = -1;
char exp[50], *s;
/* Solicita a expressao de busca */
printf("\n\nDigite a expressao de busca: ");
gets(exp);
if ((s = strchr(exp, '\n')) != NULL) /* retira o \n se houver */
s[0] = '\0';
/* Varre a lista procurando a primeira ocorrencia da expressao */
for(i=0; i<lista.tamanho; i++)
if ((strstr(lista.fichas[i].nome, exp)) != NULL)
{
resp = i;
break;
}
if (resp < 0)
printf("\nExpressao nao encontrada.");
else
{
printf("\nExpressao encontrada no registro %d", resp+1);
imprime(lista.fichas[resp]);
}
}
/* --------------------------------------------------------
Funcao altera: altera um registro baseado na sua posicao
na lista. Para fazer a alteracao, a pessoa devera saber qual
posicao do registro na lista (pode ser conseguida atraves da
funcao find, acionada pela opcao 1 do menu).
A funcao altera le o novo registro do teclado e
o substitui
na posicao desejada. */
void altera(tLista lista)
{
int n;
char c;
tPessoal aux;
printf("\nDigite o numero do registro que deseja alterar: ");
scanf("%d%c", &n, &c); /* Le o numero do registro e o lixo do buffer */
/* Le o novo registro */
printf("\nDigite o novo registro:\n");
le_reg(&aux);
/* Atualiza na lista */
memcpy(&(lista.fichas[n-1]), &aux, sizeof(tPessoal));
printf("\nRegistro alterado.\n");
}
/* ---------------------------------------------------------
Funcao le_arquivo: Recebe um apontador para o arquivo aberto
e retorna uma lista montada a partir do arquivo */
tLista le_arquivo(FILE *arq)
{
tLista l;
tPessoal ficha;
int i;
char c, *s;
/* Le o tamanho do arquivo (qtos registros possui) */
fscanf(arq,"%d",
&(l.tamanho));
/* Aloca a memoria necessaria para armazenar o arquivo
em RAM e em seguida le registro por registro */
if ((l.fichas = (tPessoal *) calloc(l.tamanho, sizeof(tPessoal))) != NULL)
for (i=0; i<l.tamanho; i++)
{
/* Le cada ficha */
c = getc(arq); /* Para o cursor mudar de linha no
arquivo */
le_str(ficha.nome, 50, arq);
le_str(ficha.telefone, 20, arq);
le_str(ficha.endereco.rua, 50, arq);
fscanf(arq,"%d\n", &(ficha.endereco.numero));
le_str(ficha.endereco.bairro, 20, arq);
le_str(ficha.endereco.cidade, 30, arq);
le_str(ficha.endereco.sigla_estado, 3, arq);
fscanf(arq,"%d", &(ficha.endereco.CEP));
while ((c = getc(arq)) !='$'); /* Sincronismo! */
memcpy(&(l.fichas[i]), &ficha, sizeof(tPessoal));
if (feof(arq)) i = l.tamanho;
}
/* retorna a lista criada */
return l;
}
/* -----------------------------------------------------------
Funcao salva: salva a lista l no arquivo arq, observando a
sintaxe necessaria para o arquivo de leitura. Ao final,
libera a memoria da lista
*/
void salva(FILE *arq, tLista l)
{
int i;
fprintf(arq,"%d\n", l.tamanho);
for (i = 0; i<l.tamanho; i++)
{
fprintf(arq,"%s\n", l.fichas[i].nome);
fprintf(arq,"%s\n", l.fichas[i].telefone);
fprintf(arq,"%s\n", l.fichas[i].endereco.rua);
fprintf(arq,"%d\n", l.fichas[i].endereco.numero);
fprintf(arq,"%s\n", l.fichas[i].endereco.bairro);
fprintf(arq,"%s\n", l.fichas[i].endereco.cidade);
fprintf(arq,"%s\n", l.fichas[i].endereco.sigla_estado);
fprintf(arq,"%d\n", l.fichas[i].endereco.CEP);
fprintf(arq,"$\n");
}
free(l.fichas);
}
/* -----------------------------------------------------------
Funcao
le_reg: le um registro via teclado */
void le_reg(tPessoal *reg)
{
tPessoal ficha;
char c;
printf("\n\nNome: ");
gets(ficha.nome);
printf("Telefone: ");
gets(ficha.telefone);
printf("\nEndereco");
printf("\nRua: ");
gets(ficha.endereco.rua);
printf("Numero: ");
scanf("%d", &(ficha.endereco.numero));
scanf("%c", &c); /* Para absorver o \n que fica no buffer */
printf("Bairro: ");
gets(ficha.endereco.bairro);
printf("Cidade: ");
gets(ficha.endereco.cidade);
printf("Sigla do Estado: ");
gets(ficha.endereco.sigla_estado);
printf("CEP: ");
scanf("%d", &(ficha.endereco.CEP));
scanf("&c", &c);
memcpy(reg, &ficha, sizeof(tPessoal));
}
/* ----------------------------------------------------------
Funcao le_str: le uma string em um arquivo e faz as
devidas correcoes.
Se a string lida possuir um final de linha ('\n'), a funcao
o localiza e o
retira */
void le_str(char *s, int n, FILE *arq)
{
fgets(s, n, arq);
if ((s = strchr(s, '\n')) != NULL)
s[0] = '\0';
}
/*
----------------------------------------------------------
Funcao imprime: Imprime Uma ficha na tela */
void imprime(tPessoal f)
{
printf("\n%s\n", f.nome);
printf("%s\n", f.telefone);
printf("%s\n", f.endereco.rua);
printf("%d\n", f.endereco.numero);
printf("%s\n",
f.endereco.bairro);
printf("%s\n", f.endereco.cidade);
printf("%s\n", f.endereco.sigla_estado);
printf("%d\n\n", f.endereco.CEP);
}
Coment�rios:
Alguns pontos que merecem especial aten��o:
- Fun��es desconhecidas: Algumas fun��es usadas neste programa nunca foram usadas em nosso curso:
+ strchr(char *s, char c): Esta fun��o retorna um apontador para a primeira ocorr�ncia
de c em s, ou NULL caso n�o encontre.
+ strstr(char *s1, char *s2): Retorna um apontador para a primeira ocorr�ncia da cadeia s2 em s1, ou NULL, se n�o encontrar.
- Como j� mencionamos, o n�vel de complexidade de um programa aumenta a medida que ele cresce. Este programa tem em torno de 250 linhas, e eh um programa que precisa ser largamente testado, para se ter a garantia de que funciona.
- Uma alternativa de solu��o para este
problema, muito melhor que a apresentada utilizaria uma "lista encadeada", que � uma estrutura de dados din�mica, onde cada registro possui um apontador para o pr�ximo registro. Antes que alguem pergunte porque isto n�o foi usado, adianto que foi pelo simples fato de que este assunto fugiria ao escopo do curso.
Curso de C do CPDEE/UFMG - 1996-1999