ESTRUTURAS

Uma estrutura, nada mais é do que um modo de agruparmos variáveis relacionadas. Veja um círculo, por exemplo. Um círculo pode ser definido pelas coordenadas de seu centro e pelo comprimento de seu raio. Pois bem, até agora, como definíamos um círculo?

int main() {
	int x;
	int y;
	float r;

	printf("Entre o raio ");
	scanf("%f",&r);
	printf("Entre o x do centro ");
	scanf("%d",&x);
	printf("Entre o y do centro ");
	scanf("%d",&y);
}
		

Agora, suponha que temos 2 círculos, temos que fazer:

int main() {
	int x1;
	int y1;
	float r1;
	int x2;
	int y2;
	float r2;

	printf("Primeiro círculo:\n");
	printf("Entre o raio ");
	scanf("%f",&r1);
	printf("Entre o x do centro ");
	scanf("%d",&x1);
	printf("Entre o y do centro ");
	scanf("%d",&y1);

	printf("Segundo círculo:\n");
	printf("Entre o raio ");
	scanf("%f",&r2);
	printf("Entre o x do centro ");
	scanf("%d",&x2);
	printf("Entre o y do centro ");
	scanf("%d",&y2);
}
		

Já ficou complicado! Repare que x, y e r são relacionadas - elas servem para definir o círculo. O que podemos fazer então? Podemos criar uma estrutura:

/*
	Defino um tipo struct s_circulo que conterá 3 campos.
*/
struct s_circulo {
	int x;
	int y;
	float r;
};

int main() {
	struct s_circulo c1; /* declaro variável do tipo struct s_circulo */
	struct s_circulo c2;

	printf("Primeiro círculo:\n");
	printf("Entre o raio ");
	scanf("%f",&c1.r);
	printf("Entre o x do centro ");
	scanf("%d",&c1.x);
	printf("Entre o y do centro ");
	scanf("%d",&c1.y);

	printf("Segundo círculo:\n");
	printf("Entre o raio ");
	scanf("%f",&c2.r);
	printf("Entre o x do centro ");
	scanf("%d",&c2.x);
	printf("Entre o y do centro ");
	scanf("%d",&c2.y);
}
		

Mais simples, não? Aqui declaramos a estrutura como global para que todo o programa possa acessar ao TIPO estrutura. Poderíamos definí-la localmente também, mas isso faria com que fosse reconhecida somente dentro da função onde foi definida:

int main() {
	struct s_circulo {
		int x;
		int y;
		float r;
	} c1, c2;
	struct s_circulo c3; /* pus para mostrar que pode ser usada assim */

	printf("Primeiro círculo:\n");
	printf("Entre o raio ");
	scanf("%f",&c1.r);
	printf("Entre o x do centro ");
	scanf("%d",&c1.x);
	printf("Entre o y do centro ");
	scanf("%d",&c1.y);

	printf("Segundo círculo:\n");
	printf("Entre o raio ");
	scanf("%f",&c2.r);
	printf("Entre o x do centro ");
	scanf("%d",&c2.x);
	printf("Entre o y do centro ");
	scanf("%d",&c2.y);
}
		

note que podemos listar as variáveis do TIPO struct s_circulo após sua definição. De uma forma geral, um tipo struct é definido assim (repare no ; final):

struct nome_da_estrutura {
	tipo1 campo1;
	tipo2 campo2;
	...
	tipoN campoN;
} variável1, variável2, ..., variávelN;
		

nesse caso, as variáveis são opcionais. É importante lembrar que, até o momento em que fizemos:

struct s_circulo {
	float x;
	float y;
	float r;
};
		

NENHUMA variável foi declarada. Somente quando fizemos "struct s_circulo c1" é que declaramos a variável. Ao criarmos uma variável deste tipo, o compilador aloca memória suficiente para todos seus campos (juntos). Cada variável tem seus próprios campos, ou seja, apesar de terem o mesmo nome, c1.x é diferente de c2.x.

Referenciando Elementos da Estrutura

Já vimos acima como podemos referenciar um campo de uma variável de estrutura:

	nome_da_variável.nome_do_campo
		

Por exemplo, suponha que queremos verificar qual círculo tem o maior raio:

struct s_circulo {
	int x;
	int y;
	float r;
};

