Estruturas em C permitem agrupar dados heterogêneos sob uma mesma estrutura. Podem conter tipos básicos, matrizes e outras estruturas. São declaradas usando a palavra-chave struct e permitem organizar e acessar dados de forma conjunta.
Estruturas Struct são colecções de dados heterogêneos agrupados em uma mesma estrutura de dados Ex: armazenas as coordenadas (x,y) de um ponto:
3.
Tipos Complexos Tiposbásicos : char , int , float , etc. Variáveis guardam um só valor. Matrizes : v.g. char matriz[20] Variáveis guardam colecções de objectos do mesmo tipo. Como guardar colecções de tipos diversos?
4.
Solução: Estruturas Declaração:struct { int x; int y; } p1, p2; a estrutura contém dois inteiros, x e y p1 e p2 são duas variáveis tipo struct contendo duas coordenadas cada.
5.
Estruturas Exemplo: struct { char nome[NOME_MAX + 1]; int numero; double media; } aluno1, aluno2; Informação diversa sobre uma única entidade (um aluno). Podem conter matrizes (e vice-versa). Podem conter outras estruturas.
6.
Declaração Formato dadeclaração: struct nome_da_estrutura { tipo_1 dado_1; tipo_2 dado_2; ... tipo_n dado_n; } lista_de_variaveis; A estrutura pode agrupar um número arbitrário de dados de tipos diferentes Pode nomear-se a estrutura para referenciá-la
7.
Definição de Tiposstruct { int x; int y; } p1; struct { int x; int y; } p2; struct ponto { int x; int y; }; struct ponto p1, p2; Repetição struct ponto define um novo tipo de dado Pode definir-se novas variáveis do tipo ponto
8.
Definição de Tipos (declaração de variáveis) Novo tipo: struct Aluno Definição de variáveis: struct Aluno aluno1 , aluno2,*p, lista[10] ; struct Aluno { char nome [NOME_MAX + 1]; int numero ; double media ; }; Equivalente a: struct { char nome [NOME_MAX + 1]; int numero ; double media ; }aluno1,aluno2,*p, lista[10];
Inicialização de estruturasstruct Aluno { char nome[NOME_MAX + 1]; int numero; double media;}; struct Aluno aluno = {"Zacarias", 666, 20.0}; Equivalente a: struct Aluno aluno; strcpy(aluno.nome,"Zacarias"); aluno.numero = 666; aluno.media = 20.0; aluno nome: numero: media: Z a c a r i as 666 20.0
12.
Atribuição de EstruturasRevisão : Inicialização de uma estrutura: struct ponto p1 = { 220, 110 }; Atribuição entre estruturas do mesmo tipo : struct ponto p1 = { 220, 110 }; struct ponto p2; p2 = p1; /* p2.x = p1.x e p2.y = p1.y */ Os campos correspondentes das estruturas são automaticamente copiados do destino para a origem p2 = p1 p1 x: y: 220 110 p2 x: y: p2 x: y: 220 110
13.
Atribuição de EstruturasAtenção para estruturas que contenham ponteiros : struct aluno { char *nome; int idade; } a1, a2; a1.nome = “Afonso”; a1.idade = 32; a2 = a1; Agora a1 e a2 apontam para a mesma string nome: a1.nome == a2.nome == “Afonso”
14.
Composição de Estruturasstruct retangulo { struct ponto inicio; struct ponto fim; }; struct retangulo r = { { 10, 20 }, { 30 , 40 } }; Acesso aos dados: r.inicio.x += 10; r.inicio.y -= 10; r inicio x: y: 10 20 fim x: y: 30 40
15.
Estruturas como parâmetrosstruct ponto cria_ponto ( int x, int y) { struct ponto tmp; tmp.x = x; tmp.y = y; return tmp; } main () { struct ponto p = cria_ponto(10, 20); } p x: y: 10 20 p x: y:
16.
Operações Operações entremembros das estruturas devem ser feitas membro a membro: /* retorna uma cópia de p1 = p1 + p2 */ struct soma_pts ( struct ponto p1, struct ponto p2) { p1.x += p2.x; (relembro que p1.x = p1.x +p2.x) p1.y += p2.y; return p1; /* retorna uma copia de p1 */ }
17.
Arrays de Estruturasstruct ponto arp[10]; /* cria um array de 10 pontos */ arp[1].x = 5; /*atribui 5 a coordenada x do 2º ponto */ struct jogador { char *nome; int idade; }; struct jogador PT[4] = {“Figo”,32, “ Carlos”, 24, “ Rui Costa”,27 ...}; PT nome: idade: Figo 32 nome: idade: Carlos 24 nome: idade: Rui Costa 27 nome: idade: ... ...
18.
Ponteiros para EstruturasEstruturas grandes são passadas como parâmetro De forma mais eficiente através de ponteiros struct ponto *pp; struct ponto p1 = { 10, 20 }; pp = &p1; printf(“Ponto P1: (%d %d)\n”, (*pp).x, (*pp).y}; Aceder com o operador “->”: printf(“Ponto P1: (%d %d)\n”, pp->x, pp->y}; (*pp).x == pp->x pp 1002 p1 x: y: 1002 10 20
Função sizeof(tipo)A função sizeof(tipo) retorna o tamanho em bytes ocupado na memória pelo tipo de dado passado como parâmetro Ex: sizeof(int) => 4 bytes sizeof(char) => 1 byte sizeof(struct ponto) => 8 bytes sizeof(struct ponto *) => 4 bytes
Espaço Efectivo /*teste com Symantec C, PowerPC 603 - Macintosh */ struct aluno2 { char *nome; /* 4 bytes */ short idade; /* 2 bytes */ char matricula[7]; /* 7 bytes */ }; /* sizeof(aluno2) = 16 bytes */ no PowerMac uma estrutura é um múltipo do tamanho da palavra, 32 bits
24.
Alocação Dinâmica deMemória incluir a biblioteca standard do C: stdlib.h (malloc() e free()) possibilidade de libertar memória à medida que deixa de ser precisa as funções calloc e malloc permitem alocar blocos de memória em tempo de execução void * malloc( ); /* retorna um ponteiro void para n bytes de memória não iniciados. Se não há memória disponível malloc retorna NULL */ número de bytes alocados size_t n
25.
Alocação Dinâmica deMemória A função malloc () ( memory allocation ) reserva uma porção de memória, retornando um apontador genérico (tipo void *) para o ínicio da porção reservada, ou o valor NULL no caso da reserva ser impossível A sua utilização é representada no exemplo seguinte: int *pi; pi= ( int *) malloc (sizeof( int )); /* aloca espaço para um inteiro */
26.
malloc () –exemplo float *v; int n; printf("Quantos valores? "); scanf("%d", n); v = (float *) malloc(n * sizeof(float) ); Neste exemplo, é reservada uma porção de memória capaz de guardar n números reais ( float ), ficando o apontador v a apontar para o endereço inicial dessa porção de memória. O cast da função malloc() - (float *) - assegura que o apontador retornado é para o tipo especificado na declaração do apontador. Certos compiladores requerem obrigatóriamente o cast .
27.
malloc () Conselho: não altere o valor do apontador que recebeu o retorno da função malloc(). Desta forma poderá sempre saber onde começa o bloco de memória dinâmica reservado. Utilize apontadores auxiliares para realizar operações (leitura, escrita) dentro do bloco de memória.
28.
Libertar memória dinâmicaA memória é libertada utilizando a função free() int *pi; pi= ( int *) malloc (sizeof( int )); Para libertar a memória: free(pi);
29.
Ajuste da memóriadinâmica É possível alterar o tamanho do bloco de memória reservado, utilizando a função realloc() . Esta função salvaguarda os valores anteriormente em memória, até ao limite do novo tamanho (especialmente importante quando se reduz o tamanho do bloco de memória). O seguinte exemplo ilustra a forma de utilização desta função.
30.
Ajuste da memóriadinâmica int *a; a = (int *) malloc( 10 * sizeof(int) ); (...) a = (int *) realloc( a, 23 * sizeof(int) ); (...) free(a); A chamada da função realloc() recebe como argumentos um apontador para o bloco de memória previamente reservado, com uma função malloc(), de forma a saber qual a porção de memória a ser redimensionada e o novo tamanho absoluto para o bloco de memória.
31.
Alocação dinâmica dememória void * calloc(size_t n, size_t size); /* calloc retorna um ponteiro para um array com n elementos de tamanho size cada um ou NULL se não houver memória disponível. Os elementos são iniciados em zero */ o ponteiro retornado por malloc e calloc deve ser convertido para o tipo de ponteiro que invoca a função:
32.
Alocação dinâmica dememória int *ai = ( int *) calloc (n, sizeof( int )); /* aloca espaço para um array de n inteiros */ toda memória não mais utilizada deve ser liberada através da função free() : free(ai); /* libera todo o array */ free(pi); /* libera o inteiro alocado */
33.
Exercícios 1- Pretende-seque faça a alocação de espaço em memória para 10 inteiros. Deverá imprimir os seus respectivos endereço de memórias e o seu conteúdo. 2- Leia uma sequência de 10 números to teclado usando apontadores em lugar de índices. Usando a mesma técnica (apontadores) determine o maior e o menor valor. Reserve memória dinâmica em vez de declarar o vector de uma forma estática. 3- Ler uma sequência de números do teclado (sequência terminada em zero ).Escreva no ecrã os números que estão acima da média. Utilize um vector dinâmico para armazenar os números.
34.
Resolução Nº 11- Pretende-se que faça a alocação de espaço em memória para 10 inteiros. Deverá imprimir os seus respectivos endereço de memórias e o seu conteúdo. #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <alloc.h> int *dados,i; //int *p; void main() { clrscr(); dados=(int *)malloc(5*sizeof(int)); if (dados==NULL) { printf ("A aloca‡Æo nÆo correu bem!!"); exit(1); } //p=dados; podia iniciar um outro ponteiro for (i=0;i<5;++i) { printf("O dados sÆo %d ", *(dados+i)); //mostra o que existe nesse espa‡o de mem¢ria printf(". E est no endere‡o %d\n", dados);//endere‡o de mem¢ria dados++; //printf("O dados sÆo %d\n", *(p+i)); //p++; } getch(); }
35.
Resolução Nº 2Leia uma sequência de 10 números to teclado usando apontadores em lugar de índices. Usando a mesma técnica (apontadores) determine o maior e o menor valor. Reserve memória dinâmica em vez de declarar o vector de uma forma estática. #include <stdio.h> #include <stdlib.h> void main() { int *v, *min, *max; int i, soma = 0; float media; /* v passa a apontar para um bloco de memória com capacidade para 10 inteiros */ v = (int *) malloc(10 * sizeof(int)); for(i = 0; i < 10; i++) { printf("Insira um número: "); scanf("%d", v+i); } /* min e max passam a apontar para o primeiro valor do vector */ min = v; max = v; for(i = 0; i < 10; i++) { if ( *(v+i) > *max ) max = v+i; else if ( *(v+i) < *min ) min = v+i; } printf("O menor número inserido: %d\n", *min); printf("O maior número inserido: %d\n", *max); }
36.
Resolução Nº 3Ler uma sequência de números do teclado (sequência terminada em zero ).Escreva no ecrã os números que estão acima da média. Utilize um vector dinâmico para armazenar os números. #include <stdio.h> #include <stdlib.h> void main() { int *v; int soma, i, num, c; float media; /* Esta operação é necessária para utilizar posteriormente a função realloc() */ v = (int *) malloc( sizeof(int) ); /* São inicializadas as variáveis soma e contador de números inseridos */ soma = 0; i = 0; /* O primeiro número é inserido antes do ciclo while para verificar se é zero (para a acabar) */ printf("Insira um número (zero para acabar): "); scanf("%d", &num); while( num ) /* O ciclo é executado enquanto num não é zero */ { i++; v = (int *) realloc(v, i*sizeof(int)); *(v+i-1) = num; /* O vector começa na posição zero pelo que i anda avançado um valor */ soma += num; /* É efectuado o somatório dos números inseridos */ /* É inserido um novo número para verificar no início do próximo ciclo */ printf("Insira um número (zero para acabar): "); scanf("%d", &num); } /* O cast (float) força as operações a serem realizadas no domínio dos float */ /* que de outra forma seria nos int (soma e i são ambos inteiros) */ media = (float) soma / i; for(c = 0; c < i; c++) if ( *(v+c) > media ) printf("O valor %d está acima da média.\n", *(v+i)); }