Você está na página 1de 24

Programação de Computadores

(PdC)

Structs
typedef, operadores, funções, ponteiros

{ }
Cristiano Premebida
cpremebida@deec.uc.pt

Edition: 2022-23 Page 1 of 24


Structs
Motivação

Imaginemos que desejamos tratar dados relativos a uma pessoa. Poderíamos criar um conjunto
de variáveis com a informação (registo) da pessoa:
• char nome[100];
• char sexo, estado_civil;
• unsigned int idade;
• float salario;

Estruturas: permitem que toda esta informação esteja agrupada e relacionada entre si.

Campos ou Membros de uma Estrutura


As componentes armazenadas dentro de uma estrutura são denominadas por campos ou
membros da estrutura.

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 2
Structs - sintaxe
Sintaxe da declaração de uma estrutura
struct [nome_da_estrutura] A declaração de uma estrutura
{ define um tipo de dados
tipo_1 campo_1a, campo_1b; composto, mas não define
tipo_2 campo_2; variáveis de tipo estrutura.
...
tipo_n campo_n;
};

Exemplo: uma estrutura capaz de armazenar uma data

struct Data
{
int dia, ano; // campos numéricos
char mes[12]; // uma string para o mês
};

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 3
Structs – exemplo (acesso aos campos)
Para aceder aos membros de uma estrutura, usa-se o operador ponto (.),
por exemplo: Data.dia
#include <stdio.h>
#include <string.h>

int main() {

struct Data
{
int dia, ano;
char mes[12];
} data; // note o ; no final da declaração

data.dia = 11;
data.ano = 2049;
strcpy(data.mes, "Maio"); // nao eh possivel data.mes = "Maio";

printf("Data: %d / %s / %d \n", data.dia, data.mes, data.ano);


printf("Primeira letra do mes: %c \n", data.mes[0]);

return (1); }

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 4
Structs - Inicialização - declaração
Sintaxe da declaração com inicialização p/ex:
struct Data dy =
struct nome_da_estrutura nome_var = {25, 2035, "Abril"};
{valor_1, valor_2, ..., valor_n};

onde se assume que n é o número de membros da estrutura em causa, e os valores dados


correspondem aos membros da struct pela ordem em que estes surgem na declaração da mesma.

Considere-se a declaração: struct Data dt, datas[5], *ptr_data;

• dt é uma variável do tipo struct Data, contendo 2 inteiros e uma


string com espaço para 11 char úteis.
• datas é uma tabela de 5 elementos, cada um deles contendo struct Data
uma estrutra do tipo struct Data ou seja, é reservado espaço {
int dia, ano;
para 5 elementos do tipo struct Data. char mes[12];
• ptr_data é um ponteiro para o tipo struct Data. };

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 5
Structs - exemplo
#include <stdio.h>
int main() {
struct Data {
int dia, ano;
char mes[12];
} dx = {10, 2099, "Outubro"}, tab[2]; ;

struct Data dy = {25, 2035, "Abril"};


tab[0] = dx;
tab[1] = dy;
// Soma 1 ao ano de tab[0]
tab[0].ano++;
// Mostra tab
printf("A tabela de datas:\n");
for(int i = 0; i < 2; i++)
printf(" %d / %s / %d \n", tab[i].dia, tab[i].mes, tab[i].ano);

puts("A primeira letra de cada mes:");


for(int i = 0; i < 2; i++)
printf(" %c eh a 1a letra de %s \n",tab[i].mes[0], tab[i].mes);

return (1);}

Page 6
Structs: definição de tipos – typedef
Sintaxe:
typedef tipo_existente nova_designação;

typedef permite criar um sinónimo (uma só palavra) para um tipo já existente, de acordo com as
preferências/necessidades do programador. Num typedef não há declaração de variáveis.

Exemplo struct Data


{
int dia, ano;
char mes[12];
};

