Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

quitZAUMMM

[Resolvido] [Tutorial] Manipulação de ponteiros e tipos avançados de d

Recommended Posts

Manipulação de ponteiros e tipos avançados de dados

 

As structs

 

As structs formam uma parte integrante do C bastante utilizada pelos programadores em geral. Muitas vezes, os programadores se deparam com problemas para os quais a solução utilizando os tipos de variáveis do C é muito complicada, gera código ilegível e conseqüentemente custoso de manter. Por isso existem as structs - são estruturas que o programador pode criar livremente com o objetivo de incrementar o espaço de programação. Com o uso de structs, o programador pode agrupar dados que possuem uma forte ligação de significado, criando um tipo novo de variável composto por uma ou mais variáveis, inclusive de tipos diferentes. Vamos ver um exemplo:

 

Imagine que você esteja codificando uma função e que essa função precisa de um conjunto de cinco dados. Não é tão difícil imaginar uma função que necessite dessa quantidade de dados - um exemplo é uma função que calcula a média de um aluno com base nas notas de cinco provas. Temos várias formas de resolver esse problema: primeiro, podemos fazer uma função que recebe um vetor com quantidade indefinida de elementos. Ou então podemos passar como parâmetro para a função o endereço de memória para o primeiro elemento do vetor de notas, e uma variável dizendo o número de provas às quais o aluno foi submetido - essa é uma boa idéia, mas vamos pensar em mandar as cinco notas separadamente. O protótipo da função seria o seguinte:

float calculaMedia (float floatNota1, float floatNota2, float floatNota3, floatNota4, floatNota5);

Se você não se importar com a quantidade de parâmetros, tudo bem, pode fazer a função assim. Mas esse não é um código de qualidade, não é legível e conseqüentemente é difícil de manter. Por isso, vamos criar uma estrutura composta por cinco variáveis do tipo inteiro, assim poderemos passar apenas ela como parâmetro:

struct notas {
	float floatNota1; 
	float floatNota2;
	float floatNota3;
	float floatNota4;
	float floatNota5;
};

Perceba que há um ';' logo após o final do bloco de código. Com a estrutura criada, podemos, dentro do programa, criar uma variável do tipo dela, simplesmente fazendo:

struct notas varNotas;

E podemos criar a função com o seguinte protótipo:

float calculaMedia (struct notas varNotas);

Vamos ver um exemplo completo:

#include <stdio.h>

struct notas {
	float floatNota1;
	float floatNota2;
	float floatNota3;
	float floatNota4;
	float floatNota5;
};

float calculaMedia (struct notas varNotas) {
	return((varNotas.floatNota1 + varNotas.floatNota2 + varNotas.floatNota3 + varNotas.floatNota4 + varNotas.floatNota5)/5);
}

int main() {
	struct notas varNotas;
	float floatMedia;
	printf("Digite a nota da prova 1: "); scanf("%f",&(varNotas.floatNota1));
	printf("Digite a nota da prova 2: "); scanf("%f",&(varNotas.floatNota2));
	printf("Digite a nota da prova 3: "); scanf("%f",&(varNotas.floatNota3));
	printf("Digite a nota da prova 4: "); scanf("%f",&(varNotas.floatNota4));
	printf("Digite a nota da prova 5: "); scanf("%f",&(varNotas.floatNota5));
	floatMedia = calculaMedia(varNotas); 
	printf("A media do aluno eh: %.2f\n", floatMedia);
	return(0);
}

É importante percebermos que é apenas um exemplo do uso de structs - não deve ser visto com um exemplo de um programa bem escrito. Sempre que estiver programando se preocupe em escrever código legível, mantenível (de fácil manutenção) e acima de tudo eficiente. No caso de estarmos codificando um programa seguindo esses objetivos, nunca utilizaríamos cinco execuções seguidas da função scanf para ler as notas - utilizaríamos um vetor e leríamos da seguinte forma:

float vtrNotas[5];
	int i;
	for (i=0; i<5; i++) {
		printf("Digite a nota da %da prova: ", i+1);
		scanf("%f",&vtrNotas[i]);
}

