Prévia do material em texto
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: 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: #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 100 typedef 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; } 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