typedef struct Data DATA;

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 7
Exemplos com typedef

/* Sinónimos */
typedef float decimal;
typedef int inteiro;

/* Mais curto */
typedef long unsigned int LUint;

/* struct sem nome, identificada por typedef */


typedef struct // struct sem nome
{
unsigned int h,m,s;
char evento[100];
} EVENTO;

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 8
Âmbito da declaração de uma estrutura e typedef

• O âmbito da declaração de uma estrutura e de um typedef


segue as regras habituais de declaração de variáveis.

• Assim, se quisermos que uma estrutura seja conhecida/visível para várias funções de
um programa, a sua definição deve estar fora de qualquer função e de preferência no
início, antes dos protótipos da funções.

Curiosidade:
• O tipo FILE é um exemplo da utilização de
typedef:
typedef struct _IO_FILE FILE;

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 9
Operadores e estruturas
• Sendo uma estrutura definida pelo utilizador, não podemos utilizar os operadores relacionais
<, >, >=, <=, == ou ! =

• Da mesma forma não podemos usar operadores aritméticos.


• Mas podemos usar o operador atribuição (=), para copiar uma estrutura como um bloco de dados
para outra estrutura do mesmo tipo.
Ou seja para copiar uma estrutura para outra não precisamos copiar membro a membro.

• Podemos obter o endereço de uma estrutura, ou o endereço de um membro de uma estrutura


p/ex:

• Se v é uma estrutura então &v devolve o endereço dessa estrutura em memória (ou seja
o menor dos endereços que ela ocupa)

• Se x é um membro de v, &v.x devolve o endereço de memória de v.x

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 10
Estruturas – exemplo (operadores)
#include <stdio.h>
struct ponto {
double x; //Coordenada segundo o eixo dos x
double y; //Coordenada segundo o eixo dos y
};

int main() {
struct ponto P1={0.0,0.0}, P2, P3;
printf(" Coord. de P1 (%.1f,%.1f) \n", P1.x, P1.y);
// Preenche novas coordenadas
printf("De-me as coordenadas x, y de um ponto:\n");
scanf("%lf%lf", &P1.x, &P1.y);
printf("\n Novas coord. P1 (%.1f,%.1f) \n", P1.x, P1.y);
// usa atribuição ie, copia para P2
P2 = P1;
printf("P2 = (%.1f,%.1f) \n", P2.x, P2.y);

P3.x = 2 * P2.x; // campo x de P3


P3.y = -1 * P2.y; // campo y de P3
printf("Coord. de P3 = (%.1f,%.1f)\n", P3.x, P3.y);

return (1);}

Page 11
Estruturas que contêm estruturas
• um membro de uma estrutura pode ser do tipo estrutura. Basta para tal que esse tipo já tenha sido
definido previamente.

Exemplo de uma estrutura com um membro que aponta para uma estrutura com o mesmo tipo:

struct Elem
{
int valor;
struct Elem *pElem; // Ponteiro para uma struct Elem
}; // Útil em Estrutras de Dados e Algoritmos

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 12
Estruturas que contêm estruturas - exemplo
Podemos definir um ponto 2D num plano: struct ponto {
double x; //Coord. x
double y; //Coord. y
};
E em seguida definir um segmento:
struct segmento {
struct ponto origem; // extremo 1 do segmento
struct ponto destino; // extremo 2 do segmento
};

Considere a estrutura: struct segmento Seg;

Sendo Seg do tipo struct segmento, que tem como mebro a estrutura ponto, para aceder aos
membros basta usarmos a notação:

Seg.origem.x = 7.1; // aceder a um membro de Seg


Seg.origem.y = 8.3;
ponto a = {3.5, 4.2};
Seg.destino = a; // alterar um membro de Seg

Page 13
Exemplo: passagem de estruturas a funções – por valor
#include <stdio.h>
#include <math.h>

struct ponto {double x, y; }; // declara a estrutura


