ine - ufsc - disciplina estruturas de dados - prof. dr. aldo von wangenheim página 1 estruturas de...

31
C - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem de Parâmetros e Modelo de Memória

Upload: vasco-abreu-braga

Post on 07-Apr-2016

226 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1

Estruturas de Dados - T.332

Capítulo 3Parte 1:

Ponteiros, Passagem de Parâmetros e Modelo de Memória

Page 2: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 2

3.1 Variáveis Apontador (Ponteiros)

DefiniçãoDefinição: Um ponteiro é uma variável cujo : Um ponteiro é uma variável cujo conteúdo é um conteúdo é um endereço de memóriaendereço de memória. .

Esse endereço normalmente é a Esse endereço normalmente é a posição de uma posição de uma outra variável na memóriaoutra variável na memória. .

Se uma variável contém o endereço de uma outra, Se uma variável contém o endereço de uma outra, então a primeira variável é dita então a primeira variável é dita apontar para a apontar para a segundasegunda. .

Page 3: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 3

3.1. Declaração de Ponteiros

A declaração de uma variável do tipo ponteiro (ou A declaração de uma variável do tipo ponteiro (ou apontador) consiste do apontador) consiste do tipo basetipo base (aquele para o (aquele para o qual o ponteiro vai apontar), um qual o ponteiro vai apontar), um ** e o e o nomenome da da variável. variável.

A forma geral é: A forma geral é: tipo *nome; tipo *nome;

ou ou

tipo* nome;tipo* nome;

Page 4: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 4

Declaração de Ponteiros

Exemplos:Exemplos:int *contador; int *contador; ponteiro para um inteiroponteiro para um inteiro

char *meuString; char *meuString; ponteiro para caracteresponteiro para caracteres

float *raizQuadrada; float *raizQuadrada; ponteiro para realponteiro para real. .

Caso especial: Caso especial: void *simplesPonteiro; void *simplesPonteiro; ponteiro genéricoponteiro genérico. .

Page 5: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 5

Declarações que também devolvem ponteiros:

char nome[30]; char nome[30]; nomenome sozinho é também um ponteiro para sozinho é também um ponteiro para

caracter, que aponta para o primeiro elemento do caracter, que aponta para o primeiro elemento do nome. nome.

Exemplo: Exemplo: main ()main () {{ char char nome[30]; nome[30];

char *apontaPraNome;char *apontaPraNome; int *numero;int *numero; ..............

apontaPraNome = nome; apontaPraNome = nome; /* só o endereço *//* só o endereço */ }}

Page 6: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 6

3.2. Operadores de Ponteiros

Existem dois operadores especiais para ponteiros:Existem dois operadores especiais para ponteiros:

* * indireção. indireção. Devolve o valor apontado pelo ponteiro. Devolve o valor apontado pelo ponteiro.

& & operador de endereço. operador de endereço. Devolve o endereço na memória de seu operando.Devolve o endereço na memória de seu operando.

Page 7: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 7

