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