Por isso esse não é um bom exemplo de um código bem escrito, mas serve como exemplo de um código que utiliza structs. Um outro bom exemplo de programa que utiliza structs é um programa responsável por manter uma agenda de endereços. Se não for a idéia fazer com que os registros sejam dinâmicos, ou seja, que o conteúdo de cada registro não varie, podemos utilizar uma struct parecida com a seguinte:

struct registro {
	char nome[20];
	char sobrenome[20];
	char telFixo[11];
	char telMovel[11];
	char endPessoal[40];
	char endProfissional[40];
	char email[30];
};

 

Vetores e structs

 

Uma forma interessante de se trabalhar com as structs é utilizar vetores dentro delas, como uma forma de armazenar dados. O método é bem intuitivo - vamos criar uma struct:

struct aluno {
	char nome[40];
	float notas[5];
	float trabalhos[2];
	float conceito;
};

Criando a struct dessa forma a leitura das nota do aluno seria feita com um código bem mais elegante, assim:

struct aluno varAluno;
for (i=0; i<5; i++) {
	printf("Digite a %da nota do aluno: ", i+1);
	scanf("%f",&varAluno.notas[i]);
}

Além disso, podemos criar um vetor de structs! Seria como por na memória uma stuct dessa depois da outra, contíguamente na memória, assim:

struct aluno varAluno[10];

E poderíamos acessar a nota do aluno de índice cinco da seguinte forma:

varNotas[5].notas[i]
que quer dizer, a i-ésima nota do aluno de índice cinco.

 

 

 

Ponteiros

 

Uma forma bastante elegante de se manipular as estruturas compostas é com a utilização de ponteiros. Anteriormente nós comentamos que a maior desavantagem da programação orientada às funções é o fato de todas as variáveis que serão utilizadas pela função serem copiadas para o espaço de execução da função, gerando um custo de tempo e memória nessa cópia. Se estivermos trabalhando com estruturas compostas extensas, esse efeito é mais prejudicial ainda. Por isso, se pudermos passar para as funções a área da memória em que a estrutura se encontra, ganharemos tempo e espaço na memória. Podemos fazer isso da seguinte forma:

 

Primeiro criamos a estrutura - afinal, ela tem que estar na memória propriamente dita:

struct aluno varAluno;

Depois, criamos a função que, ao invés de receber a estrutura, recebe o endereço dela:

float calculaMedia (struct aluno* varAluno);

Com a função criada dessa forma, podemos passar o endereço da estrutura como parâmetro, assim:

floatMedia = calculaMedia(&varAluno);

Agora só precisamos nos preocupar com mais uma coisa: estamos trabalhando com endereço de memória e não o elemento em si. Por isso, precisamos manipular os elementos da estrutura de uma forma um pouco diferente. Dentro da função de calcular a média, acessaríamos as notas da seguinte forma:

for (i=0; i<5; i++) {
	floatMedia += varAluno->notas[i];
}

Isto porque varAluno não é uma estrutura e sim um ponteiro para uma estrutura. Para fixar, vamos ver uma estrutura com mais um nível e como manipular os seus dados:

struct endereco {
	char cep[10];
	char rua[10];
	char bairro[10];
};

struct aluno {
	char nome[40];
	float notas[5];
	float trabalhos[2];
	float conceito;
	struct endereco;
};

Como você pode ver, temos uma struct dento de uma struct. Isso não é um problema, e na verdade, pode ser uma boa solução. Se estivermos trabalhando com a estrutura em si, podemos manipular o cep da seguinte forma:

varAluno.endereco.cep

No entanto, se estivermos trabalhando com um ponteiro para a estrutura, faríamos assim:

varAluno->endereco.cep

Isto porque varAluno é um ponteiro, mas endereco é uma estrutura. Então utilizamos o operador '->' para o ponteiro varAluno e o operador '.' para a estrutura endereço.

 

Este texto retirei do site www.cdtc.org.br

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.