int main() {
	struct s_circulo c1;
	struct s_circulo c2;

	/* abasteço os dados em c1 */
	c1.x = 2; /* armazeno 2 no campo x de c1 */
	c1.y = 5; /* armazeno 5 no campo y de c1 */
	c1.r = 3.2; /* armazeno 3.2 no campo r de c1 */

	c2.x = c1.x + 10; /* armazeno 12 no campo x de c2 */
	c2.y = c1.y; /* armazeno 5 no campo y de c2 */
	c2.r = 5.3; /* armazeno 5.3 no campo r de c2 */
}
		

Note que c1.x é usado como x1 em nosso primeiro exemplo, e é para ser assim. Só que agora fica muito mais fácil identificar a quem pertence este x particular.

E que tipos de variáveis podemos ter nos campos? Todos! Veja:

struct mucho_loca {
	int x;
	float y;
	char c;
	int v[10];
	char str[5];
	int *r;
};
		

Nossa! E como acessamos cada um destes? Lembra que variavel.campo é o mesmo que se usássemos uma variável comum? Então:

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

struct mucho_loca {
	int x;
	float y;
	char c;
	int v[10];
	char str[5];
	int *r;
};

int main() {
	struct mucho_loca estr;
	int i;

	estr.x = 0;
	estr.y = 2.3;
	estr.c = 'd';
	/* carrego o vetor de dentro da estrutura */
	for (i=0; i<10; i++) {
		estr.v[i] = i;
	}
	/* carrego o string */
	strcpy(estr.str, "oba!");
	/* carrego o ponteiro */
	estr.r = &i;

	/* agora vamos ler cada uma delas */
	printf("x = %d\n", estr.x);
	printf("y = %f\n", estr.y);
	printf("c = %c\n", estr.c);
	for (i=0; i<10; i++)
		printf("v[%d] = %d\n", i, estr.v[i]);
	printf("str = %s\n",estr.str);
	/* imprimo o endereço */
	printf("r = %p\n", estr.r);
	/* e seu conteúdo (no caso, o valor final de i, ou seja, 10) */
	printf("*r = %d\n", *estr.r);
}
		

Repare que usamos estr.r como usaríamos um ponteiro comum.

Mas, e uma estrutura pode ter como campo outra estrutura? Pode! Veja nosso círculo. Nele há um conjunto de dados também relacionados entre si. Veja bem, o círculo é definido pelo raio e posição do centro, correto? E a posição do centro é que é definida pelas coordenadas x e y, ou seja, podemos fazer:

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};
		

Nesse caso, usamos a estrutura assim:

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};


int main() {
	struct s_circulo c1;
	struct s_circulo c2;

	/* abasteço os dados em c1 */
	c1.c.x = 2; /* armazeno 2 no campo x de c1.c */
	c1.c.y = 5; /* armazeno 5 no campo y de c1.c */
	c1.r = 3.2; /* armazeno 3.2 no campo r de c1 */

	c2.c.x = c1.c.x + 10; /* armazeno 12 no campo x de c2.c */
	c2.c.y = c1.c.y; /* armazeno 5 no campo y de c2.c */
	c2.r = 5.3; /* armazeno 5.3 no campo r de c2 */
}
		

Isso pode parecer complicar as coisas, mas em projetos grandes, pode valer a pena, por organizar tudo.

Atribuição de Estruturas

Suponha que queremos copiar o conteúdo de uma variável struct s_circulo para outra, como fazemos? Uma maneira é copiar o conteúdo de seus campos, campo a campo:

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};


int main() {
	struct s_circulo c1;
	struct s_circulo c2;

	/* abasteço os dados em c1 */
	c1.c.x = 2;
	c1.c.y = 5;
	c1.r = 3.2;

	/* copio c1 para c2 */
	c2.c.x = c1.c.x;
	c2.c.y = c1.c.y;
	c2.r = c1.r;

	/* imprimo c2 */
	printf("%d\n", c2.c.x);
	printf("%d\n", c2.c.y);
	printf("%f\n", c2.r);
}
		

Bom, se sua estrutura for grande, ou o número de atribuições que você tiver que fazer for grande, seu código pode ficar enorme. Felizmente C tem uma outra maneira:

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};


int main() {
	struct s_circulo c1;
	struct s_circulo c2;

	/* abasteço os dados em c1 */
	c1.c.x = 2;
	c1.c.y = 5;
	c1.r = 3.2;

	/* copio c1 para c2 */
	c2 = c1;

	/* imprimo c2 */
	printf("%d\n", c2.c.x);
	printf("%d\n", c2.c.y);
	printf("%f\n", c2.r);
}
		

Viu? Estruturas inteiras podem ser copiadas usando-se apenas o operador de atribuição (=).

Vetores de Estruturas

