50
FACULDADE DE ENGENHARIA DE SOROCABA LINGUAGEM DE PROGRAMAÇÃO Módulo 2 – Alocação Dinâmica e Estruturas PROFª. ANDRÉA

apostila de programação em c - Estrura de dados

Embed Size (px)

DESCRIPTION

para entendimento de estrutura de dados em C, como elaborar e exemplos para criação de programas em linguagem c

Citation preview

FACULDADE DE ENGENHARIA DE SOROCABA

FACENS Linguagem de Programao MDULO 2 Prof. Andra

FACULDADE DE ENGENHARIA DE SOROCABA

LINGUAGEM DE PROGRAMAO

Mdulo 2 Alocao Dinmica e EstruturasPROF. ANDRA

35.ALOCAO DINMICA

35.1 - Introduo

35.2 - Alocando Espao durante a Execuo do Programa

35.3 - Heap

35.4 - Funo malloc( )

65.5 - Funo calloc( )

75.6 - Funo realloc( )

85.7 - Funo free( )

95.8 Alocao de Memria na Main X na Funo

145.9 Exerccios Propostos

156.ESTRUTURAS

156.1 Introduo

156.2 Definindo um Tipo Estrutura

166.3 - Declarando as Variveis do Tipo Estrutura

176.4 - Definindo e Declarando Estruturas

186.5 - Acessando Membros da Estrutura

186.6 - Mltiplas Estruturas de Mesmo Tipo

196.7 - Definio de Estruturas Sem Rtulo ou Etiqueta

196.8 - Estruturas que Contm Matrizes

206.9 Exemplo - Criando uma Lista de Livros

216.10 - Inicializando Estruturas

226.11 - Atribuies entre Estruturas

226.12 - Estruturas Aninhadas - Estruturas que contm Estruturas

236.13 - Matrizes de Estruturas

256.14 - Inicializando Estruturas Complexas

266.15 Exerccios Propostos

277.ESTRUTURAS COMPLEXAS

277.1 - Estruturas e Ponteiros

277.2 - Ponteiros para Estruturas

287.2.1 - Operador de Acesso Indireto

287.2.2 - Operador de Indireo (*)

287.2.3 - Nome da Estrutura

297.3 - Ponteiros e Matrizes de Estruturas

317.4 - Passando Estruturas como Argumentos para Funes

337.5 Estruturas e Alocao Dinmica

357.6 Exerccios Propostos

5. ALOCAO DINMICA

5.1 - Introduo

A nica finalidade das variveis simples e matrizes alocar espao suficiente na memria para armazenar valores. E se pudssemos encontrar algum espao disponvel na memria sem ter que criar uma varivel? Nesse caso, poderamos us-lo para armazenar diretamente os valores e bastaria um ponteiro que indicasse a posio do primeiro valor e uma varivel que indicasse a quantidade de elementos armazenados, exatamente como a matriz previamente definida. Mas como fazer para localizar reas de memria disponveis para armazenagem ? Usa-se funes para alocar espao na memria enquanto o programa est sendo executado um processo conhecido como "alocao dinmica".

5.2 - Alocando Espao durante a Execuo do Programa

H funes de alocao da memria em C. Ao chamar estas funes, voc deve especificar o nmero de bytes necessrios, a funo localiza e reserva um bloco de memria no tamanho apropriado e retorna o endereo do primeiro byte desse bloco.

Esse tipo de funo retorna um endereo, e seu tipo de retorno um ponteiro para o tipo void. Por que void ? Porque um ponteiro para dados do tipo void compatvel com todos os tipos de dados, i.e., ele genrico. Como a memria alocada pode ser usada para armazenar qualquer dos tipos de dados vlidos em C, o tipo de retorno void o mais apropriado.

5.3 - Heap

O heap ou rea de alocao dinmica consiste de toda a memria disponvel que no foi usada para um outro propsito. Em outras palavras, o heap simplesmente o resto da memria.

A linguagem C oferece um conjunto de funes que permitem a alocao ou liberao dinmica de memria do heap, como : malloc( ), calloc( ), realloc( ) e free( ).

5.4 - Funo malloc( )

Arquivo de cabealho:stdlib.h

sintaxe:

void*malloc(tamanho);

onde:

tamanho corresponde a um inteiro sem sinal, que representa a quantidade em bytes de memria requerida.