Exemplosmain ()main () {{ int int *aponta;*aponta; int valor1, valor2;int valor1, valor2;

valor1 = 5;valor1 = 5; // inicializa valor1 com 5// inicializa valor1 com 5 aponta = &valor1;aponta = &valor1; // aponta recebe o endereço// aponta recebe o endereço // de valor1, ou seja:// de valor1, ou seja: // passa a apontar para valor1// passa a apontar para valor1 valor2 = *aponta;valor2 = *aponta; // valor2 recebe o valor // valor2 recebe o valor // apontado por aponta, nesse// apontado por aponta, nesse // caso 5, pois aponta possui// caso 5, pois aponta possui // como valor o endereço de // como valor o endereço de // valor1// valor1 }} PrecedênciaPrecedência: Tanto o : Tanto o && como o como o ** possuem precedência possuem precedência

maior do que todos os outros operadores, com exceção do maior do que todos os outros operadores, com exceção do menos unário, que possue a mesma.menos unário, que possue a mesma. int valor; int *aponta; valor = *aponta++ int valor; int *aponta; valor = *aponta++

Page 8: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 8

3.3. Aritmética de Ponteiros: Expressões

envolvendo Ponteiros A linguagem "C" permite que se faça uma série de A linguagem "C" permite que se faça uma série de

operações utilizando ponteiros, inclusive várias operações utilizando ponteiros, inclusive várias operações aritméticas, como soma e subtração, operações aritméticas, como soma e subtração, além de comparações entre ponteiros. além de comparações entre ponteiros.

Isto é muito útil, pode porém, ser também muito Isto é muito útil, pode porém, ser também muito perigoso, pois permite ao programador uma perigoso, pois permite ao programador uma liberdade que em nenhuma outra linguagem de liberdade que em nenhuma outra linguagem de programação (exceto os assemblers) é possível. programação (exceto os assemblers) é possível.

Page 9: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 9

3.3.1. Atribuição A maior parte dos aspectos da atribuição vimos no A maior parte dos aspectos da atribuição vimos no

capítulo anterior. A título de reforço, observe-se que: capítulo anterior. A título de reforço, observe-se que: Atribuição direta entre ponteiros passa o Atribuição direta entre ponteiros passa o endereço de endereço de

memória apontadomemória apontado por um para o outro. por um para o outro. int *p1, *p2, x;int *p1, *p2, x;x = 4;x = 4;p1 = &x; /* p1 passa a apontar para x */p1 = &x; /* p1 passa a apontar para x */p2 = p1; /* p2 recebeu o valor de p1, que é */p2 = p1; /* p2 recebeu o valor de p1, que é */ /* o endereço de x, ou seja: p2 *//* o endereço de x, ou seja: p2 */ /* também aponta para x. *//* também aponta para x. */printf ("%p", p2 ); /* imprime o endereço de x */printf ("%p", p2 ); /* imprime o endereço de x */printf ("%i", *p2 ); /* imprime o valor apontado por */printf ("%i", *p2 ); /* imprime o valor apontado por */ /* p2, seja: o valor de x. *//* p2, seja: o valor de x. */

O operador de endereço &, quando usado como operador sobre um O operador de endereço &, quando usado como operador sobre um ponteiro, devolve o endereço ocupado por ponteiro, devolve o endereço ocupado por este ponteiroeste ponteiro, , nãonão o o endereço apontado por ele!!!endereço apontado por ele!!!

Page 10: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 10

3.3.2. Aritmética de Ponteiros Duas operações aritméticas são válidas com Duas operações aritméticas são válidas com

ponteiros: adição e subtração. Estas são muito úteis ponteiros: adição e subtração. Estas são muito úteis com vetores. com vetores.

A expressão abaixo é válida em "C": A expressão abaixo é válida em "C": int *p1, *p2, *p3, *p4, x=0;int *p1, *p2, *p3, *p4, x=0; p1 = &x;p1 = &x; p2 = p1++;p2 = p1++; p3 = p2 + 4;p3 = p2 + 4; p4 = p3 - 5; /* p4 acaba tendo o mesmo valor que p1 */p4 = p3 - 5; /* p4 acaba tendo o mesmo valor que p1 */ /* no começo. *//* no começo. */ /* Note que p1 foi incrementado e *//* Note que p1 foi incrementado e */ /* agora tem o valor (&x + 1). *//* agora tem o valor (&x + 1). */

Observe que aqui as expressões *p2 e *p3 vão resultar em um erro, já Observe que aqui as expressões *p2 e *p3 vão resultar em um erro, já que esses ponteiros estarão apontando para áreas de memória que não que esses ponteiros estarão apontando para áreas de memória que não estão associadas com nenhuma variável. O único endereço de memória estão associadas com nenhuma variável. O único endereço de memória acessável é o de x.acessável é o de x.

Page 11: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 11

Aritmética Para o cálculo do incremento ou decremento é usado Para o cálculo do incremento ou decremento é usado

sempre o sempre o TAMANHO DO TIPO BASE DO PONTEIROTAMANHO DO TIPO BASE DO PONTEIRO. . Isto significa que se p1 aponta para o endereço 2000, p1 + 2 Isto significa que se p1 aponta para o endereço 2000, p1 + 2

não necessariamente vai ser igual a 2002. Se o tipo base é um não necessariamente vai ser igual a 2002. Se o tipo base é um inteiro (int *p1), que em Unix inteiro (int *p1), que em Unix sempresempre possui tamanho 4 bytes, possui tamanho 4 bytes, então p1 + 2 é igual a 2008. então p1 + 2 é igual a 2008.

Ou seja: o valor de p1 adicionado de duas vezes o tamanho do Ou seja: o valor de p1 adicionado de duas vezes o tamanho do tipo base.tipo base.

No exemplo anterior, se o endereço de x é 1000: No exemplo anterior, se o endereço de x é 1000: p1 recebe o valor 1000, endereço de memória de x. p1 recebe o valor 1000, endereço de memória de x. p2 recebe o valor 1004 e p1 tem seu valor atualizado para p2 recebe o valor 1004 e p1 tem seu valor atualizado para

1004. 1004. p3 recebe o valor 1004 + 4 * 4 = 1020. p3 recebe o valor 1004 + 4 * 4 = 1020. p4 recebe o valor 1020 - 5 * 4 = 1000. p4 recebe o valor 1020 - 5 * 4 = 1000.

Se as variáveis acima fossem do tipo char e char* (1 byte de tipo Se as variáveis acima fossem do tipo char e char* (1 byte de tipo base), os endereços seriam, respectivamente: 1000, 1001, 1001, base), os endereços seriam, respectivamente: 1000, 1001, 1001, 1005 e 1000.1005 e 1000.

Page 12: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 12

3.3.3. Comparações entre ponteiros Você pode comparar ponteiros, para saber se um Você pode comparar ponteiros, para saber se um

ponteiro aponta para um endereço de memória ponteiro aponta para um endereço de memória mais alto do que outro. Exemplo: mais alto do que outro. Exemplo:

int *p, *q;int *p, *q;

........

if (p < q) if (p < q)

printf("p aponta para um endereço menor que o de q");printf("p aponta para um endereço menor que o de q");

é um trecho de programa perfeitamente válido em é um trecho de programa perfeitamente válido em "C"."C". Isto pode ser útil em testes em matrizes e vetores.Isto pode ser útil em testes em matrizes e vetores.

Page 13: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 13

3.3.4 Exercício: Para fazer em casa Reimplemente o seu programinha de pilha com Reimplemente o seu programinha de pilha com

vetor de números inteiros usando como TOPO um vetor de números inteiros usando como TOPO um ponteiro para inteiro, que você incrementa, ponteiro para inteiro, que você incrementa, decrementa e testa, para saber se a pilha está decrementa e testa, para saber se a pilha está cheia, vazia, etc. cheia, vazia, etc.

Para resolver: Para resolver: Modifique a estrutura tipoPilha da seguinte forma: Modifique a estrutura tipoPilha da seguinte forma:

constantes Maxpilha = 100; constantes Maxpilha = 100; tipo Pilha { tipo Pilha { inteiro dados[Maxpilha]; inteiro dados[Maxpilha]; inteiro *topo; inteiro *topo; }; };

Page 14: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 14

Exercício em Casa II Modifique os algoritmos de manipulação da pilha de Modifique os algoritmos de manipulação da pilha de

forma que se utilize ponteiros para inteiro para forma que se utilize ponteiros para inteiro para referenciar os elementos da pilha.referenciar os elementos da pilha.

Exemplo: Exemplo: Inteiro FUNÇÃO empilha(inteiro dado) Inteiro FUNÇÃO empilha(inteiro dado) início início SE (pilhaCheia) ENTÃO SE (pilhaCheia) ENTÃO RETORNE(ErroPilhaCheia); RETORNE(ErroPilhaCheia); SENÃO SENÃO ""Se houver espaco, incremento o ponteiro topo Se houver espaco, incremento o ponteiro topo e faco o valor apontado por topo receber o novo e faco o valor apontado por topo receber o novo dadodado" " aPilha.topo <- aPilha.topo + 1. aPilha.topo <- aPilha.topo + 1. *(aPilha.topo) <- dado; *(aPilha.topo) <- dado; RETORNE(aPilha.topo); RETORNE(aPilha.topo); FIM SE FIM SE fim;fim;

Page 15: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 15

Exercício em Casa III Lembre-se de adaptar a inicialização da pilha e também os Lembre-se de adaptar a inicialização da pilha e também os

testes de pilha cheia e vazia. Exemplos:testes de pilha cheia e vazia. Exemplos: FUNÇÃO inicializaPilha() FUNÇÃO inicializaPilha() início início ""Fazemos a topo apontar para um endereco de memoria Fazemos a topo apontar para um endereco de memoria anterior ao inicio do vetor dados para simbolizar anterior ao inicio do vetor dados para simbolizar que está vazia.que está vazia. " " aPilha.topo <- aPilha.dados - 1; aPilha.topo <- aPilha.dados - 1; fim; fim; Booleano FUNÇÃO pilhaVazia() Booleano FUNÇÃO pilhaVazia() início início SE (aPilha.topo < aPilha.dados) ENTÃO SE (aPilha.topo < aPilha.dados) ENTÃO ""O topo está apontando para um endereço de memória O topo está apontando para um endereço de memória anterior ao próprio início da pilha. Segundo a nossa anterior ao próprio início da pilha. Segundo a nossa definição, isto significa que a pilha está vazia.definição, isto significa que a pilha está vazia. " " RETORNE(Verdade) RETORNE(Verdade) SENÃO SENÃO RETORNE(Falso); RETORNE(Falso); fim; fim;

Page 16: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 16

3.4. Ponteiros e Matrizes

Ponteiros, Vetores e Matrizes possuem uma Ponteiros, Vetores e Matrizes possuem uma relação muito estreita em "C”relação muito estreita em "C” A qual podemos aproveitar de muitas formas para A qual podemos aproveitar de muitas formas para

escrever programas que ninguém entende... escrever programas que ninguém entende... A seguir veremos um exemplo.A seguir veremos um exemplo.

Page 17: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 17

char nome[30] = "José da Silva";char nome[30] = "José da Silva";char *p1, *p2;char *p1, *p2;char car;char car;int i;int i;p1 = nome; p1 = nome; // nome sozinho é um ponteiro// nome sozinho é um ponteiro // para o 1º elemento de nome[].// para o 1º elemento de nome[].car = nome[3]; car = nome[3]; // Atribui 'é' a car.// Atribui 'é' a car.car = p1[0]; car = p1[0]; // Atribui 'J' a car. Válido.// Atribui 'J' a car. Válido.p2 = &nome[5]; p2 = &nome[5]; // Atribui a p2 o endereço da 6ª// Atribui a p2 o endereço da 6ª // posição de nome, no caso 'd'.// posição de nome, no caso 'd'.printf( "%s", p2); printf( "%s", p2); // Imprime "da Silva"...// Imprime "da Silva"...

p2 = p1; p2 = p1; // Evidentemente válido.// Evidentemente válido.p2 = p1 + 5; p2 = p1 + 5; // Equivalente a p2 = &nome[5]// Equivalente a p2 = &nome[5]printf( "%s",(p1 + 5)); printf( "%s",(p1 + 5)); // Imprime "da Silva"...// Imprime "da Silva"...printf( "%s",(p1 + 20)); printf( "%s",(p1 + 20)); // Cuidado: Imprime lixo!!// Cuidado: Imprime lixo!!

for (i=0; strlen(nome)- 1; i++)for (i=0; strlen(nome)- 1; i++) {{ printf ("%c", nome[i]); printf ("%c", nome[i]); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc p2 = p1 + i;p2 = p1 + i; printf ("%c", *p2); printf ("%c", *p2); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc }}

Page 18: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 18

char nome[30] = "José da Silva";char nome[30] = "José da Silva";char *p1, *p2;char *p1, *p2;char car;char car;int i;int i;p1 = nome; p1 = nome; // nome sozinho é um ponteiro// nome sozinho é um ponteiro // para o 1º elemento de nome[].// para o 1º elemento de nome[].car = nome[3]; car = nome[3]; // Atribui 'é' a car.// Atribui 'é' a car.car = p1[0]; car = p1[0]; // Atribui 'J' a car. Válido.// Atribui 'J' a car. Válido.p2 = &nome[5]; p2 = &nome[5]; // Atribui a p2 o endereço da 6ª// Atribui a p2 o endereço da 6ª // posição de nome, no caso 'd'.// posição de nome, no caso 'd'.printf( "%s", p2); printf( "%s", p2); // Imprime "da Silva"...// Imprime "da Silva"...

p2 = p1; p2 = p1; // Evidentemente válido.// Evidentemente válido.p2 = p1 + 5; p2 = p1 + 5; // Equivalente a p2 = &nome[5]// Equivalente a p2 = &nome[5]printf( "%s",(p1 + 5)); printf( "%s",(p1 + 5)); // Imprime "da Silva"...// Imprime "da Silva"...printf( "%s",(p1 + 20)); printf( "%s",(p1 + 20)); // Cuidado: Imprime lixo!!// Cuidado: Imprime lixo!!

for (i=0; strlen(nome)- 1; i++)for (i=0; strlen(nome)- 1; i++) {{ printf ("%c", nome[i]); printf ("%c", nome[i]); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc p2 = p1 + i;p2 = p1 + i; printf ("%c", *p2); printf ("%c", *p2); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc }}

Page 19: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 19

char nome[30] = "José da Silva";char nome[30] = "José da Silva";char *p1, *p2;char *p1, *p2;char car;char car;int i;int i;p1 = nome; p1 = nome; // nome sozinho é um ponteiro// nome sozinho é um ponteiro // para o 1º elemento de nome[].// para o 1º elemento de nome[].car = nome[3]; car = nome[3]; // Atribui 'é' a car.// Atribui 'é' a car.car = p1[0]; car = p1[0]; // Atribui 'J' a car. Válido.// Atribui 'J' a car. Válido.p2 = &nome[5]; p2 = &nome[5]; // Atribui a p2 o endereço da 6ª// Atribui a p2 o endereço da 6ª // posição de nome, no caso 'd'.// posição de nome, no caso 'd'.printf( "%s", p2); printf( "%s", p2); // Imprime "da Silva"...// Imprime "da Silva"...

p2 = p1; p2 = p1; // Evidentemente válido.// Evidentemente válido.p2 = p1 + 5; p2 = p1 + 5; // Equivalente a p2 = &nome[5]// Equivalente a p2 = &nome[5]printf( "%s",(p1 + 5)); printf( "%s",(p1 + 5)); // Imprime "da Silva"...// Imprime "da Silva"...printf( "%s",(p1 + 20)); printf( "%s",(p1 + 20)); // Cuidado: Imprime lixo!!// Cuidado: Imprime lixo!!

for (i=0; strlen(nome)- 1; i++)for (i=0; strlen(nome)- 1; i++) {{ printf ("%c", nome[i]); printf ("%c", nome[i]); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc p2 = p1 + i;p2 = p1 + i; printf ("%c", *p2); printf ("%c", *p2); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc }}

Page 20: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 20

char nome[30] = "José da Silva";char nome[30] = "José da Silva";char *p1, *p2;char *p1, *p2;char car;char car;int i;int i;p1 = nome; p1 = nome; // nome sozinho é um ponteiro// nome sozinho é um ponteiro // para o 1º elemento de nome[].// para o 1º elemento de nome[].car = nome[3]; car = nome[3]; // Atribui 'é' a car.// Atribui 'é' a car.car = p1[0]; car = p1[0]; // Atribui 'J' a car. Válido.// Atribui 'J' a car. Válido.p2 = &nome[5]; p2 = &nome[5]; // Atribui a p2 o endereço da 6ª// Atribui a p2 o endereço da 6ª // posição de nome, no caso 'd'.// posição de nome, no caso 'd'.printf( "%s", p2); printf( "%s", p2); // Imprime "da Silva"...// Imprime "da Silva"...

p2 = p1; p2 = p1; // Evidentemente válido.// Evidentemente válido.p2 = p1 + 5; p2 = p1 + 5; // Equivalente a p2 = &nome[5]// Equivalente a p2 = &nome[5]printf( "%s",(p1 + 5)); printf( "%s",(p1 + 5)); // Imprime "da Silva"...// Imprime "da Silva"...printf( "%s",(p1 + 20)); printf( "%s",(p1 + 20)); // Cuidado: Imprime lixo!!// Cuidado: Imprime lixo!!

for (i=0; strlen(nome)- 1; i++)for (i=0; strlen(nome)- 1; i++) {{ printf ("%c", nome[i]); printf ("%c", nome[i]); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc p2 = p1 + i;p2 = p1 + i; printf ("%c", *p2); printf ("%c", *p2); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc }}

Page 21: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 21

char nome[30] = "José da Silva";char nome[30] = "José da Silva";char *p1, *p2;char *p1, *p2;char car;char car;int i;int i;p1 = nome; p1 = nome; // nome sozinho é um ponteiro// nome sozinho é um ponteiro // para o 1º elemento de nome[].// para o 1º elemento de nome[].car = nome[3]; car = nome[3]; // Atribui 'é' a car.// Atribui 'é' a car.car = p1[0]; car = p1[0]; // Atribui 'J' a car. Válido.// Atribui 'J' a car. Válido.p2 = &nome[5]; p2 = &nome[5]; // Atribui a p2 o endereço da 6ª// Atribui a p2 o endereço da 6ª // posição de nome, no caso 'd'.// posição de nome, no caso 'd'.printf( "%s", p2); printf( "%s", p2); // Imprime "da Silva"...// Imprime "da Silva"...

p2 = p1; p2 = p1; // Evidentemente válido.// Evidentemente válido.p2 = p1 + 5; p2 = p1 + 5; // Equivalente a p2 = &nome[5]// Equivalente a p2 = &nome[5]printf( "%s",(p1 + 5)); printf( "%s",(p1 + 5)); // Imprime "da Silva"...// Imprime "da Silva"...printf( "%s",(p1 + 20)); printf( "%s",(p1 + 20)); // Cuidado: Imprime lixo!!// Cuidado: Imprime lixo!!

for (i=0; strlen(nome)- 1; i++)for (i=0; strlen(nome)- 1; i++) {{ printf ("%c", nome[i]); printf ("%c", nome[i]); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc p2 = p1 + i;p2 = p1 + i; printf ("%c", *p2); printf ("%c", *p2); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc }}

Page 22: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 22

char nome[30] = "José da Silva";char nome[30] = "José da Silva";char *p1, *p2;char *p1, *p2;char car;char car;int i;int i;p1 = nome; p1 = nome; // nome sozinho é um ponteiro// nome sozinho é um ponteiro // para o 1º elemento de nome[].// para o 1º elemento de nome[].car = nome[3]; car = nome[3]; // Atribui 'é' a car.// Atribui 'é' a car.car = p1[0]; car = p1[0]; // Atribui 'J' a car. Válido.// Atribui 'J' a car. Válido.p2 = &nome[5]; p2 = &nome[5]; // Atribui a p2 o endereço da 6ª// Atribui a p2 o endereço da 6ª // posição de nome, no caso 'd'.// posição de nome, no caso 'd'.printf( "%s", p2); printf( "%s", p2); // Imprime "da Silva"...// Imprime "da Silva"...

p2 = p1; p2 = p1; // Evidentemente válido.// Evidentemente válido.p2 = p1 + 5; p2 = p1 + 5; // Equivalente a p2 = &nome[5]// Equivalente a p2 = &nome[5]printf( "%s",(p1 + 5)); printf( "%s",(p1 + 5)); // Imprime "da Silva"...// Imprime "da Silva"...printf( "%s",(p1 + 20)); printf( "%s",(p1 + 20)); // Cuidado: Imprime lixo!!// Cuidado: Imprime lixo!!

for (i=0; strlen(nome)- 1; i++)for (i=0; strlen(nome)- 1; i++) {{ printf ("%c", nome[i]); printf ("%c", nome[i]); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc p2 = p1 + i;p2 = p1 + i; printf ("%c", *p2); printf ("%c", *p2); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc }}

Page 23: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 23

char nome[30] = "José da Silva";char nome[30] = "José da Silva";char *p1, *p2;char *p1, *p2;char car;char car;int i;int i;p1 = nome; p1 = nome; // nome sozinho é um ponteiro// nome sozinho é um ponteiro // para o 1º elemento de nome[].// para o 1º elemento de nome[].car = nome[3]; car = nome[3]; // Atribui 'é' a car.// Atribui 'é' a car.car = p1[0]; car = p1[0]; // Atribui 'J' a car. Válido.// Atribui 'J' a car. Válido.p2 = &nome[5]; p2 = &nome[5]; // Atribui a p2 o endereço da 6ª// Atribui a p2 o endereço da 6ª // posição de nome, no caso 'd'.// posição de nome, no caso 'd'.printf( "%s", p2); printf( "%s", p2); // Imprime "da Silva"...// Imprime "da Silva"...

p2 = p1; p2 = p1; // Evidentemente válido.// Evidentemente válido.p2 = p1 + 5; p2 = p1 + 5; // Equivalente a p2 = &nome[5]// Equivalente a p2 = &nome[5]printf( "%s",(p1 + 5)); printf( "%s",(p1 + 5)); // Imprime "da Silva"...// Imprime "da Silva"...printf( "%s",(p1 + 20)); printf( "%s",(p1 + 20)); // Cuidado: Imprime lixo!!// Cuidado: Imprime lixo!!

for (i=0; strlen(nome)- 1; i++)for (i=0; strlen(nome)- 1; i++) {{ printf ("%c", nome[i]); printf ("%c", nome[i]); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc p2 = p1 + i;p2 = p1 + i; printf ("%c", *p2); printf ("%c", *p2); // Imprime 'J','o','s',etc// Imprime 'J','o','s',etc }}

Page 24: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 24

3.4.1. Matrizes de Ponteiros Ponteiros podem ser declarados como vetores ou Ponteiros podem ser declarados como vetores ou

matrizes multidimensionais. Exemplo: matrizes multidimensionais. Exemplo: int *vetor[30]; /* Vetor de 30 ponteiros para */int *vetor[30]; /* Vetor de 30 ponteiros para */ /* números inteiros. *//* números inteiros. */ int a=1, b=2, c=3;int a=1, b=2, c=3; vetor[0] = &a; /* vetor[0] passa a apontar p/a.*/vetor[0] = &a; /* vetor[0] passa a apontar p/a.*/ vetor[1] = &b;vetor[1] = &b; vetor[2] = &c;vetor[2] = &c; printf ( "a: %i, b: %i", *vetor[0], *vetor[1] );printf ( "a: %i, b: %i", *vetor[0], *vetor[1] ); /* Imprime "a: 1, b: 2"... *//* Imprime "a: 1, b: 2"... */ ImportantíssimoImportantíssimo: Note que o fato de você alocar um vetor de : Note que o fato de você alocar um vetor de

apontadores para inteiros, não implica que você alocou espaço apontadores para inteiros, não implica que você alocou espaço de memória para armazenar os valores desses inteiros. de memória para armazenar os valores desses inteiros. A operação acima foi possível porque com a declaração de a,b e c A operação acima foi possível porque com a declaração de a,b e c

este espaço foi alocado. este espaço foi alocado. As posições 0,1 e 2 do vetor só apontam para as posições de As posições 0,1 e 2 do vetor só apontam para as posições de

memória ocupadas por a, b e c.memória ocupadas por a, b e c.

Page 25: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 25

3.4.2. Ponteiros para Ponteiros e Indireção Múltipla Matrizes de ponteiros são normalmente utilizadas Matrizes de ponteiros são normalmente utilizadas

para a manipulação de coleções de Strings. para a manipulação de coleções de Strings. Suponhamos a seguinte função que exibe uma mensagem Suponhamos a seguinte função que exibe uma mensagem

de erro com base em um código de erro:de erro com base em um código de erro:

char *mensagem[] = char *mensagem[] = {/* vetor inicializado */{/* vetor inicializado */ "arquivo não encontrado","arquivo não encontrado", "erro de leitura","erro de leitura", "erro de escrita","erro de escrita", "impossível criar arquivo""impossível criar arquivo" };};void escreveMensagemDeErro (int num)void escreveMensagemDeErro (int num) {{ printf ("%s\n", mensagem[num]);printf ("%s\n", mensagem[num]); }}main ()main () {{ escreveMensagemDeErro( 3 );escreveMensagemDeErro( 3 ); }}

Page 26: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 26

No caso anterior, nem parece que estamos usando ponteiros. Se quiséssemos fazer o mesmo com inteiros, por Se quiséssemos fazer o mesmo com inteiros, por

exemplo em uma rotina que imprime todos os exemplo em uma rotina que imprime todos os valores apontados por um vetor de inteiros, já seria valores apontados por um vetor de inteiros, já seria diferente: diferente:

int *vetor[40];int *vetor[40];void imprimeTodos ()void imprimeTodos () { int i;{ int i; for (i=0; i < 40; i++) for (i=0; i < 40; i++)

printf ("%i\n", *vetor[i]);printf ("%i\n", *vetor[i]); }} Você pode ter um ponteiro apontando para outro Você pode ter um ponteiro apontando para outro

ponteiro que por sua vez aponta para um valor. ponteiro que por sua vez aponta para um valor. Esta situação é chamada de Esta situação é chamada de Indireção MúltiplaIndireção Múltipla ou ou

de de Ponteiros para PonteirosPonteiros para Ponteiros..

Page 27: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 27

Indireção Múltipla Uma forma de declarar ponteiros para ponteiros é a Uma forma de declarar ponteiros para ponteiros é a

forma implícita já vista antes. forma implícita já vista antes. Outra forma que podemos utilizar, quando não Outra forma que podemos utilizar, quando não

sabemos de antemão o espaço em memória a ser sabemos de antemão o espaço em memória a ser utilizado, é de declarar um ponteiro explicitamente utilizado, é de declarar um ponteiro explicitamente como sendo de indireção: como sendo de indireção:

#include <stdio.h#include <stdio.hmain ()main () {{ int x, *p, int x, *p, **q**q; ; // q é um ponteiro para um // q é um ponteiro para um // ponteiro a inteiro.// ponteiro a inteiro. x = 10;x = 10; p = &x; p = &x; // p aponta para x// p aponta para x q = &p; q = &p; // q aponta para p// q aponta para p printf ("%i\n", **q); printf ("%i\n", **q); // imprime 10...// imprime 10... }}

Page 28: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 28

3.5. Passagem de Parâmetros usando Ponteiros#include <stdio.h#include <stdio.hchar *a = "Bananarama";char *a = "Bananarama";char b[80] = "uma coisa besta";char b[80] = "uma coisa besta";char *c[5];char *c[5];

void teste1 (char *d[] )void teste1 (char *d[] ) { { /* Recebe vetor de ponteiros para caracter de tamanho indefinido *//* Recebe vetor de ponteiros para caracter de tamanho indefinido */ printf( "Teste1: d[0]:%s e d[1]:%s\n\n", d[0], d[1]);printf( "Teste1: d[0]:%s e d[1]:%s\n\n", d[0], d[1]); }}

void teste2 (char **d )void teste2 (char **d ) { { /* Recebe ponteiro para ponteiro para caracter *//* Recebe ponteiro para ponteiro para caracter */ printf( "Teste2: d[0]:%s e d[1]:%s\n", d[0], d[1]);printf( "Teste2: d[0]:%s e d[1]:%s\n", d[0], d[1]); printf( "Teste3: d[0]:%s e d[1]:%s\n", *d, printf( "Teste3: d[0]:%s e d[1]:%s\n", *d, *(d + 1)*(d + 1));); }}

main ()main () {{ c[0] = a;c[0] = a; c[1] = b;c[1] = b; printf( "a: %s e b: %s\n\n", a, b);printf( "a: %s e b: %s\n\n", a, b); printf( "c[0]: %s e c[1]: %s\n\n", c[0], c[1]);printf( "c[0]: %s e c[1]: %s\n\n", c[0], c[1]); teste1 ( c );teste1 ( c ); teste2 ( c );teste2 ( c );}}

Page 29: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 29

3.6 Passagem de Parâmetros Existem basicamente três tipos de formas de Existem basicamente três tipos de formas de

passagem de parâmetros para um função:passagem de parâmetros para um função: Por Por valorvalor

Quando Quando copiamoscopiamos o valor de uma variável para denro do o valor de uma variável para denro do parâmetro de uma funçãoparâmetro de uma função

Por Por referênciareferência Quando passamos para uma função uma Quando passamos para uma função uma referênciareferência a a

uma região de memória onde está o valor desta variáveluma região de memória onde está o valor desta variável Por Por nomenome

Quando passamos para uma função o nome de uma Quando passamos para uma função o nome de uma variável, que está em algum lugar e contém o valor.variável, que está em algum lugar e contém o valor.

Usada somente em LISP e algumas antigas implementações Usada somente em LISP e algumas antigas implementações de ALGOL. Sem interesse para nós.de ALGOL. Sem interesse para nós.

Page 30: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 30

3.6 Passagem de Parâmetros: Modelo de Memória

Para entendermos as nuances da passagem de Para entendermos as nuances da passagem de parâmetros de forma fundamentada, temos parâmetros de forma fundamentada, temos primeiro que entender o primeiro que entender o Modelo de MemóriaModelo de Memória de de um computador.um computador.

Com isto poderemos entender qual a diferença Com isto poderemos entender qual a diferença entre uma variável entre uma variável locallocal, uma variável , uma variável globalglobal e e memória alocada memória alocada dinamicamentedinamicamente..

Page 31: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Estruturas de Dados - T.332 Capítulo 3 Parte 1: Ponteiros, Passagem

INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 31

3.6 Passagem de Parâmetros: Modelo de Memória Para entendermos o modelo de memória, vamos Para entendermos o modelo de memória, vamos

nos basear no modelo mais simples:nos basear no modelo mais simples: