Curso de C

Estruturas - Segunda parte


Atribuindo

Podemos atribuir duas estruturas que sejam do mesmo tipo. O C irá, neste caso, copiar uma estrutura, campo por campo, na outra. Veja o programa abaixo:

struct est1 {
    int i;
    float f;
};

void main()
{
    struct est1 primeira, segunda;         /* Declara primeira e segunda como structs do tipo est1 */
           primeira.i = 10;
    primeira.f = 3.1415;

    segunda = primeira;                             /* A segunda struct e' agora igual a primeira */
    printf(" Os valores armazenasdos na segunda struct sao :  %d  e  %f ", segunda.i , segunda.f);
}

São declaradas duas estruturas do tipo est1, uma chamada primeira e outra chamada segunda. Atribuem-se valores aos dois campos da struct primeira.   Os valores de primeira são copiados em segunda apenas com a expressão de atribuição:

segunda = primeira;

Todos os campos de primeira serão copiados na segunda. Note que isto é diferente do que acontecia em vetores, onde, para fazer a cópia dos elementos de um vetor em outro, tínhamos que copiar elemento por elemento do vetor. Nas structs é muito mais fácil!

Porém, devemos tomar cuidado na atribuição de structs que contenham campos ponteiros. Veja abaixo:

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

struct tipo_end
{
	char *rua;     /* A struct possui um campo que é um ponteiro */
	int numero;
};

void main()
{
   struct tipo_end end1, end2;
   char buffer[50];
   printf("\nEntre o nome da rua:");
   gets(buffer);         /* Le o nome da rua em uma string de buffer */
   end1.rua = (char *) malloc((strlen(buffer)+1)*sizeof(char));  /* Aloca a quantidade de memoria
   							suficiente para armazenar a string */
   strcpy(end1.rua, buffer);   /* Copia a string */
   printf("\nEntre o numero:");
   scanf("%d", &end1.numero);

   end2 = end1;      	/* ERRADO end2.rua e end1.rua estao apontando para a mesma regiao de memoria */

   printf("Depois da atribuicao:\n Endereco em end1 %s %d  \n Endereco em end2 %s %d", end1.rua,end1.numero,end2.rua, end2.numero);

   strcpy(end2.rua, "Rua Mesquita"); 		/* Uma modificacao na memoria apontada por end2.rua causara' a modificacao do
 						que e' apontado por end1.rua, o que, esta' errado !!!	*/
   end2.numero = 1100;				/* Nesta atribuicao nao ha problemas */

   printf(" \n\nApos modificar o endereco em end2:\n Endereco em end1 %s %d \n Endereco em end2 %s %d", end1.rua, end1.numero, end2.rua, end2.numero);
}

 

Neste programa há um erro grave, pois ao se fazer a atribuição end2 = end1, o campo rua de end2 estará apontando para a mesma posição de memória que o campo rua de end1. Assim, ao se modificar o conteúdo apontado por end2.rua estaremos também modificando o conteúdo apontado por end1.rua !!!

Passando para funções

No exemplo apresentado no ítem usando, vimos o seguinte comando:

strcpy (ficha.nome,"Luiz Osvaldo Silva");

Neste comando um elemento de uma estrutura é passado para uma função. Este tipo de operação pode ser feita sem maiores considerações.

Podemos também passar para uma função uma estrutura inteira. Veja a seguinte função:

void PreencheFicha (struct ficha_pessoal ficha)
{
...
}

Como vemos acima é fácil passar a estrutura como um todo para a função. Devemos observar que, como em qualquer outra função no C, a passagem da estrutura é feita por valor. A estrutura que está sendo passada, vai ser copiada, campo por campo, em uma variável local da função PreencheFicha. Isto significa que alterações na estrutura dentro da função não terão efeito na variável fora da função. Mais uma vez podemos contornar este pormenor usando ponteiros e passando para a função um ponteiro para a estrutura.

Ponteiros

Podemos ter um ponteiro para uma estrutura. Vamos ver como poderia ser declarado um ponteiro para as estruturas de ficha que estamos usando nestas seções:

struct ficha_pessoal *p;

Os ponteiros para uma estrutura funcionam como os ponteiros para qualquer outro tipo de dados no C. Para usá-lo, haveria duas possibilidades. A primeira é apontá-lo para uma variável struct já existente, da seguinte maneira:

struct ficha_pessoal ficha;

struct ficha_pessoal *p;

p  = &ficha;

A segunda é alocando memória para  ficha_pessoal usando, por exemplo, malloc():

#include <stdlib.h>

main()
{
    struct ficha_pessoal *p;
    int a = 10; /* Faremos a alocacao dinamica de 10 fichas pessoais */
    p = (struct ficha_pessoal *) malloc (a * sizeof(struct ficha_pessoal));
    p[0].telefone = 3443768;             /* Exemplo de acesso ao campo telefone da primeira ficha apontada por p */
    free(p);
}

Há mais um detalhe a ser considerado. Se apontarmos o ponteiro p  para uma estrutura qualquer (como fizemos em p  = &ficha; ) e quisermos acessar um elemento da estrutura poderíamos fazer:

(*p).nome

Os parênteses são necessários, porque o operador . tem precedência maior que o operador * . Porém, este formato não é  muito usado. O que é comum de se fazer é acessar o elemento nome através do operador seta, que é formado por um sinal de "menos" (-) seguido por um sinal de "maior que" (>), isto é: -> . Assim faremos:

p->nome

A declaração acima é muito mais fácil e concisa. Para acessarmos o elemento CEP dentro de endereco faríamos:

p->endereco.CEP

Fácil, não?


AUTO AVALIAÇÃO

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.


left.gif (1505 bytes)Índice da Aula Próxima página


Curso de C do CPDEE/UFMG - 1996 - 1999