A = p

Propaganda
CES-10 INTRODUÇÃO À
COMPUTAÇÃO
Capítulo IX
Ponteiros
Capítulo IX – Ponteiros
9.1 – Introdução
9.2 – Relação entre ponteiros e variáveis indexadas
9.3 – Alocação dinâmica de memória
9.4 – Variáveis indexadas, ponteiros e estruturas
como parâmetros e elementos de retorno
9.5 – Subprogramas como parâmetros
9.6 – Encadeamento de estruturas
9.1 – Introdução
9.1.1 – Constantes e variáveis do tipo ponteiro

As variáveis dos programas apresentados nos capítulos
anteriores são usadas para guardar e manipular valores de
determinados tipos

Endereços também podem ser manipulados em C

Sendo a uma variável declarada em um programa, &a é seu
endereço

Ponteiros são endereços

Assim como existem constantes e variáveis do tipo
int, float, char, cadeias de caracteres, vetores, matrizes e
estruturas
também existem constantes e variáveis do tipo ponteiro

O endereço de uma variável a declarada num bloco qualquer
permanece o mesmo durante a execução do bloco


Então &a é uma constante do tipo ponteiro
Variável do tipo ponteiro armazena um endereço que pode
ser alterado durante a execução do programa

Variáveis-ponteiros podem guardar endereços de outras
variáveis

Diz-se que elas apontam para essas outras variáveis

Na declaração de uma variável-ponteiro, deve-se especificar
o tipo das variáveis para as quais ela pode apontar