A cada chamada de malloc( ) devemos inform-la do tamanho do bloco que queremos guardar. Esta informao pode ser conhecida do programador ou podemos utilizar o operador unrio chamado sizeof( ), que fornece um inteiro, igual ao tamanho, em bytes, da varivel ou do tipo do dado em questo.

A funo malloc( ) retorna um ponteiro para o primeiro byte do bloco de memria alocado. Quando incapaz de alocar a quantidade solicitada de memria, seu retorno nulo (NULL). Sempre que tentarmos alocar memria, mesmo que seja uma pequena quantidade, devemos verificar o valor de retorno.

Por exemplo, podemos usar malloc( ) para alocar a memria para armazenar uma nica varivel do tipo int. Em primeiro lugar, declaramos um ponteiro para o tipo int:

int*ptr;

A seguir, chamamos malloc( ) passando o tamanho do bloco de memria desejado. Como um tipo int ocupa 4 bytes, precisamos de um bloco de 4 bytes. O valor retornado por malloc ( ) atribudo ao ponteiro:

ptr = (int*) malloc(sizeof(int*));

Esta instruo aloca um bloco de memria com 4 bytes e atribui o endereo inicial ao ponteiro ptr. Ao contrrio das variveis que so declaradas no programa, esse bloco de memria no tem qualquer nome e s pode ser referenciado atravs do ponteiro. Por exemplo, para armazenar o valor 10 nesse bloco, devemos escrever:

*ptr = 10;

A alocao de matrizes usando malloc( ) quase idntica a de uma nica varivel do tipo int. A principal diferena que precisamos saber antecipadamente quantos bytes devero ser alocados - ou seja, qual ser o nmero mximo de valores na matriz. Esse valor mximo depende das necessidades do programa. Para exemplificar, iremos alocar uma matriz com 100 valores, o que resulta em 400 bytes. Em primeiro lugar, teramos que declarar um ponteiro para o tipo int, e depois chamar malloc( ).

int *ptr;

ptr = (int *) malloc(400);

Agora ptr est apontando para um bloco reservado de 400 bytes, que pode ser usado para a armazenagem e manipulao de inteiros. Podemos usar o ponteiro ptr exatamente como faramos se o programa tivesse alocado explicitamente o mesmo espao atravs de uma declarao de matriz:

int mat[100];

O uso de malloc( ) permite que o programa aloque espao conforme seja necessrio. Evidentemente, o espao disponvel para armazenagem no ilimitado; ele depende tanto da quantidade de memria instalada no computador quanto das outras necessidades de armazenagem do prprio programa. Se a memria disponvel no for suficiente, malloc( ) retornar um valor 0 (nulo). Portanto, devemos testar o valor de retorno de malloc ( ) para ter certeza de que a memria solicitada foi alocada adequadamente. O valor de retorno de malloc( ) deve sempre ser testado contra a constante simblica NULL que definida em STDLIB.H.

Obs.:1)Nunca devemos presumir que a funo malloc ( ) tenha conseguido reservar a memria que lhe pedimos. Pois de fato, no ordenamos funo que aloque memria; apenas lhe perguntamos se isso pode ser feito.

2)O que significa a expresso (char *) ou (int *) ou (float *) precedendo malloc( ) ?

A funo malloc( ) retorna um ponteiro para o tipo void, portanto esse ponteiro deve ser moldado para o tipo apropriado antes de ser usado. E para isso usamos a converso de tipos, na verdade um operador unrio chamado operador de molde, que consiste em colocar um parnteses envolvendo o tipo de dado desejado.

Ex.:A funo sqrt( ), retorna a raiz quadrada de um nmero do tipo double e temos uma varivel float:

floatn;

double resposta;

resposta = sqrt ((double)n);

/* converte n antes de us-lo na funo sqrt */

Portanto, devemos indicar que o valor retornado por malloc( ) ser do tipo ponteiro para char ou int ou float.

Exemplo 1 aloca memria para uma matriz com 50 valores do tipo int.

include

include

int *numeros;

main( )

{

if( (numeros = (int *) malloc(50 * sizeof(int) ) ) = = NULL)

printf("Espao insuficiente para alocar buffer \n");

else

printf("Matriz foi alocada");

}/* main */

Exemplo 2 aloca memria para uma matriz com 10 valores do tipo float.

include

include

float *numeros;

main( )

{

if( (numeros = (float *) malloc(10 * sizeof(float) ) ) = = NULL)

printf("Espao insuficiente para alocar buffer \n");

else

printf("Matriz foi alocada");

}/* main */