E se quiséssemos ter um vetor de círculos, como faríamos? Como com qualquer variável:

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};


int main() {
	struct s_circulo vet[5]; /* vetor de 5 estruturas */
	int i;

	/* vou zerar cada uma das estruturas do vetor */
	for (i=0; i<5; i++) {
		vet[i].c.x = 0;
		vet[i].c.y = 0;
		vet[i].r = 0;
	}

	/* leio o vetor */
	for (i=0; i<5; i++) {
		printf("Campos do elemento %d:\n", i);
		printf("\tx = %d\n", vet[i].c.x);
		printf("\ty = %d\n", vet[i].c.y);
		printf("\tr = %d\n", vet[i].r);
	}
}
		

Ponteiros para Estruturas

Declarar um ponteiro para uma estrutura é como declarar ponteiro para qualquer outro tipo:

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};

int main() {
	struct s_circulo c1; /* um círculo */
	struct s_circulo *p; /* ponteiro para um círculo */

	/* abasteço a estrutura */
	c1.c.x = 5;
	c1.c.y = 10;
	c1.r = 8.3;

	/* aponto p para o círculo */
	p = &c1;
}
		

E como acessamos um campo da estrutura apontada por p? Já vimos, em nossa estrutura mucho_loca acima, que para acessar o valor apontando por um campo de uma estrutura (no caso, campo r de estr), fizemos:

	printf("*r = %d\n", *estr.r);
		

Ou seja, *estr.r acessa o valor apontado pelo campo r da estrutura estr. Nesse caso, r é o ponteiro, e não estr. E agora? Que fazer? Uma solução é usar ():

	(*p).r = 5.4;
		

Outra solução é usar o operador ->:

	p->r = 5.4;
		

Ou seja, "ponteiro->campo" equivale a "(*ponteiro).campo", que é o valor do campo da estrutura apontada por ponteiro.

Não confunda! "*estr.campo" dá o valor apontado pelo campo ponteiro da estrutura estr, ou seja, campo é um ponteiro e estr uma variável do tipo estrutura. Já "(*estr).campo" ou "estr->campo" dá o valor do campo da estrutura apontada por estr, ou seja, estr é um ponteiro e campo não.

O exemplo abaixo ilustra os 2 usos:

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};

int main() {
	struct s_circulo c1; /* um círculo */
	struct s_circulo *p; /* ponteiro para um círculo */

	/* abasteço a estrutura */
	c1.c.x = 5;
	c1.c.y = 10;
	c1.r = 8.3;

	/* aponto p para o círculo */
	p = &c1;

	/* mudo a coordenada x do centro */
	(*p).c.x = 15;
	/* mudo a coordenada y do centro */
	p->c.y = 7;
	/* mudo o raio */
	p->r = 1.0;

	/* imprimo a estrutura */
	printf("x = %d\n", c1.c.x);
	printf("y = %d\n", c1.c.y);
	printf("r = %f\n", c1.r);
}
		

E isso imprime:

x = 15
y = 7
r = 1.000000
		

Estruturas como Parâmetros

Da mesma forma que podemos atribuir uma estrutura à outra, podemos passá-las como parâmetros. Essa passagem se dá por valor, ou seja, a estrutura passada é inteiramente copiada para dentro do parâmetro (que também deve ser uma estrutura):

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};


void faz_nada(struct s_circulo cir) {
	/* mudo os dados da estrutura */
	cir.c.x = 2;
	cir.c.y = 3;
	cir.r = 2.4;

	/* imprimo a estrutura */
	printf("x = %d\n", cir.c.x);
	printf("y = %d\n", cir.c.y);
	printf("r = %f\n", cir.r);
}

int main() {
	struct s_circulo c1;

	/* abasteço a estrutura */
	c1.c.x = 5;
	c1.c.y = 10;
	c1.r = 8.3;

	/* chamo a função */
	faz_nada(c1);

	/* imprimo a estrutura */
	printf("x = %d\n", c1.c.x);
	printf("y = %d\n", c1.c.y);
	printf("r = %f\n", c1.r);
}
		

E a saída será:

x = 2
y = 3
r = 2.400000
x = 5
y = 10
r = 8.300000
		

Note que, como se espera, mudar os valores na estrutura DENTRO da função, ou seja, o valor do parâmetro, não muda o valor da estrutura passada a este parâmetro. Isso prova que a passagem é por valor. Também vale notar que quando declaramos parâmetros que são estruturas, devemos declarar o tipo da estrutura globalmente.

Até agora vimos uma estrutura passada por valor. E como passamos ela por referência? Simples, passando ponteiros:

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};