void mostra_ponto(struct ponto); // funcao

int main(){
struct ponto a = {1.2, 2.3};
struct ponto b = {4.2, 6.3};
mostra_ponto(a);
mostra_ponto(b);
mostra_ponto((struct ponto){5.7, 8.9});

return (1); }

void mostra_ponto(struct ponto p){


printf("ponto (%.1f,%.1f)\n", p.x, p.y); }

Page 14
Exemplo: Função que retorna uma estrutura
#include <stdio.h>
struct ponto { double x, y; };
void mostra_ponto(struct ponto p)
{ printf("ponto (%.1f,%.1f)\n", p.x, p.y); }

struct ponto retorna_ponto(){


struct ponto aux;
printf("De-me as coordenadas x, y de um ponto:\n");
scanf("%lf%lf", &aux.x, &(aux.y));
return aux; }

int main(){
struct ponto a;
a = retorna_ponto(); // a <- valor retornado
mostra_ponto(a);

return (1); }

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 15
Exemplo: funções e estuturas que contêm estruturas
#include <stdio.h>
#include <math.h>
struct ponto {double x, y;};
struct segmento {struct ponto origem, destino;};
double comprimento(struct segmento s);

void main(){
struct ponto a = {1.2, 2.3};
struct ponto b = {4.2, 6.3};
struct segmento z;
z.origem = a;
z.destino = b;
printf("O segmento mede %.0f\n", comprimento(z));
return (1);}

double comprimento(struct segmento s) {


double dx, dy;
dx = fabs(s.origem.x - s.destino.x); // fabs(r) em <math.h>
dy = fabs(s.origem.y - s.destino.y); // valor absoluto de r
return ((double)(sqrt(dx*dx + dy*dy))); }

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 16
Exemplo anterior: com typedef
#include <stdio.h>
#include <math.h>
typedef struct {double x, y; } ponto;
typedef struct {ponto origem, destino; } segmento;
double comprimento(segmento s);

int main(){
ponto a = {1.2, 2.3};
ponto b = {4.2, 6.3};
segmento z;
z.origem = a;
z.destino = b;
printf("O segmento mede %.0f\n", comprimento(z));
return (1);}

double comprimento(segmento s) {
double dx, dy;
dx = fabs(s.origem.x - s.destino.x);
dy = fabs(s.origem.y - s.destino.y);
return ((double)(sqrt(dx*dx + dy*dy))); }

Page 17
Passagem de estruturas a funções – por ponteiro
• Em C só existe passagem por valor.
• Se desejamos que uma função seja capaz de modificar uma variável que lhe é externa, tal
só é possível se a função receber um ponteiro para o valor dessa variável.
• O ponteiro é passado por valor, mas permite à função aceder e alterar o valor apontado.

Passagem de struct por ponteiro


É obrigatório passar o endereço de uma estrutura para uma função,
se esta tiver como objetivo alterar a estrutura (ou seja modificar o(s)
campo(s) da estrutura). Esse endereço será o argumento da função
que deverá ter um parâmetro do tipo ponteiro para a estrutura em
causa.

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 18
Exemplo: passagem por ponteiro
#include <stdio.h>
struct ponto {
double x, y; };

void mostra_ponto(struct ponto p){


printf("ponto (%.1f,%.1f)\n", p.x, p.y); }

void le_ponto(struct ponto * ptr) {


printf("De-me as coordenadas x, y de um ponto:\n");
scanf("%lf%lf", &(*ptr).x, &(*ptr).y);
}

int main(){
struct ponto a;
le_ponto(&a);
mostra_ponto(a);

return (1);}

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 19
Passagem de estruturas a funções – por ponteiro
No exemplo anterior temos, struct ponto *ptr; e para
acedermos aos membros x e y de struct ponto escrevemos:
(*ptr).x , porque o que desejamos é o campo x da struct
apontada por ptr, a qual é *ptr