( O ponteiro ptr aponta para o valor inicial (letra A) e utilizamos outro ponteiro p para inserir valores no espao reservado, ou seja, incrementamos p e preservamos ptr, caso contrrio perderamos o valor inicial da memria alocada. Devemos lembrar que este bloco de memria no contm nome, e o programa apenas sabe onde ele se encontra.

5.5 - Funo calloc( )

A funo calloc ( ) ao invs de alocar um grupo de bytes como malloc ( ), ela aloca memria para um grupo de objetos.

Arquivo de cabealho:stdlib.h

sintaxe:

void*calloc(num, tamanho);

onde:

num - corresponde a um inteiro sem sinal, o nmero de objetos para os quais a memria deve ser alocada.

tamanho - corresponde a um inteiro sem sinal, o tamanho de cada objeto em bytes.

Se a alocao for bem-sucedida, toda a memria alocada inicializada com o valor 0 e a funo retorna um ponteiro para void para o primeiro byte. Se a alocao fracassar ou se num ou size forem iguais a zero, a funo retorna NULL.

( Devemos usar o operador molde se quisermos um ponteiro para um tipo diferente.

Exemplo 1 - aloca memria para 100 elementos do tipo longlong*ptr;

ptr = (long *) calloc (l00, sizeof (long));

if(ptr = = NULL)

printf("Espao insuficiente \n");

else

printf("Memoria alocada");

O primeiro argumento o nmero de clulas de memria desejada. O segundo argumento o tamanho de cada clula em bytes.

Neste caso, long usa quatro bytes, ento esta instruo alocar espao para 100 unidades de quatro bytes ou seja 400 bytes.

Exemplo 2 programa que aloca a quantidade de variveis int estipulada pelo usurio.

#include

#include

main()

{

unsigned num;

int *ptr;

printf("Digite o numero de variveis do tipo int: ");

scanf("%i", &num);

ptr = (int *) calloc(num, sizeof(int));

if (ptr != NULL)

puts("Memria alocada sem problemas.");

else

puts("Erro na alocao de memria.");

}

Este programa recebe um valor do usurio. Esse nmero determina a quantidade de espao a ser alocado. O programa tenta alocar memria suficiente para conter o nmero especificado de variveis. Se a alocao fracassar, o valor de retorno de calloc( ) NULL; caso contrrio, um ponteiro para a rea de memria alocada. Neste programa, o valor de retorno de calloc ( ) colocado em um ponteiro para o tipo int chamado ptr. Uma instruo if verifica o resultado da alocao com base no valor de ptr e imprime uma mensagem apropriada.

Digite diferentes valores e veja qual o mximo de memria que voc consegue alocar sem problemas. Esse limite depende, at certo ponto, da configurao do sistema. Em alguns sistemas, a alocao de espao para at 25.000 ocorrncias do tipo int feita sem problemas, mas a alocao de espao para 30.000 fracassa.

5.6 - Funo realloc( )

Muda o tamanho de um bloco de memria que tenha sido alocado anteriormente com malloc( ) ou calloc( ).

Arquivo de cabealho:stdlib.h

sintaxe:

void*realloc(*ptr, tamanho);

onde:

ptr corresponde a um ponteiro para o tipo void, aponta para o bloco original de memria.

tamanho - corresponde a um inteiro sem sinal, especifica o novo tamanho desejado, em bytes.

Os resultados possveis do uso realloc( ) so:

se houver espao suficiente para expandir o bloco de memria referenciado por ptr, a memria adicional alocada e a funo retorna ptr.

se no houver espao suficiente para expandir o bloco atual, um novo bloco do tamanho especificado em tamanho alocado e os dados existentes so copiados do bloco original para o incio do novo bloco. A seguir, o bloco original liberado e a funo retorna um ponteiro para o novo bloco.

se o argumento ptr for NULL, a funo atua como malloc( ), alocando um bloco de tamanho bytes e retornando um ponteiro para ele.

se o argumento tamanho for 0, a memria indicada por ptr liberada e a funo retorna NULL.

se no houver memria suficiente para a realocao (tanto expandindo o bloco original quanto alocando um novo bloco), a funo retorna NULL e o bloco original permanece inalterado.

5.7 - Funo free( )

Ao usarmos malloc( ), calloc( ) ou realloc( ) alocamos parte do total de memria dinmica disponvel para o programa. Esse total, que costuma ser chamado de heap, finito. Portanto, quando o programa j no estiver utilizando algum bloco da memria alocada, aconselhamos desalocar", ou liberar, essa memria, tornando-a disponvel para alocaes futuras. Para liberarmos a memria que foi alocada dinamicamente, usamos a funo free ( ).

Arquivo de cabealho:stdlib.h

sintaxe:

void free (*ptr);

onde:

ptr corresponde a um ponteiro para o tipo void, aponta para o incio do bloco de memria a ser liberado.

A funo free ( ) libera a memria referenciada por ptr. Essa memria deve ter sido alocada usando malloc( ), calloc( ) ou realloc( ). Se ptr for NULL, free ( ) no faz nada.

A funo free( ) declara o seu argumento como um ponteiro para void. A vantagem desta declarao que ela permite que a chamada funo seja feita com um argumento ponteiro para qualquer tipo de dado.

Exemplo1 - libera memria alocada por funo desenvolvida em calloc( ).

liberamem()

{

long *ptr, *alocamem();

ptr = alocamem();

/* alocamem() - funo que aloca memria usando calloc( ) - exemplo2 */

free(ptr);

}

Exemplo2 - este programa tenta alocar dois blocos de memria.

#include

#include

#include

#define TAMBLOCO 30000

main( )

{

void *ptrl, *ptr2;

ptr1 = malloc(TAMBLOCO);

/* tenta alocar o 1 bloco */

if (ptr1 = = NULL)

printf("\n Tentativa de alocar %i bytes falhou", TAMBLOCO);

else

{

printf("\n Primeira alocao de %i bytes realizada", TAMBLOCO);

ptr2 = malloc(TAMBLOCO);

/* tenta alocar o 2 bloco */

if (ptr2 != NULL)

printf("\n Segunda alocao de %i bytes realizada", TAMBLOCO);

else

{

printf("\n Segunda tentativa de alocar %i bytes falhou", TAMBLOCO);

free (ptr1);

printf("\n Liberando o primeiro bloco);

ptr2 = malloc(TAMBLOCO);

if (ptr2 != NULL)

printf("\n Depois de free(), alocao de %i bytes realizada", TAMBLOCO);

}/* else */

}/* else */

}/* main */

Este programa tenta alocar dinamicamente dois blocos de memria, usando a constante TAMBLOCO para determinar o tamanho de cada bloco. Porm, a 2 alocao s ocorrer se a 1 for bem sucedida.

ptr1 corresponde a 1 alocao. Determinamos o resultado da alocao verificando se o valor de retorno foi NULL. Se a alocao no foi bem sucedida (valor de retorno = NULL) o programa encerrado. Caso contrrio, tentaremos alocar um 2 bloco de memria.

ptr2 corresponde a 2 alocao. Novamente verificamos o resultado, porm agora se o procedimento foi bem sucedido (valor de retorno diferente de NULL). Se a 2 alocao ocorreu sem problemas, o programa finalizado, caso contrrio, o primeiro bloco liberado com free ( ) e feita uma nova tentativa de alocao.

5.8 Alocao de Memria na Main X na FunoPara alocarmos memria dinamicamente na main, devemos declarar um ponteiro e utilizar malloc(), calloc() ou realloc(). Porm, quando utilizamos funo, devemos lembrar que a memria no pode ser conhecida apenas na funo, mas tambm na main. Portanto, devemos declarar um ponteiro na main e a funo pode ser feita de 2 formas:

Chamada por Referncia devemos passar o endereo do ponteiro declarado na main, portanto, a funo receber como parmetro ponteiro para ponteiro.

Chamada por Valor s conseguimos trabalhar dessa forma, se a funo retornar o endereo alocado para o ponteiro declarado na main, permitindo assim, o acesso deste memria alocada. Caso contrrio o ponteiro na main continuar NULL e ao sairmos da funo perdemos a referncia da memria alocada. Lembre-se que as variveis (inclusive ponteiro) declaradas dentro da funo, deixam de existir assim que a funo termina.Verso utilizando Chamada por Referncia#include

#include

void aloca(int **p, int tam);

//passa o endereo do ponteiro declarado na mainmain( )

{

int *ptr=NULL;

printf("\nAloca memoria na Funcao e na Main\n");

printf("\nChamada por Referencia - passa ENDERECO do ponteiro\n");

printf("\nFuncao main - antes de alocar");

printf("\nEndereco ptr = %u \nConteudo %u = %u",&ptr,&ptr,ptr);

aloca(&ptr, 1);

//chamada por referencia

printf("\n\nFuncao main - depois de alocar");

printf("\nEndereco ptr = %u \nConteudo %u = %u\n\n\n",&ptr,&ptr,ptr);

system("pause");

}//mainvoid aloca(int **p, int tam)

{

printf("\n\nFuncao aloca - antes de alocar");

printf("\nEndereco p = %u \tConteudo p = %u (Endereco ptr)",&p,p);

printf("\nConteudo %u = %u\n",p,*p);

if((*p=(int*)realloc(*p, tam*sizeof(int)))== NULL)

{

printf("Erro de alocacao");

exit(1);

}

printf("\n\nFuncao aloca - depois de alocar");

printf("\nEndereco p = %u \tConteudo p = %u (Endereco ptr)",&p,p);

printf("\nConteudo %u = %u\n",p,*p);

}//alocaVerso utilizando Chamada por Valor com RETORNO do endereo alocado#include

#include

int*aloca(int *p, int tam);

//retorna o endereo da memria alocadamain()

{

int *ptr=NULL;

printf("\nAloca memoria na Funcao e RETORNA para a Main\n");

printf("\nChamada por Valor - passa CONTEUDO do ponteiro\n");

printf("\nFuncao main - antes de alocar");

printf("\nEndereco ptr = %u \nConteudo %u = %u",&ptr,&ptr,ptr);ptr = aloca(ptr, 1);

//chamada por valorprintf("\n\nFuncao main - depois de alocar");

printf("\nEndereco ptr = %u \nConteudo %u = %u\n\n\n",&ptr,&ptr,ptr);system("pause");

}//mainint*aloca(int *p, int tam)

{

printf("\n\nFuncao aloca - antes de alocar");

printf("\nEndereco p = %u \nConteudo p = %u (Conteudo ptr)",&p,p);

if((p=(int*)realloc(p, tam*sizeof(int)))== NULL)

{

printf("Erro de alocacao");

exit(1);

}

printf("\n\nFuncao aloca - depois de alocar");

printf("\nEndereco p = %u \nConteudo p = %u (Conteudo ptr)",&p,p);

}//alocaERRO: Verso utilizando Chamada porValor sem RETORNO do endereo alocado#include

#include

void aloca(int *p, int tam);

//NO retorna o endereo da memria alocadamain()

{

int *ptr=NULL;

printf("\nERRO pois aloca memoria apenas na Funcao e nao na Main\n");

printf("\nChamada por Valor - passa CONTEUDO do ponteiro\n");

printf("\nFuncao main - antes de alocar");

printf("\nEndereco ptr = %u \nConteudo %u = %u",&ptr,&ptr,ptr);

aloca(ptr, 1);

//chamada por valor

printf("\n\nFuncao main - depois de alocar");

printf("\nEndereco ptr = %u \nConteudo %u = %u\n\n\n",&ptr,&ptr,ptr); //ptr continua NULLsystem("pause");

}//mainvoid aloca(int *p, int tam)

{

printf("\n\nFuncao aloca - antes de alocar");

printf("\nEndereco p = %u \nConteudo p = %u (Conteudo ptr)",&p,p);

if((p=(int*)realloc(p, tam*sizeof(int)))== NULL)

{

printf("Erro de alocacao");

exit(1);

}

printf("\n\nFuncao aloca - depois de alocar");

printf("\nEndereco p = %u \nConteudo p = %u",&p,p);

}//alocaExemplo de Alocao de Memria na Main X na Funo

Alocar espao para 10 nmeros inteiros. Mostrar o endereo e receber do usurio os valores. Em seguida mostrar novamente o endereo e o respectivo valor de cada elemento.Verso para Alocao feita na main( )

#include

#include

void recebe (int *p, int tam);

void imprime (int *p, int tam);

main( )

{int*ptr=NULL;

if((ptr = (int *) realloc(ptr, 10 * sizeof(int))) == NULL)

{

printf(Erro na alocao);

exit(1);

}

recebe(ptr,10);

imprime(ptr,10);

system(pause);}//mainvoid recebe (int *p, int tam)

{

int i;

printf(\nFuncao recebe Digite os valores \n);for(i=0;inumero, p_pea->nome);

scanf(%i,&(p_pea->numero);

E se quisssemos imprimir todos os elementos da matriz? Nesse caso, provavelmente usaramos um loop for. Para acessar os membros usando notao de ponteiros, teramos que alterar o ponteiro p_pea para que, a cada iterao do loop, ele apontasse para o prximo elemento da matriz (ou seja, para a prxima estrutura contida na matriz).

Para isso, a aritmtica de ponteiros da linguagem C pode lhe ser til. O operador unrio de incremento (++) tem um significado especial quando aplicado a um ponteiro, passando a significar "incrementar o ponteiro com um valor equivalente ao tamanho do objeto para o qual ele est apontando". Em outras palavras, se voc tem um ponteiro ptr que aponta para um objeto de dados do tipo obj, a instruo:

ptr++;

tem o mesmo efeito de:

ptr += sizeof (obj);

Os elementos de uma matriz sempre so armazenados seqencialmente na memria. Se um ponteiro estiver apontando para o elemento n de uma matriz, o uso do operador (++) para increment-lo far com que ele passe a apontar para o elemento n+1. Isto ilustrado na figura abaixo, que mostra uma matriz chamada x[ ] que consiste de elementos de quatro bytes (cada elemento pode ser, por exemplo, uma estrutura contendo dois membros do tipo char, cada um dos quais ocupa dois bytes). O ponteiro ptr foi inicializado para apontar para x[0] ; cada vez que incrementado, ptr passa a apontar para o prximo elemento da matriz.

X[0]

x[1]

x[2]

100110021003100410051006100710081009101010111012 .....

1

1

1

0 ptr++

0 ptr++

0

0

0

0

1

5

9

Isto significa que o seu programa pode avanar atravs de uma matriz de estruturas (ou, para ser exato, atravs de uma matriz de qualquer tipo) simplesmente incrementando um ponteiro. Este tipo de notao geralmente mais fcil de usar e mais conciso do que o uso de subscritos de matrizes para realizar a mesma tarefa.

Ex. - acessa elementos sucessivos de uma matriz atravs do incremento de um ponteiro.

#include

#define MAX4

struct pea {

int numero;

char nome[10];

};

main()

{

struct pea*p_pea, dados[MAX] = {1, "camisa",

2, "cala",

3, "gravata",

4, "casaco" };

intcontagem;

p_pea = dados;

// inicializa o ponteiro para o primeiro elemento da matriz

for (contagem = 0; contagem < MAX; contagem++)

{

printf("\n No endereo %u :%i%s", p_pea, p_peca->numero, p_pea->nome ) ;

p_pea++;

}

}// mainTeremos como sada, por exemplo:

No endereo 96: 1camisa

No endereo 120: 2cala

No endereo 144: 3gravata

No endereo 168: 4casaco

Inicialmente, o programa declara e inicializa uma matriz de estruturas chamada dados. A seguir, definido um ponteiro chamado p_pea para apontar para uma estrutura do tipo peas. A primeira tarefa da funo main( ) inicializar o ponteiro p_pea para que ele aponte para a matriz dados declarada anteriormente. A seguir, todos os elementos dessa matriz so impressos na tela usando um loop for que incrementa o ponteiro a cada interao. O programa exibe tambm o endereo de cada elemento da matriz.

Observando os endereos mostrados, percebemos que todos os incrementos sero feitos em quantidades iguais, correspondendo ao tamanho da estrutura peas (na maioria dos sistemas, esse incremento ser de 24 bytes). Isto ilustra claramente o fato de que o incremento de um ponteiro feito com um valor igual ao tamanho do objeto de dados para o qual ele est apontando.

7.4 - Passando Estruturas como Argumentos para Funes

Como qualquer outro tipo de dados, uma estrutura pode ser passada como um argumento para uma funo. O programa abaixo mostra como isso feito.

Ex.:

#include

struct dados{

floatquantia;

charnome[80];

} ;

voidprint_reg (struct dados x);

main( )

{

struct dadosreg;

printf("Digite o nome e o sobrenome do doador: ");

scanf("%s%s", reg.nome, reg..snome);

printf("\n Digite a quantia doada: ");

scanf("%f", &reg.quantia);

print_reg( reg );

}// main

voidprint_reg(struct dados x)

{

printf("\O doador %s doou R$%.2f.", x.nome, x.quantia);

}

Teremos como sada na tela:

Digite o nome e o sobrenome do doador: Carlos Silva

Digite a quantia doada: 1000.00

O doador Carlos Silva doou R$1000.00.

O prottipo da funo dever receber a estrutura, portanto devemos incluir os parmetros adequados. No caso, uma estrutura do tipo dados. As mesmas informaes so repetidas no cabealho da funo. Ao chamarmos a funo, temos que informar o nome da instncia dessa estrutura - no caso, reg. Isso tudo. Passar uma estrutura para uma funo no muito diferente de passar uma varivel simples. Alternativamente, podemos passar uma estrutura para uma funo informando o seu endereo (ou seja, passando um ponteiro que aponte para a estrutura).

De fato, esta era a nica maneira de usarmos uma estrutura como argumento nas verses mais antigas da linguagem C. Isso j no necessrio, mas possvel encontrarmos programas mais antigos que ainda usam esse mtodo. Ao passarmos um ponteiro como argumento para uma funo, teremos que usar o operador de acesso indireto (->) para acessarmos membros da estrutura de dentro da funo.

Ex. Novamente, usaremos o programa de livros, onde uma funo obter informaes dos livros pelo usurio e outra ir imprimi-las.

#include

#include

typedef struct 1ivro {

char titulo[30];

int regnum;

}livro;

livronovonome();

// funo do tipo struct livro chamada novonome

voidlistar (livro liv);

// funo void, cujo parmetro do tipo struct livro

main( )

{

livrolivro1, livro2;

// varivel estrutura chamada livro1, livro2

livro1 = novonome();

// livro1 ir receber o retorno da funo novonome

livro2 = novonome();

// livro2 ir receber o retorno da funo novonome

listar(livro1);

listar(livro2);

} // mainlivronovonome()

{

char numstr[8];

livrolivr;

// varivel estrutura chamada livr

printf("\n Novo livro \n Digite titulo: ");

gets(livr.titulo);

printf("Digite o numero do registro (3 dgitos): );

gets(numstr);

livr.regnum = atoi(numstr);

return(livr);

}// novonome

void listar (livroliv)

{

printf("\n Livro: \n");

printf("Titulo: %s ", liv.titulo);

printf("\n N do registro: %3i", liv.regnum);

} // listar

Visto que as duas funes, como tambm o programa main(), devem conhecer a estrutura livro, ela deve ser definida antes da main().

As funes main(), novonome() e listar() declaram internamente suas prprias variveis estrutura, chamadas livro1 e livro2, livr e liv.

A funo listar() recebe uma cpia da estrutura e a coloca num endereo conhecido somente por ela; no a mesma estrutura declarada em main().

A funo novonome() chamada pelo programa principal para obter informaes do usurio sobre os 2 livros. Esta funo guarda as informaes em uma varivel interna, livr, e retorna o valor desta varivel para o programa principal usando o comando return, exatamente como faria para devolver uma simples varivel. A funo novonome( ) deve ser declarada como sendo do tipo struct livro, visto que ela retorna um valor deste tipo.

O programa principal atribui o valor retornado por novonome() varivel estrutura livro1 e livro2. Finalmente main() chama a funo listar() para imprimir os valores de livro1 e livro2, passando os valores destas duas estruturas para a funo como variveis.

A funo listar() atribui estes valores varivel estrutura interna liv e acessa os elementos individuais desta estrutura para imprimir seus valores.

7.5 Estruturas e Alocao Dinmica

Para alocarmos memria dinamicamente na main, devemos declarar um ponteiro e utilizar malloc(), calloc() ou realloc(). Porm, quando utilizamos funo, devemos lembrar que a memria no pode ser conhecida apenas na funo, mas tambm na main. Portanto, devemos declarar um ponteiro na main e a funo pode ser feita de 2 formas:

Chamada por Referncia devemos passar o endereo do ponteiro declarado na main, portanto, a funo receber como parmetro ponteiro para ponteiro.

Chamada por Valor s conseguimos trabalhar dessa forma, se a funo retornar o endereo alocado para o ponteiro declarado na main, permitindo assim, o acesso deste memria alocada. Caso contrrio o ponteiro na main continuar NULL e ao sairmos da funo perdemos a referncia da memria alocada. Lembre-se que as variveis (inclusive ponteiro) declaradas dentro da funo, deixam de existir assim que a funo termina.

Verso para Alocao feita na main( )

#include

#include

typedef struct 1ivro {

char titulo[30];

int regnum;

}livro;

main( )

{

livro*ptr=NULL;

if((ptr = (livro *) realloc(ptr, 10 * sizeof(livro))) == NULL)// aloca 10 elementos

{

printf(Erro na alocao);

exit(1);

}

}//main

Verso utilizando Chamada por Referncia

#include

#include

typedef struct 1ivro {

char titulo[30];

int regnum;

}livro;

void aloca(livro **p, int tam);

//passa o endereo do ponteiro declarado na main

main( )

{

livro*ptr=NULL;

aloca(&ptr, 10);

//chamada por referencia

}//main

void aloca(livro **p, int tam)

{

if((*p=(livro*)realloc(*p, tam*sizeof(livro)))== NULL)

{

printf("Erro de alocacao");

exit(1);

}

}//aloca

Verso utilizando Chamada por Valor com RETORNO do endereo alocado

#include

#include

typedef struct 1ivro {

char titulo[30];

int regnum;

}livro;

livro*aloca(livro *p, int tam);

//retorna o endereo da memria alocada

main()

{

livro*ptr=NULL;

ptr = aloca(ptr, 10);

//chamada por valor

}//main

livro*aloca(livro *p, int tam)

{

if((p=(livro*)realloc(p, tam*sizeof(livro)))== NULL)

{

printf("Erro de alocacao");

exit(1);

}

return p;

}//aloca

7.6 Exerccios Propostos

1. Dado a estrutura abaixo, implemente uma rotina de cadastro, deve-se consultar o usurio para continuar. O registro deve ser gerado automaticamente pelo sistema. Utilizar alocao dinmica e ponteiros para a estrutura.struct agenda

{

int reg;

char nome[80];

float nota;

};2. Fazer um programa para Sistema de Conta Bancria este programa se destina a controlar as contas de clientes. Consultar o usurio para continuar. Utilizar alocao dinmica e ponteiros para a estrutura.[1] Cadastro - receber os valores digitados pelo usurio. Apenas um registro cadastrado por vez.

[2] Depsito - o acesso deve ser feito atravs do n de conta corrente. Buscar o registro, mostrar o nome do cliente e o saldo para simples conferncia, pedir o valor do depsito, fazer as alteraes e apresentar na tela o saldo atualizado.[3] Retirada - o acesso deve ser feito atravs do n de conta corrente. Buscar o registro, mostrar o nome do cliente e o saldo para simples conferncia, pedir o valor da retirada, fazer as alteraes se possvel (a retirada s ser permitida, se houver saldo suficiente) e apresentar na tela o saldo atualizado.

struct cliente{

char nome[30];

int conta;

float saldo;

};3. Fazer um programa para Dirio Eletrnico este programa se destina a controlar as notas e a mdia dos alunos. Consultar o usurio para continuar. Utilizar alocao dinmica e ponteiros para a estrutura.[1] Cadastro - receber os valores digitados pelo usurio, inicialmente notas e mdia=0. Apenas um registro cadastrado por vez.[2] Controle de Notas - o acesso deve ser feito atravs do RA. Buscar o registro, mostrar o nome do aluno para simples conferncia, fazer as alteraes das notas, calcular a mdia e apresentar na tela as notas e a mdia.struct aluno{

char nome[80];

char RA[79];

float nota[2];

//notas de provas considerar 2 provas

float media;

//mdia aritmtica das provas

};

4. Fazer um programa para Controle de Hotel - este programa se destina a controlar o check-in (cadastro de hspedes) de um hotel. O hotel possui 15 quartos. Utilizar alocao dinmica e ponteiros para a estrutura.[1] Check-in - alocar dinamicamente espao, receber os valores digitados pelo usurio, se o hspede no tiver acompanhantes atribuir categoria Solteiro, caso contrrio Familiar, buscar o nmero do quarto disponvel, de acordo com a categoria na estrutura quartos. Apenas um hspede cadastrado por vez. No esquecer de atualizar o quarto da estrutura quartos para Ocupado.

[2] Check-out encerra a estadia e apresenta o relatrio, de acordo com o quarto. Apenas um registro acessado por vez, buscar e mostrar o nmero do quarto, o nome do hspede, quantidade de acompanhantes, a categoria (Solteiro ou Familiar,o tempo de permanncia em dias e o valor a ser pago.

[3] Fim

Dica:

No check-in - no esquecer de verificar se na estrutura hospede h um espao vago (cujo quarto = -1), se houver o novo hspede dever ser ali armazenado, caso contrrio, acrescentar no final da estrutura.

struct hospede{

int quarto;

// nmero do quarto

char nome[80];

int acompanhante;

// quantidade de acompanhantes

char categoria;

// [S]olteiro / [F]amiliar

int dias;

// tempo de permanncia em dias

};

struct quarto{

int num;

// nmero do quarto

char categoria

// [S]olteiro / [F]amiliar

char status

// [L]ivre / [O]cupado

};

Categoria de quarto:

[S]olteiro diria R$ 85,00 por pessoa[F]amiliar diria R$ 45,00 por pessoaPAGE 37