/*
	Troca os valores de uma estrutura para outra
*/
void troca(struct s_circulo *c1, struct s_circulo *c2) {
	struct s_circulo aux;

	aux = *c1;

	*c1 = *c2;
	*c2 = aux;
}

int main() {
	struct s_circulo cir1; /* um círculo */
	struct s_circulo cir2; /* um círculo */

	/* abasteço a cir1 */
	cir1.c.x = 5;
	cir1.c.y = 10;
	cir1.r = 8.3;

	/* abasteço a cir2 */
	cir2.c.x = 12;
	cir2.c.y = 1;
	cir2.r = 3.3;

	troca(&cir1, &cir2);

	/* imprimo as estruturas */
	printf("Cir1:\n");
	printf("\tx = %d\n", cir1.c.x);
	printf("\ty = %d\n", cir1.c.y);
	printf("\tr = %f\n", cir1.r);
	printf("Cir2:\n");
	printf("\tx = %d\n", cir2.c.x);
	printf("\ty = %d\n", cir2.c.y);
	printf("\tr = %f\n", cir2.r);
}
		

E a saída é:

Cir1:
        x = 12
        y = 1
        r = 3.300000
Cir2:
        x = 5
        y = 10
        r = 8.300000
		

Ou seja, trocamos todos os valores das estruturas. Mas e se quiséssemos trocar o valor de apenas um campo?

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};

/*
	Abastece os dados da estrutura.
*/
void abastece(struct s_circulo *c, int x, int y, float r) {
	c->c.x = x;
	c->c.y = y;
	c->r = r;
}

/*
	Troca os valores de uma estrutura para outra
*/
void trocaRaio(struct s_circulo *c, float raio) {
	c->r = raio;
}

int main() {
	struct s_circulo cir1; /* um círculo */

	/* abasteço a cir1 */
	abastece(&cir1, 5, 10, 8.3);

	/* imprimo a estrutura */
	printf("Cir1:\n");
	printf("\tx = %d\n", cir1.c.x);
	printf("\ty = %d\n", cir1.c.y);
	printf("\tr = %f\n", cir1.r);

	trocaRaio(&cir1, 3.54);

	/* imprimo a estrutura */
	printf("Cir1:\n");
	printf("\tx = %d\n", cir1.c.x);
	printf("\ty = %d\n", cir1.c.y);
	printf("\tr = %f\n", cir1.r);
}
		

E a saída será:

Cir1:
        x = 5
        y = 10
        r = 8.300000
Cir1:
        x = 5
        y = 10
        r = 3.540000

		

Ou seja, da mesma forma que com variáveis comuns, se quisermos modificar uma estrutura passada como parâmetro, devemos sim passar um ponteiro para esta estrutura.

Retornando Estruturas

Da mesma forma que variáveis comuns (não vetores ou strings), estruturas podem ser retornadas a partir de funções:

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};

/*
	Retorna um círculo oposto a outro (em relação à origem).

	Param:
		c - o círculo cujo oposto será retornado
*/
struct s_circulo reflexo(struct s_circulo c) {
	struct s_circulo resp;

	/* faço o oposto */
	resp.c.x = -c.c.x;
	resp.c.y = -c.c.y;
	resp.r = c.r;

	return(resp);
}


int main() {
	struct s_circulo cir1; /* um círculo */
	struct s_circulo oposto; /* um círculo */

	/* abasteço a cir1 */
	cir1.c.x = 5;
	cir1.c.y = 10;
	cir1.r = 8.3;

	oposto = reflexo(cir1);

	/* imprimo a estrutura */
	printf("oposto:\n");
	printf("\tx = %d\n", oposto.c.x);
	printf("\ty = %d\n", oposto.c.y);
	printf("\tr = %f\n", oposto.r);
}
		

E isso retorna:

        x = -5
        y = -10
        r = 8.300000
		

Comparação de Estruturas

Infelizmente, NÃO há como fazer:

struct s_pos {
	int x;
	int y;
};

struct s_circulo {
	struct s_pos c; /* centro do círculo */
	float r;        /* seu raio */
};

int main() {
	struct s_circulo c1;
	struct s_circulo c2;

	if (c1 == c2) printf("iguais\n");
}
		

Nesse caso, você terá que implementar sua própria função de comparação. Essa função terá que comparar cada membro das duas estruturas e, então, retornar 1 se todos forem iguais e 0 se algum for diferente.




Copyright© 2005 Norton Trevisan Roman - Direitos Autorais Reservados.