• Não podemos escrever *ptr.x porque o operador ponto (.) tem precedência sobre o
operador de desreferencia (*)

• Em vez de escrevermos (*ptr).x poderíamos ter escrito mais simplesmente:


ptr->x , que significa obter o valor do membro x da struct apontada por ptr

Operador ->
Se ptr for um ponteiro para uma estrutura e campo um membro dessa estrutura, então as
expressões (*ptr).campo e ptr->campo são equivalentes.

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 20
Exemplo: passagem por ponteiro
#include <stdio.h>
struct ponto {
double x, y; };

void mostra_ponto(struct ponto p){


printf("ponto (%.1f,%.1f)\n", p.x, p.y);}

void le_ponto(struct ponto *ptr){


printf("De-me as coordenadas x, y de um ponto:\n");
scanf("%lf%lf", &ptr->x, &ptr->y); }

int main()
{
struct ponto a;
le_ponto(&a);
mostra_ponto(a);

return (1); }

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 21
Estruturas – ficheiros
A escrita de estruturas em ficheiros pode ser feita em modo texto.

Para tal o programador deve usar escrita formatada para cada


um dos membros da estrutura e usar algo como valores
separados por ";"ou por ",“ para identificar cada um dos
membros; cada estrutura poderá estar numa linha do ficheiro de texto.

• O mais simples é contudo criar um ficheiro binário e usando as


funções fread e fwrite já introduzidas.

@Créditos/referência: partes do conteúdo são baseados no material didático, de anos anteriores, da Profª. Teresa Gomes – DEEC-UC. Page 22
Exemplo: criar ficheiro texto
#include <stdio.h>
struct ponto {double x, y; };
void mostra_ponto(struct ponto p) {
printf("ponto (%.1f,%.1f)\n", p.x, p.y); }
void le_ponto(struct ponto *ptr){
printf("De-me as coordenadas x, y de um ponto:\n");
scanf("%lf%lf", &(*ptr).x, &(*ptr).y); }

int main(){
struct ponto a[4];
for(int i = 0; i < 4; i++) le_ponto(&a[i]);
FILE *fich;
fich= fopen("pontos.txt","w"); // Cria/Reescreve para escrita
if(fich == NULL) return (-1);
for(int i = 0; i < 4; i++)
fprintf(fich, "%g;%g\n", a[i].x, a[i].y);
fclose(fich);
// Abre o ficheiro para leitura
fich= fopen("pontos.txt","r");
struct ponto b[4];
for(int i = 0; i < 4; i++)
fscanf(fich, "%lf%*c%lf\n", &b[i].x, &b[i].y);
//print
for(int i = 0; i < 4; i++) mostra_ponto(b[i]);
fclose(fich);

return (1);}
Page 23
Exemplo: criar ficheiro binário
struct ponto {double x, y; };
void mostra_ponto(struct ponto p) {
printf("ponto (%.1f,%.1f)\n", p.x, p.y); }
void le_ponto(struct ponto *ptr){
printf("De-me as coordenadas x, y de um ponto:\n");
scanf("%lf%lf", &(*ptr).x, &(*ptr).y); }

int main(){
struct ponto a[4];
for(int i = 0; i < 4; i++) le_ponto(&a[i]);
FILE *fich;
fich= fopen("pontos.bin","wb");
if(fich == NULL) return (-1);
int k = fwrite(a, sizeof(struct ponto), 4, fich);
fclose(fich);
if(k != 4) {
printf("Erro a criar o ficheiro pontos.bin");
return -2; }
fich= fopen("pontos.bin","rb");
struct ponto b[4];
k = fread(b, sizeof(struct ponto), 4, fich);
fclose(fich);
if(k != 4) {
printf("Erro a ler o ficheiro pontos.bin");
return -2; }
for(int i = 0; i < 4; i++) mostra_ponto(b[i]);

return (1);}
Page 24

Você também pode gostar