Post on 18-Apr-2015
Estrutura de dados II
Carlos Oberdan Rolim
Ciência da ComputaçãoSistemas de Informação
Revisão
Ponteiros, passagem de parâmetros para funções,
alocação dinâmica e estruturas
Ponteiros
Ponteiros em Linguagem C
O Que é uma variável?
É uma área da memória do computador onde é armazenado um valor….
Exemplo 1:
int a = 1; Atribui ao endereço 1000 o valor 1
1000 1001 1002 1003
1
Variável Posição
a 1000
Ponteiros em Linguagem C
O Que É Um Ponteiro?
Um ponteiro é uma variável que aponta para outra variável. Isto significa que um ponteiro mantém o endereço de memória de outra variável. Em outras palavras, o ponteiro não contém um valor no sentido tradicional, mas sim o endereço de outra variável. Um ponteiro "aponta para" esta outra variável mantendo uma cópia de seu endereço
Convém dizer que a expressão “apontar para...” significa “armazenar o endereço de memória de...”
Como um ponteiro contém um endereço, e não um valor, terá duas partes. O ponteiro contém um endereço e o endereço aponta para um valor. Há o ponteiro e o valor para o qual ele aponta. Este fato pode ser um tanto confuso, até você se familiarizar com ele. Superada a etapa da familiarização, ele se torna extremamente eficaz.
Ponteiros em Linguagem C
Operadores relacionados a Ponteiros:
*(asterisco): informa que uma variável irá armazenar o endereço de outra variável;
ou:
Informa ao computador que vc deseja o valor que está no endereço armazenado;
- Pode ser lido como “no endereço”
q = *m; q recebe o valor armazenado no endereço m
& (e comercial): retorna o endereço de uma variável;
- Pode ser lido como “o endereço de”
m = &count; m recebe o endereço de count
Ponteiros em Linguagem C
int main() {
int i,j;
int *p;
p = &i;
*p=5;
j=i;
printf(("%d %d %d\n", i, j, *p);
return 0;
}
==> 5 5 5
Operadores de ponteiros
* (asterisco) indica que a variável é um ponteiro
tipo_dado *nome_ponteiro;
Ex:
int x;
int *pi; /* compilador sabe que pi é ponteiro */
/* pi é um ponteiro para inteiro */
Operadores de ponteiros
o operador “&” quando aplicado sobre uma variável retorna o seu endereço
Ex:
int x = 10, *pi;
pi = &x;
printf(“&x: %p pi: %p”, &x, pi);
=> &x: 0x03062fd8 pi: 0x03062fd8
Operadores de ponteiros
o operador “*” quando aplicado sobre um ponteiro retorna o dado apontado
Ex:
void main () {
int *tmp_ptr;
int x, y;
x = 10;
tmp_ptr = &x;
y = *tmp_ptr; /* (*tmp_ptr) = 10 */
}
tmp_ptr
x
y
0xABA0
0xABA2
0xABA0
10
10
Outro exemplo ilustrado
int i; int *p;
p = &i;
*p=5;
Relembrando...
operador *declara-se com *
int *xacessa-se (alterar, modificar, ler) também com *
*x = 10; // atribui o valor 10 ao local apontado pelo ponteiro ‘x’
printf(“%d”, *x); // imprime o valor armazenado no local apontado por ‘x’
observação: strings e vetores funcionam de forma diferente: um vetor ou string é um ponteiro por definição
operador &acessa (alterar, modificar, ler) o endereço de uma variável (que é um ponteiro)
Exemplo de uso
int a = 1; declara variavel inteiro com valor 1
int *pt_a; declara um ponteiro para um inteiro
pt_a = &a; ponteiro recebe o endereco da variavel a
printf(“%d”, *pt_a); imprime o valor apontado pelo ponteiro
Ponteirosponteiros são variáveis tipadas: (int *) ≠ (float *) ≠ (char *)
As variaveis ponteiro devem sempre apontar para os tipos de dados corretos. Uma variavel ponteiro declarada como apontador de dados inteiros deve sempre apontar para dados deste tipo.
Ex:
main() {
int *ip, x;
float *fp, z;
ip = &x; /* OK */
fp = &z; /* OK */
ip = &z; /* erro */
fp = &x; /* erro */
}
Ponteiros
espaço ocupado pelas variáveis
Ponteiro aponta para o tamanho segundo seu tipo
1 byte
(int *)
1 byte
(float *)
(char *)
Exemplo de uso
Exemplo:
int a = 1;
int *pt_a;
pt_a = &a;
1000 1001 1002 1003
1 1000
Variável Posição
a 1000
pt_a 1001
Ponteiros em Linguagem C
Onde usar isto???Funções!
Alocação Dinâmica
Não sei o tamanho que o vetor precisa ter….!
Não sei o tamanho que cada string precisa ter…
Não sei o tamanho que a matriz precisa ter…
Utilizando Ponteiros
void main() {int x = 10;int *pi;
pi = &x; /* *pi == 10 */(*pi)++; /* *pi == 11 */printf(“%d”, x);
}==> 11
ao alterar *pi estamos alterando o conteúdo de x
Utilizando Ponteiros
void main() {
int x = 10;
int *pi, *pj;
pi = &x; /* *pi == 10 */
pj = pi; /* *pj == 10 */
(*pi)++; /* (*pi, *pj, x) == 11 */
(*pj)++; /* (*pi, *pj, x) == 12 */
printf(“%d”, x); /* ==> 12 */ printf(“%x”, &pj); /* Endereco de x ==> 0x0c220c */
}
Ponteiros e Strings
Quando imprimimos uma cadeia de caracteres constantes (string) com printf o que é passado é o ponteiro para a cadeia.
Printf(“Ola como vai?”);
Dessa forma é possível carregar o endereço da string em um ponteiro do tipo char
char * lista;
lista = "Ola como vai ?";
printf("%s", lista );
Ponteiros e Strings
Na verdade, strings são arrays de caracteres e podem ser acessados através de char *
void main ()
{
char str[]=“abcdef”, *pc;
for (pc = str; *pc != ‘\0’; pc++)
putchar(*pc);
}
==> abcdef
o incremento de pc o posiciona sobre o próximo caracter (byte a byte)
Ponteiros e Strings
Outra forma de mostrar uma string usando laço
char *origem = "testando";
do{
printf("%c ", *origem);
}while (*origem++); /* origem == 0 encerra o laco */
Cuidados com Strings
É comum esquecer de alocar uma área para armazenamento de caracteres
void main() {
char *pc; char str[] = “Um string”;
strcpy(pc, str); /* erro! pc indeterminado */
...
}
Alocação dinâmica
Alocação dinâmica de memóriaAlocação dinâmica x alocação estática
Pode-se alocar dinâmicamente (em tempo de execução) um espaço de memória para uso com arrays, structs, etc...
int main() { int *p;
p = (int *) malloc(sizeof(int)); if (p == 0) { printf("ERRO: Sem memória\n"); return 1; } *p = 5; printf("&d\n", *p); free(p); return 0; }
Aloca de forma dinâmica espaço para um inteiro
Alocação dinâmica de memória
malloc
Utilizamos a função malloc() quando não conseguimos prever a quantidade de memória que nosso programa irá necessitar.
A função malloc() pode ser utilizada em run time para determinar o tamanho de um array.
Exemplochar * p; p = malloc(50);
free
Libera memória alocada previamente
Exemplo
free(p);
Alocação dinâmica de memória
void main() {
int numero = 10;
int *arranjo;
arranjo=(int *)malloc(numero * sizeof(int));
for (i=0; i < numero; i++) {
arranjo[i] = i;
}
free(arranjo);
}
Aloca de forma dinâmica espaço para um array de inteiros de 10 posições
#include <stdio.h> #include <stdlib.h> #include <conio.h>
int main() {
int *a; int i, k, m, min, temp, n;
/* Alocar memória para guardar o array */ printf("Quantos números quer ordenar? "); scanf("%d", &n); a = (int *) malloc( n * sizeof(int) );
if( a == NULL ) { printf("ERRO: nao ha memoria.\n"); exit(1); }
/* Receber os valores a ordenar */ for (i=0; i<n; i++) { printf("%d.º numero -> ",i+1); scanf("%d",&a[i]); }
/* Ordenar o array */ for( k=0; k<=n-1; k++ ) { /* descobre o índice do mínimo */ min = a[k]; m = k; for( i=k; i<=n-1; i++ ) if( a[i] < min ){ min = a[i]; m = i; }
/* troca a[k] com a[m] */ temp = a[k]; a[k] = a[m]; a[m] = temp; }
/* Escrever os elementos ordenados */ for( i=0; i<n; i++ ) printf("%d ", a[i]); printf("\n");
free( a ); /* libertar a memória */
getche();return 0;}
Estrutura de Dados Compostos
(Structs)
Definição
Uma estrutura (struct) ou registro em C é uma coleção de um ou mais valores, agrupados sob um único nome.
Estruturas constituem um recurso importante para organizar os dados utilizados por um programa graças à possibilidade de tratar um grupo de valores como uma única variável
Exemplo de uso
struct ponto { int x; int y;};
struct funcionario { int registro; char nome[30]; char depto[5]; float salario;};
Exemplo de uso
As declarações de ponto e funcionario, definem os respectivos tipos de dados, que podem ser utilizados em declarações de variáveis. Exemplos:
struct ponto p1, p2, p3; struct funcionario Joao;
Na primeira declaração, estão sendo declaradas as variáveis p1, p2 e p3 do tipo ponto. Na segunda declaração, é declarada a variável Joao do tipo funcionário.
Exemplo de uso
Para uma variável do tipo ponto, dizemos que x e y são seus campos ou membros. Os campos de uma variável podem ser acessados individualmente como variáveis usando-se o nome da variável seguido de "." e o nome do campo. Exemplos:
p1.x = 10;p1.y = 20;p2.x = p1.x + 5;p2.y = p2.y + 5;
Além disso, é possível atribuir a uma estrutura o valor de outra estrutura do mesmo tipo. Exemplos:
funcionario f = Joao;p3 = p2;
Estruturas complexas
Os campos de uma estrutura podem ser de qualquer tipo: tipos simples (int, char, float, etc), vetores, ou até mesmo estruturas. Exemplo:
struct retangulo { struct ponto pa; struct ponto pb;}
Uso de estruturas com funções
Uma vez que o tipo de uma estrutura foi declarado, é possível utilizá-lo em outras declarações (variáveis simples, vetores, funções, etc).
...struct ponto poligono[10];...
float dist(ponto p, ponto q) { int dx = p.x - q.x; int dy = p.y - q.y; return sqrt((double)dx*dx + (double)dy*dy);}
Passagem de estrutura por referência
Uma estrutura pode ser passada como parâmetro por referência numa função. Quando se usa uma referência (apontador), o acesso aos campos da mesma é feito através do operador "->" ao invés de ".". Exemplo:
void moveP(ponto* p, int dx, int dy){ p -> x += dx; p -> y += dy;}
...
moveP(&(r -> pa), dx, dy); moveP(&(r -> pb), dx, dy);
Retornando uma estrutura
Uma função pode ter uma estrutura como valor de retorno
struct ponto constroiPonto(int x, int y){ struct ponto temp; temp.x = x; temp.y = y; return temp;}
...struct ponto Origem = constroiPonto(0,0);
Declaração com valores iniciais
Ao declararmos uma estrutura, podemos também definir o seu valor inicial, de forma análoga a aquela utilizada para vetores. Exemplos:
struct ponto origem = {0,0};...struct ponto trapezio[] = { { 5,5}, {5, 10}, {10,5}, {10,13} };...
Usando ponteiros com structs
struct data{int dia;int mês; int ano;};
Definindo uma variável do tipo datastruct data dt;
Definindo um ponteiro para dtstruct data *pdt = &dt;
Fazendo referência a um elemento da estruturadt.dia ou (*pdt).dia ou pdt->diadt.mes ou (*pdt).mes ou pdt->mêsdt.ano ou (*pdt).ano ou pdt->ano
#include <stdio.h>typedef struct estrutura{ int valor; } ESTRUTURA;
void incrementa(ESTRUTURA * e){ printf(" Valor --> %i \n", e->valor); printf(" Valor --> %i \n", (*e).valor); /* outra forma de acessar */ (e->valor)++; /* incrementa valor */}
int main(){ ESTRUTURA d; /* declara variavel struct */ d.valor = 0; /* atribui valor inicial */ printf("Antes da funcao --> %d \n", d.valor); incrementa(&d); /* invoca a funcao */ printf("Apos a funcao --> %d\n", d.valor); return 0;
}
Exemplo de programa demonstrando uso de ponteiro, passagem de parâmetro
para função e estrutura
Alocação dinâmica de estruturas
É preciso armazenar esse endereço retornado pela malloc num ponteiro de tipo apropriado
Para alocar um tipo de dado que ocupa vários bytes, é preciso recorrer ao operador sizeof, que diz quantos bytes o tipo especificado tem
Vamos utilizar outra forma de declaração da struct:
struct tipo_data{
int dia, mes, ano;
};
typedef struct tipo_data DATA;
ATENÇÃO: data é o nome to tipo
Outra forma de declaração
typedef struct tipo_data{
int dia, mes, ano;
} DATA;
DATA *d;
d = malloc (sizeof (DATA));
d->dia = 31;
d->mes = 12;
d->ano = 2008;