Exemplo: na declaração
float *p;
p é uma variável-ponteiro destinada a guardar endereços de
variáveis do tipo float, ou a apontar para elas
Abreviadamente, p é um ponteiro para o tipo float
Exemplo: seja trecho de programa:
int c = 237, b = 15, *q;
double a = 13.5, *p;
p = &a; q = &b;
printf ("Endereco(p) = %d\n", &p);
printf ("
p = %d\n", p);
printf ("Endereco(a) = %d\n", &a);
printf ("Endereco(q) = %d\n", &q);
printf ("
q = %d\n", q);
printf ("Endereco(b) = %d\n", &b);
printf ("Endereco(c) = %d\n", &c);
printf ("
a = %g\n", a);
printf ("
b = %d\n", b);
printf ("
c = %d\n", c);
Resultado
Endereco(p)
p
Endereco(a)
Endereco(q)
q
Endereco(b)
Endereco(c)
a
b
c
=
=
=
=
=
=
=
=
=
=
1638204
1638208
1638208
1638216
1638220
1638220
1638224
13.5
15
237
Com este resultado,
pode-se desenhar o
mapa da memória a
seguir
int c = 237, b = 15, *q;
double a = 13.5, *p;
p = &a; q = &b;
Endereco(p)
p
Endereco(a)
Endereco(q)
q
Endereco(b)
Endereco(c)
a
b
c
Resultado
=
=
=
=
=
=
=
=
=
=
1638204
1638208
1638208
1638216
1638220
1638220
1638224
13.5
15
237
1638204
1638208
p
13.5
a
1638220
q
15
b
237
c
1638208
1638216
1638220
1638224
int c = 237, b = 15, *q;
double a = 13.5, *p;
p = &a; q = &b;
1638204
p
13.5
a
1638220
q
15
b
237
c
1638208
&a é uma constante-ponteiro
para double
&b é uma constante-ponteiro
para int
1638208
1638216
1638220
1638224
int c = 237, b = 15, *q;
double a = 13.5, *p;
p = &a; q = &b;
1638204
p
13.5
a
1638220
q
15
b
237
c
1638208
q é um ponteiro para o tipo int
p é um ponteiro para o tipo
double
p recebe o endereço de a
q recebe o endereço de b
1638216
p aponta para a
q aponta para b
1638220
a é apontada por p
b é apontada por q
1638208
1638224
int c = 237, b = 15, *q;
double a = 13.5, *p;
p = &a; q = &b;
1638204
1638208
p
13.5
a
1638220
q
15
b
237
c
1638208
Endereços, isto é ponteiros,
ocupam 4 bytes
Não é recomendável fazer:
p = &b , pois
1638216
b é um int e
p é um ponteiro para o tipo
double
1638220
Alguns compiladores não
aceitam isso
1638224
int c = 237, b = 15, *q;
double a = 13.5, *p;
p = &a; q = &b;
1638204
13.5
15
b
ou simplesmente:
p
q
13.5
a
1638220
q
15
b
237
c
a
1638216
q
p
1638208
Duas formas de representação
gráfica:
p
1638208
1638220
13.5
a
15
b
1638224

Endereços são números inteiros não-negativos

Então, esses números podem ser atribuídos às variáveis
ponteiros, desde que sejam convertidos para endereços
usando-se fator de conversão

Exemplo: seja a declaração double *p;
muitos compiladores não permitem
p = 48237;
O lado esquerdo deveria receber um endereço e não um
inteiro
No entanto, a seguinte atribuição é aceita:
p = (double *) 48237;
O inteiro 48237
é convertido no
endereço 48237

Muitos compiladores também não aceitam atribuição entre
ponteiros de tipos diferentes

Exemplo: pelas declarações
double *p; int *q;
muitos compiladores não aceitam p = q;
É necessário fazer

p = (double *)q;
nem
e
q = p;
q = (int *)p;
Se alguns compiladores aceitam certas irregularidades, mas
outros não, para melhorar portabilidade, é bom não
cometê-las
A palavra ponteiro poderá ser usada tanto para
variáveis como para valores do tipo ponteiro

Usando ponteiros, o endereço zero de memória é considerado
de forma muito especial

Em C há uma constante simbólica para ele: NULL

As seguintes atribuições são equivalentes:
p = 0;
e
p = NULL;

Diz-se que p está aterrado, ou então que aponta para lugar
nenhum

É diferente de dizer que p está indefinido, pois tal lugar é
perfeitamente definido
Aqui, lugar nenhum é diferente
de nenhum lugar

Representações gráficas para o aterramento de ponteiros:
p
p
p
•
p NULL
9.1.2 – Acesso ao local apontado por um ponteiro


Seja a declaração:
int a, b, *p;
p
O local apontado por p é referenciado por *p
a
*p
b
*p

Executando-se p = &a; então *p passa a coincidir com a

Depois, executando-se p = &b;
coincidir com b

Seja a declaração int a, *p = &a;
então *p passa a
Correto:
É
errado pdizer:
é ponteiro
local
apontado porcom
inicializado
p recebe
o
o endereço
endereço
dede
aa

Exemplo: Seja o seguinte trecho de programa:
int a, b = 2, *p;
p = &a;
*p = 1;
b = *p;
a
1
Inicialmente
Prosseguindo
b
21
p

Exemplo: Seja a seguinte declaração:
int a = 2, b = 5, *p = &a, *q = &b;
Inicialmente:
Voltando
Fazendo
Fazendo*p
àp situação
==q;
*q; inicial:
a
52
p
b
5
q
Apesar dos conteúdos de *p e *q serem iguais,
o conteúdo de p é diferente do conteúdo de q
(*p == *q)
e
(p ≠ q)

Exemplo: Seja o seguinte trecho de programa:
int *p, a;
p = (int *)134;
a = *p;
printf ("*p = %d", a);
Erro de execução:
p
Região
protegida
pelo
sistema
operacional
a
O endereço 134 é
protegido pelo sistema
operacional
O comando a = *p tenta
copiar o valor ali
guardado
RAM
134

O endereço zero também é protegido pelo sistema
operacional

Portanto, ao se aterrar um ponteiro, a simples referência ao
local apontado por ele gera o mesmo tipo de erro

Então a sequência de comandos
p = NULL; a = *p;
não pode ser usada

Sejam p e q dois ponteiros quaisquer

A divisão entre os conteúdos dos locais apontados por eles
não pode ser expressa por
*p/*q

A sequência de caracteres “/*” inicia um comentário

Deve-se deixar pelo menos um espaço em branco no meio
dessa sequência:
*p/ *q

Nos atuais ambientes de programação esse problema é
facilmente detectado

Ali os comentários são escritos com tipo e coloração das
letras distintos do resto do texto dos programas

Em ambientes mais antigos, isso já causou muitos atrasos
na programação

As principais utilidades dos ponteiros são:



Alocação dinâmica de variáveis indexadas
Passagem por referência de argumentos a parâmetros
Encadeamento de estruturas

Os dois primeiros itens eram realizados não por intermédio
de ponteiros nas linguagens de programação antes de C

Para o terceiro sim, tais linguagens já usavam ponteiros

Aliás, o encadeamento de estruturas foi a principal razão
para a criação de ponteiros

Ele é abordado no último tópico deste capítulo e usado
intensamente em Estruturas de Dados
Capítulo IX – Ponteiros
9.1 – Introdução
9.2 – Relação entre ponteiros e variáveis indexadas
9.3 – Alocação dinâmica de memória
9.4 – Variáveis indexadas, ponteiros e estruturas
como parâmetros e elementos de retorno
9.5 – Subprogramas como parâmetros
9.6 – Encadeamento de estruturas
9.2 – Relação entre Ponteiros e
Variáveis Indexadas
9.2.1 – O ponteiro-nome de variável indexada

Em C, diferentemente das linguagens anteriores, há uma forte
relação entre ponteiros e variáveis indexadas

O nome de uma variável indexada é o endereço do
primeiro de seus elementos


É uma constante-ponteiro apontando para seu elemento
zero
Não tem um local exclusivo na memória

O ponteiro-nome de variável indexada aponta para um local
fixo (elemento de índice zero)

Então ele tem valor constante durante a execução do
programa (ponteiro de valor fixo)

Não pode ser alterado como um ponteiro comum

Seja a declaração
int A[8];

Representação gráfica de A:
int A[8];

O nome A não tem local exclusivo; &A é o endereço do início
do vetor A na memória

O valor de A (ou seja, A, simplesmente) é o endereço de A[0]
(&A[0])

A escrita do valor do local apontado por A (ou seja, de *A)
resulta no conteúdo de A[0]

O nome de uma variável indexada pode ser atribuído a
um ponteiro de mesmo tipo
Exemplo: seja o seguinte trecho de programa:
int i, A[8], B[5], *p;
p = A;
p = B;
Inicialmente:
Após
p = B;
A;
A
Proibidos:
p tem localAexclusivo
= p;
B = p;
A e B não têm
A = B;
B = A;
A = &i;
B = &i;
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7]
p ?
B
p tornou-se equivalente a B:
A:
B[0] B[1] B[2] B[3] B[4]
p[0]  B[0],
A[0], p[1]  A[1],
B[1], ... ,
p[7]  B[4]
p[4]
A[7]
*A  A[0] e *B  B[0]
p se tornou variável indexada
9.2.2 – Aritmética de endereços e ponteiros

Seja a seguinte declaração: int *p, i;

A expressão p+i é o endereço do iésimo inteiro após o inteiro
apontado por p (p+i = &p[i])
*p *(p+1)
*(p+i)
p
p[i]
p[0] p[1]

Seja a seguinte declaração: int A[10], i;
Analogamente, A+i = &A[i] e *(A+i)  A[i]
*A *(A+1)
*(A+i)
A
A[0] A[1]
A[i]
Exemplo: seja o seguinte
p = 1638204; &A[0] = 1638204;
de programa:
q trecho
= 1638212;
&A[1] = 1638212;
p
A[0]
r = 1638220; &A[2] = 1638220;
q-p = 1;
r-p = 2;
Diferenças de
índices
endereços
ender(q)-ender(p) = 8;
ender(r)-ender(p) = 16;
q
No vídeo
A[1]
double *p, *q, *r, A[3];
p = A; q = p+1; r = p+2;
r
printf ("p = %d; &A[0] = %d;",
p, &A[0]);
A[2]
printf ("\nq = %d; &A[1] = %d;",
q, &A[1]);
printf ("\nr = %d; &A[2] = %d;",
r, &A[2]);
printf ("\n\nq-p = %d;\nr-p = %d;", q-p, r-p);
printf("\n\nender(q)-ender(p) = %d;\nender(r)-ender(p) = %d;",
(int)q-(int)p, (int)r-(int)p);

Relações entre ponteiros e variáveis indexadas e entre
subscritos e o operador unário ‘*’ possibilitam várias
alternativas para realizar certas operações

Por exemplo, considerando-se a seguinte declaração:
int i, A[10] = {1,2,3,4,5,6,7,8,9,10}, *p, soma;
A soma dos elementos de A pode ser feita por:
1)
2)
3)
4)
5)
for
for
for
for
for
(soma
(soma
(soma
(soma
(soma
=
=
=
=
=
0, i = 0;
0, i = 0;
0, p = A;
0, p = A,
0,p = A,i
i
i
p
i
=
< 10; i++) soma += A[i];
< 10; i++) soma += *(A+i);
< &A[10]; p++) soma += *p;
= 0; i < 10; i++) soma += p[i];
0; i < 10; i++) soma += *(p+i);
Download