ponteiros.tex 37.2 KB
Newer Older
1 2 3 4
\documentclass[apostila.tex]{subfiles}


\begin{document}
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
5 6
\chapter{Ponteiros}

7 8 9
Ponteiros são ferramentas extremamente versáteis e flexíveis disponibilizadas pela linguagem C para
manipulação da memória. Através de ponteiros o programador tem controle praticamente total sobre o
armazenamento de dados na memória.
10

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
11 12 13
\section{O que são ponteiros?}

Para entender o que é um ponteiro é necessário visualizar a memória como se fosse um grande e contínuo
14
vetor. Vamos supor que a memória do computador é um vetor {\it M[n]}, como representado abaixo, {\bf N+1} é
15
o tamanho da memória:
16

Davisson Henrique Paulino's avatar
Davisson Henrique Paulino committed
17 18 19 20
\begin{tabular}{cllllllllllll}
  & 0                     & 1                     & 2                     & 3                     & 4                     & 5                     & 6                             & 7                     & 8                     & 9                     & ...                   & N                     \\ \cline{2-13} 
{\bf M}                     & \multicolumn{1}{|l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 12}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
\multicolumn{1}{l}{} &                       &                       &                       &                       &                       &                       & {\bf A}                       &                       &                       &                       &                       &                      
21
\end{tabular}
Davisson Henrique Paulino's avatar
Davisson Henrique Paulino committed
22

23

24

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
25
Em um programa C, é possível declarar uma variável qualquer e uma região desta memória será
26 27
automaticamente dedicada a esta variável. Por exemplo, considere a seguinte declaração:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
28
\begin{lstlisting}
29
int A;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
30
\end{lstlisting}
31 32


33 34 35
Quando o programa é executado, a declaração acima faz o sistema operacional alocar\footnote{Alocar uma memória para uma variável é obter uma região disponível da memória, de tamanho suficiente para conter
os dados desta variável.} uma região
disponível da memória, que será apelidada de {\bf A}. No exemplo, é ilustrada uma região da memória alocada.
36

37
\begin{tabular}{cllllllllllll}
38 39
  & 0                     & 1                     & 2                     & 3                     & 4                     & 5                     & 6                             & 7                     & 8                     & 9                     & ...                   & N                     \\ \cline{2-13} 
{\bf M}                     & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 12}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
40 41
\multicolumn{1}{l}{} &                       &                       &                       &                       &                       &                       & {\bf A}                       &                       &                       &                       &                       &                      
\end{tabular}
42

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
43 44
Ou seja, no exemplo acima, o símbolo A é, na verdade, um apelido para a célula M[6].
Um ponteiro é uma variável que será utilizada como índice do vetor memória, ou seja, um ponteiro é
45 46 47 48
uma variável que aponta para uma determinada posição de memória.

Por exemplo, suponha que tenha sido declarado um ponteiro de nome P.

49
\begin{tabular}{cllllllllllll}
50 51
   & 0                     & 1                     & 2                     & 3                     & 4                     & 5                     & 6                             & 7                     & 8                     & 9                            & ...                   & N                     \\ \cline{2-13} 
{\bf M}                     & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 12}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 6}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
52 53
\multicolumn{1}{l}{} &                       &                       &                       &                       &                       &                       & {\bf A}                       &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
54

55 56 57
A princípio, na ilustração acima, o ponteiro {\bf P} tem a mesma aparência que a variável {\bf A}, ou seja, é
alocada também uma região de memória para que seu valor possa ser armazenado ({\it V[9]}) e a essa região
denomina-se {\bf P}.
58

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
59
A diferença entre um ponteiro e uma variável numérica tradicional é que um ponteiro é um tipo de
Vytor Calixto's avatar
Vytor Calixto committed
60
dado que pode ser utilizado para {\it indexar} a memória, o que não é permitido fazer com as outras variáveis.
61

62 63
Ou seja, o ponteiro {\bf P} pode ser usado em uma forma que equivale a {\it M[{\bf P}]}, ou seja, o seu conteúdo
(que no exemplo é o valor {\bf 6}) pode ser utilizado para obter o conteúdo de uma determinada posição de
64 65
memória.

66
É importante ressaltar que a notação utilizada da memória como um vetor {\it M[ ]} é apenas para fins
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
67
de ilustração. Não existe nenhum nome especial para denominar um vetor que é a memória.
68

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
69
\section{Declarando ponteiros}
70 71 72 73 74 75 76 77

Se um ponteiro aponta para uma determinada região de memória, faz sentido determinar qual é o tipo
de dado armazenado na posição para a qual ele aponta.

Dessa forma, sempre que um ponteiro é declarado, deve ser especificado o tipo de dado para o qual
êle aponta. Como um ponteiro pode apontar para qualquer tipo de dado, faz sentido uma sintaxe que
visa simplificar a declaração.

78
Na linguagem C, para declarar um ponteiro basta acrescentar o símbolo '*' antes do que seria uma
79 80
declaração de tipo tradicional na linguagem C.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
81
\begin{lstlisting}
82
tipo *nome-do-ponteiro;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
83 84 85
\end{lstlisting}

Exemplos de declaração de ponteiros:
86

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
87
\begin{lstlisting}
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
88 89 90
char *ptr1; // ponteiro para um char
int *ptr2; // ponteiro para um int
double *ptr3; // ponteiro para um double
91

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
92 93
struct registro {
	int campo1, campo2;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
94
} *reg; // ponteiro para uma estrutura do tipo registro
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
95 96 97 98 99
\end{lstlisting}


Observe que um ponteiro também é considerado um tipo de dado, portanto não existe nenhuma
restrição que impeça de se declarar um ponteiro que aponta para outro ponteiro.
100 101 102

Por exemplo:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
103
\begin{lstlisting}
104 105
int *P;
int **Pp;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
106 107 108
\end{lstlisting}


109
Acima, foi declarado uma variável chamada Pp que aponta para uma região de memória cujo conteúdo
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
110
é do tipo int*. Essa situação é ilustrada abaixo:
111

112
\begin{tabular}{cllllllllllll}
113
   & 0                     & 1                     & 2                     & 3                       & 4                     & 5                     & 6                            & 7                     & 8                     & 9                            & ...                   & N                     \\ \cline{2-13} 
Vytor Calixto's avatar
Vytor Calixto committed
114
{\bf M}                     & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{32} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 9}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 3}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
115 116
\multicolumn{1}{l}{} &                       &                       &                       &                         &                       &                       & {\bf Pp}                     &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
117

118 119
Ou seja, {\it Pp} pode ser usado para indexar a memória {\it M} e obter o conteúdo da posição {\bf 9}, que por sua
vez também é um ponteiro e pode ser usado para indexar a memória {\it M} e obter o conteúdo da posição {\bf 3}.
120

121
Equivalentemente, se {\bf M} é um vetor, para obter o conteúdo da posição 3 a seguinte declaração seria
122 123
suficiente:

124
M[M[{\bf M[Pp]}]] $\leftarrow$ M[{\bf M[9]}] $\leftarrow$ M[3]
125

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
126
\section{Utilizando ponteiros}
127
\label{sec:utilizando_ponteiros}
Vytor Calixto's avatar
Vytor Calixto committed
128
Até agora foi discutido sobre ponteiros para indexar a memória, mas também foi observado que não existe
129
um vetor de memória {\it M} para que o ponteiro possa ser utilizado para indexar esse vetor.
130 131

Para indexar a memória utilizando o valor de uma variável que é ponteiro, basta preceder o nome da
132
variável com o símbolo `*'. Neste contexto, o operador `*' é denominado {\it derreferenciador}.
133

134 135
É necessário cuidado para não confundir o operador de {\bf derreferenciação} (que é unário) com o 
operador de {\bf multiplicação} (que é binário).
136 137

Por exemplo, dada a seguinte declaração:
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
138
\begin{lstlisting}
139
int *P, A;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
140 141
\end{lstlisting}

142
Para poder indexar a memória do valor de {\it P} e atribuir esse valor a variável A, é necessária a seguinte
143 144
linha de código:

145
A = *P; $\leftarrow$ equivalente a: {\bf A = M[P];}
146

147 148 149 150
É importante diferenciar o símbolo {\it *P} segundo o contexto em que ele se encontra. Toda vez que
aparece um tipo de dado, um `*' e logo após um símbolo que nomeia a variável (i.e., {\tt int *P}), isso não é
um acesso à posição de memória, é apenas uma declaração que denomina que {\it P} será um ponteiro para
uma posição de memória cujo conteúdo é do tipo {\it int}.
151 152 153

Suponha que a memória está no seguinte estado:

154
\begin{tabular}{cllllllllllll}
155 156
  & 0                     & 1                     & 2                     & 3                       & 4                     & 5                     & 6                            & 7                     & 8                     & 9                            & ...                   & N                     \\ \cline{2-13} 
{\bf M}                     & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{31} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 12}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 3}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
157 158
\multicolumn{1}{l}{} &                       &                       &                       &                         &                       &                       & {\bf A}                      &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
159

160
Ao executar {\tt A = *P}, a memória assumiria a seguinte configuração:
161

162
\begin{tabular}{cllllllllllll}
163 164
  & 0                     & 1                     & 2                     & 3                       & 4                     & 5                     & 6                            & 7                     & 8                     & 9                            & ...                   & N                     \\ \cline{2-13} 
{\bf M}                     & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{31} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf {\it 31}}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 3}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
165 166
\multicolumn{1}{l}{} &                       &                       &                       &                         &                       &                       & {\bf A}                      &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
167

168
Ou seja, o valor que está armazenado na posição 3 do vetor (31) é atribuído à variável {\it A}.
169

170 171
É importante observar que a atribuição só é considerada válida porque {\it P} foi declarado como ponteiro
para um {\it int}. Se {\it P} fosse declarado da seguinte forma
172

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
173 174 175 176 177 178
\begin{lstlisting}
struct { 
	int x; 
} *P;
\end{lstlisting}

179 180
A atribuição {\tt A = *P} {\bf não} seria válida e decorreria em erro na compilação, embora a aparência na
memória fosse a mesma, já que a estrutura tem apenas um campo que é do tipo {\it int}.
181

182
No entanto, se {\it P} apontasse para uma estrutura, como proposto, como os tamanhos de ambas as
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
183 184
variáveis são os mesmos, ainda parece fazer sentido a atribuição proposta. Com uma pequena 
modificação, proposta a seguir, a atribuição se torna possível.
185
{\tt 
186
A = *((int*)P)
187 188
}
Considerando que {\it P} aponta para uma estrutura, faz sentido que o programador deseje acessar os
189 190
membros dessa estrutura.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
191
Existem dois modos para acessar um campo de uma estrutura que é apontada por um ponteiro:
192

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
193
\begin{lstlisting}
194
(*P).nomecampo;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
195 196 197
P->nomecampo;
\end{lstlisting}

198 199 200 201

As declarações acima são equivalentes, ou seja, o resultado é o mesmo.
Tome como a exemplo a seguinte declaração:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
202 203 204 205 206 207
\begin{lstlisting}
struct {
	char codigo[2];
	int n;
	float cr;
} *P;
208

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
209 210
strcpy(P->codigo, "X");
P->n = 23;
211
(*P).cr = 13.6;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
212
\end{lstlisting}
213 214 215

No vetor de memória a declaração poderia assumir o seguinte aspecto:

Davisson Henrique Paulino's avatar
Davisson Henrique Paulino committed
216 217 218 219 220

\begin{tabular}{cllllllllllll}
  & 0                     & 1                     & 2                     & 3                     & 4                     & 5                     & 6                             & 7                     & 8                     & 9                     & ...                   & N                     \\ \cline{2-13} 
{\bf M}                     & \multicolumn{1}{|l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 12}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
\multicolumn{1}{l}{} &                       &                       &                       &                       &                       &                       & {\bf A}                       &                       &                       &                       &                       &                      
221
\end{tabular}
222

223
Por motivos de simplicidade, o exemplo acima assume que as variáveis do tipo {\it int} e {\it float} ocupam a
224 225
mesma quantidade de espaço em memória, o que não acontece na realidade.

226
O processo de indexar a memória com o valor do ponteiro é também conhecido como {\it derreferenciamento} do ponteiro.
227

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
228 229
Até este momento, a utilização de ponteiros envolveu apenas indexar uma determinada região de
memória, sem considerar a validade desta ação.
230

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
231
Na realidade, um ponteiro não pode ser efetivamente usado se não estiver apontando para um região
232 233
válida da memória, ou seja, uma região que tenha sido alocada especificamente para o o seu programa.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
234
No momento da declaração de um ponteiro, o seu conteúdo, que é a posição para onde está apontando,
235
é {\it lixo}, como acontece na declaração de quaisquer outras variáveis. Portanto, é necessário especificar para
236 237
onde deseja-se que o ponteiro aponte.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
238
Existem dois modos de fazer um ponteiro apontar para uma posição válida:
239

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
240 241 242
\begin{itemize}
	\item fazer o ponteiro apontar para uma variável existente no programa;
	\item alocar um espaço dinamicamente para o ponteiro.
243
{\it Alocação dinâmica} é assunto do próximo capítulo.
244 245
Para fazer um ponteiro apontar para uma variável existente no programa, deve haver um meio para
obter o endereço da variável em questão.
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
246
\end{itemize}
247

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
248
O operador \& , quando utilizado precedendo uma variável, obtêm o endereço de memória da variável
249 250
em questão. Nesse contexto, o operador \& é chamado de {\it referenciador}. É necessário cuidado para não confundir o operador de {\it referência} (que é unário) com o operador 
de {\it AND} (que é binário).
251

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
252
Dada a seguinte declaração de uma variável qualquer e a de um ponteiro para este tipo de variável:
253

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
254
\begin{lstlisting}
255 256
tipo nome var;
tipo* P;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
257 258
\end{lstlisting}

259
Para fazer como que o ponteiro {\it P} aponte para a variável {\it nome var}, a seguinte declaração é necessária:
260

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
261
\begin{lstlisting}
262
P = &nome var;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
263
\end{lstlisting}
264

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
265
Por exemplo, suponha as seguintes declarações:
266

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
267 268 269 270 271 272 273
\begin{lstlisting}
struct {
	char codigo[2];
	int n;
	float cr;
} registro, *P;
\end{lstlisting}
274 275 276

A memória assumiria o seguinte aspecto para a declaração acima:

277
\iffalse
278
\begin{tabular}{lllllllllllllllll}
279 280
\multicolumn{1}{c} & 0                     & 1                     & 2                     &                       & 3                      & 4                       & 5                       & 6                        &                       & 7                     & 8                     &                       & 9                            &                       & ...                   & N                     \\ \cline{2-17} 
\multicolumn{1}{c}{{\bf M}}                   & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{X} & \multicolumn{1}{l|}{\0} & \multicolumn{1}{l|}{23} & \multicolumn{1}{l|}{3.6} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 3}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-17} 
281
                                      &                       &                       & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{2}{r|}{.codigo}                     & \multicolumn{1}{r}{.n}  & \multicolumn{1}{r|}{.cr} & \multicolumn{1}{l|}{} &                       & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf P}} & \multicolumn{1}{l|}{} &                       &                       \\ \cline{6-9} \cline{13-13} \cline{15-15}
282 283
                                       &                       &                       & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{4}{c|}{registro}                                                                         & \multicolumn{1}{l|}{} &                       &                       &                       &                              &                       &                       &                       \\ \cline{5-10}
\end{tabular}
284
\fi
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
285
Após a seguinte linha de código:
286

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
287
\begin{lstlisting}
288
P = &registro;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
289 290 291
\end{lstlisting}


292 293
A memória assumiria o seguinte aspecto:

294
\begin{tabular}{lllllllllllllllll}
295 296
\multicolumn{1}{c}{} & 0                     & 1                     & 2                     &                       & 3                      & 4                       & 5                       & 6                        &                       & 7                     & 8                     &                       & 9                            &                       & ...                   & N                     \\ \cline{2-17} 
\iffalse
297
\multicolumn{1}{c}{{\bf M}}                   & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{X} & \multicolumn{1}{l|}{\0} & \multicolumn{1}{l|}{23} & \multicolumn{1}{l|}{3.6} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 3}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-17} 
298
\fi                                       &                       &                       & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{2}{r|}{.codigo}                     & \multicolumn{1}{r}{.n}  & \multicolumn{1}{r|}{.cr} & \multicolumn{1}{l|}{} &                       & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf P}} & \multicolumn{1}{l|}{} &                       &                       \\ \cline{6-9} \cline{13-13} \cline{15-15}
299 300
                                       &                       &                       & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{4}{c|}{registro}                                                                         & \multicolumn{1}{l|}{} &                       &                       &                       &                              &                       &                       &                       \\ \cline{5-10}
\end{tabular}
301

302 303
Observe que o valor do ponteiro {\it P} agora é {\bf 3}, que é a posição de memória onde inicia a estrutura
{\it registro}.
304 305 306

Observe o programa abaixo:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
307
\lstinputlisting{exemplos/ponteiro.c}
308 309 310


O programa acima imprime na tela o alfabeto em maiúsculas, nada muito misterioso. Mas considere
311 312
{\it como} o programa cumpre esta simples tarefa. O programa acima realiza uma impressão que se refere
apenas ao ponteiro {\it pc}.
313

314 315
A chave deste enigma está no ponteiro {\it pc}. Inicialmente, foi declarado um ponteiro para uma variável
{\it char}. A seguir, é atribuída a posição de memória referente à variável {\it c} para o ponteiro {\it pc}.
316

317
Dessa forma, é possível acessar indiretamente o conteúdo da variável {\it c}, derreferenciando o ponteiro.
318

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
319 320
\subsection{Exercício}

321 322
Dadas as seguintes declarações:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
323 324
\begin{lstlisting}
struct computador {
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
325 326 327 328
	char processador[10]; // nome do processador 
	int placa video; // codigo da placa de video 
	int modem:1; // possui modem? (s/n) 
	int modem code:7; // codigo do modem (se aplicavel) 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
329 330 331 332
} comp1;

typedef struct computador* comp_ponteiro;
\end{lstlisting}
333 334


335 336
Desenhe um diagrama da memória com a estrutura \textit{comp1} representada. Escreva o código necessário
para que o ponteiro \textit{comp\_ponteiro} aponte para esta estrutura, e complete o diagrama com essa nova
337 338
situação.

339 340
Declare um novo ponteiro {\it pcomp} que aponte para {\it comp\_ponteiro} e escreva como deveria ser o código
para acessar um dos campos da estrutura apontada por {\it com\_ponteiro} através do {\it pcomp}.
341

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
342 343 344 345

\section{Passagem de parêmetros por referência}

Muitas vezes, existe a necessidade de que funções alterem o valor de um ou mais parâmetros. Para
346 347
que isso seja possível é utilizada uma técnica conhecida como {\it passagem de parâmetro por referência},
êm contraposição ao método habitual que é a {\it passagem de parâmetro por valor}, a qual não reflete as
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
348
alterações nas variáveis utilizadas na chamada da função.
349 350

Na linguagem C na verdade não existe nenhum mecanismo específico só para manipular a passagem de
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
351
parâmetro por referência. Para que seja possível alterar o valor de uma variável passada como parâmetro
352 353
é necessário se utilizar de ponteiros.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
354 355 356
Em uma passagem por referência, é necessário que a variável de parâmetro seja, como o próprio nome
da passagem sugere, uma referência para variável passada como parâmetro. Foi visto que ponteiros são
capazes de apontar para variáveis e, portanto, podem servir como referência para uma variável.
357 358 359 360

Para entender como o processor funciona, analise novamente o diagrama do vetor que representa a
memória.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
361
\begin{lstlisting}
362 363
int A, *P;
A = 31;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
364 365
\end{lstlisting}

366
\begin{tabular}{cllllllllllll}
367 368
   & 0                     & 1                     & 2                     & 3                     & 4                     & 5                     & 6                             & 7                     & 8                     & 9                            & ...                   & N                     \\ \cline{2-13} 
{\bf M}                     & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 31}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf ??}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
369 370
\multicolumn{1}{l}{} &                       &                       &                       &                       &                       &                       & {\bf A}                       &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
371

372 373
O diagrama acima apresenta a variável {\it A} e um ponteiro {\it P}. O objetivo é utilizar o ponteiro {\it P} para
alterar o valor de {\it A}, ou seja, transformar {\it P} em uma referência para {\it A}.
374

375 376
Para tanto, basta examinar a seção {\bf ??}.
A seguinte linha de código faz com que {\it P} aponte para {\it A}:
377

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
378
\begin{lstlisting}
379
P = &A;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
380
\end{lstlisting}
381

382
Desse modo, é possível alterar o valor de {\it A} através de {\it P}.
383

384
*P = 5; $\leftarrow$ {\it Equivalente a M[P]=5.}
385

386
Ao invés de declarar {\it P} como uma variável ordinária, é possível declarar uma função com o seguinte
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
387
protótipo:
388

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
389 390 391
\begin{lstlisting}
tipo_retorno func(int *P);
\end{lstlisting}
392

393
\begin{tabular}{cllllllllllll}
394 395
   & 0                     & 1                     & 2                     & 3                     & 4                     & 5                     & 6                             & 7                     & 8                     & 9                            & ...                   & N                     \\ \cline{2-13} 
{\bf M}                     & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 31}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 6}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
396 397
\multicolumn{1}{l}{} &                       &                       &                       &                       &                       &                       & {\bf A}                       &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
398

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
399 400
Dessa maneira, o que temos na verdade é uma função tal que um de seus parâmetros é um ponteiro.
Como já foi visto, para fazer com que este ponteiro aponte para uma variável qualquer, é necessário
401 402
atribuir a ele o endereço da variável. Portanto, para que {\it P} seja realmente uma referência para a variável
que será passada como parâmetro, a chamada da função {\it func} deverá ser da seguinte forma:
403

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
404
\begin{lstlisting}
405
func(&A);
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
406 407 408 409
\end{lstlisting}


Ou seja, o que está acontecendo na realidade não é exatamente uma passagem por referência no
410
sentido habitual do termo, mas a passagem do endereço de uma variável para que um ponteiro possa
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
411
apontá-la e, por sua vez, através desse ponteiro a função será capaz de alterar o valor apontado pelo
412 413
ponteiro.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
414
\subsection{Exercício}
415

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
416
Escreva como seria o protótipo de uma função que receberá como um de seus parâmetros um ponteiro
417
{\it P}, sendo que a função deverá ser capaz de alterar o ponteiro.
418

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
419
Escreva também qual seria a linha de código para alterar o valor do ponteiro, para que ele aponte
420
para uma variável local da função {\it A}. Que problemas esse tipo atribuição poderia causar?
421

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
422
\section{Aritmética de ponteiros}
423

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
424
É interessante observar que, embora ponteiros sejam considerados um tipo especial de dados, eles ainda
425 426
são números e, como tal, faz sentido realizar algumas operações matemáticas sobre eles.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
427
A aritmética de ponteiros é restrita apenas a soma, subtração e comparações.
428 429 430 431 432
O que significa adicionar um número a um ponteiro? Para compreender qual o efeito de uma soma
ou subtração sobre um ponteiro, é interessante recorrer novamente ao diagrama da memória.

Suponha as seguintes declarações:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
433
\begin{lstlisting}
434 435
int vet[2] = f9, 31g;
int *P;
436
p = &vet[0]; // faz P apontar para a primeira celula de ver
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
437 438
\end{lstlisting}

439

440
\begin{tabular}{cllllllllllll}
441 442
  & 0                     & 1                     & 2                                    & 3                                    & 4                     & 5                     & 6                     & 7                     & 8                     & 9                            & ...                   & N                     \\ \cline{2-13} 
{\bf M}                     & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 9}}         & \multicolumn{1}{l|}{{\bf 31}}        & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 2}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
443 444
\multicolumn{1}{l}{} &                       &                       & \multicolumn{1}{c}{{\bf vet{[}0{]}}} & \multicolumn{1}{c}{{\bf vet{[}1{]}}} &                       &                       &                       &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
445

446 447
Nesse caso, o conteúdo de {\it *P} é {\bf 9}. Se for realizada uma adição sobre {\it P}:
\begin{lstlisting}
448
P++;
449
\end{lstlisting}
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
450

451 452
Teremos:

453
\begin{tabular}{cllllllllllll}
454 455
 & 0                     & 1                     & 2                                    & 3                                    & 4                     & 5                     & 6                     & 7                     & 8                     & 9                            & ...                   & N                     \\ \cline{2-13} 
{\bf M}                     & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 9}}         & \multicolumn{1}{l|}{{\bf 31}}        & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 3}} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
456 457
\multicolumn{1}{l}{} &                       &                       & \multicolumn{1}{c}{{\bf vet{[}0{]}}} & \multicolumn{1}{c}{{\bf vet{[}1{]}}} &                       &                       &                       &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
458

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
459
Agora, o conteúdo de *P é 31. Ou seja, realizar somas ou subtrações sobre ponteiros é nada mais do
460 461 462 463
que fazer com que o ponteiro aponte para uma nova posição da memória.

Observe o seguinte exemplo:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
464
\lstinputlisting{exemplos/ponteiro2.c}
465 466 467

A saída desse programa será:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
468
\begin{verbatim}
469 470 471 472
*p = A
*(p+1) = r
*(p+5) = é
*(p+7) = i
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
473 474 475
\end{verbatim}

\subsection{Exercício}
476 477 478 479

Observe pelos exemplos, que a aritmética de ponteiros cria uma forte relação entre ponteiros e vetores.
Somar valores a um ponteiro, faz o ponteiro apontar para uma próxima célula de um vetor.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
480
Escreva um programa que obtenha como entrada do teclado uma palavra (que será armazenada em
481 482
uma string) e imprima a string de trás para a frente.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
483
\section{Ponteiros e matrizes}
484
\label{sec:ponteiro_matrizes}
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
485 486
Mais do que apenas uma relação, para a linguagem C matrizes são, na realidade, ponteiros para a primeira
posição da matriz na memória.
487

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
488
É esta a razão pela qual matrizes sempre são passadas por referência para funções.
489

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
490 491
A única diferença entre uma matriz comum e um ponteiro, além da declaração, é que uma matriz é
um tipo de dado cujo espaço é alocado no momento em que ela é declarada e seu ponteiro não pode ser
492 493 494 495 496
alterado, assim como para qualquer variável não se pode alterar o seu próprio endereço, mas apenas seu
conteúdo.

Suponha a seguinte declaração:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
497 498 499 500 501
\begin{lstlisting}
char str[5] = "sapo";
\end{lstlisting}

A aparência dessa declaração na memória é a seguinte:
502

503 504
\begin{tabular}{lllllllllllll}
\multicolumn{1}{c}{}   & 0                     & 1                     & 2                              & 3                              & 4                              & 5                              & 6                              & 7                     & 8                     & 9                           & ...                   & N                     \\ \cline{2-13} 
505
\iffalse
506
\multicolumn{1}{l|}{M} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf s}}   & \multicolumn{1}{l|}{{\bf a}}   & \multicolumn{1}{l|}{{\bf p}}   & \multicolumn{1}{l|}{{\bf o}}   & \multicolumn{1}{l|}{{\bf \0}}  & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf }} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
507 508
\fi
&                       &                       & \multicolumn{1}{c}{str{[}0{]}} & \multicolumn{1}{c}{str{[}1{]}} & \multicolumn{1}{c}{str{[}2{]}} & \multicolumn{1}{c}{str{[}3{]}} & \multicolumn{1}{c}{str{[}4{]}} &                       &                       & {\bf }                      &                       &                       \\ \cline{4-8}
509 510
                       &                       &                       & \multicolumn{5}{c}{{\bf str}}                                                                                                                                      &                       &                       &                             &                       &                      
\end{tabular}
511

512
Note que a variável {\it str} sem indexação é na realidade um ponteiro para a posição 2 da memória.
513 514
Se a seguinte declaração é realizada:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
515 516
\begin{lstlisting}
char str[5] = "sapo";
517
char *pon = str;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
518 519
\end{lstlisting}

520 521

O efeito será:
522 523
\begin{tabular}{lllllllllllll}
\multicolumn{1}{c}{}   & 0                     & 1                     & 2                              & 3                              & 4                              & 5                              & 6                              & 7                     & 8                            & 9                           & ...                   & N                     \\ \cline{2-13} 
524 525
\iffalse\multicolumn{1}{l|}{M} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf s}}   & \multicolumn{1}{l|}{{\bf a}}   & \multicolumn{1}{l|}{{\bf p}}   & \multicolumn{1}{l|}{{\bf o}}   & \multicolumn{1}{l|}{{\bf \0}}  & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 2}} & \multicolumn{1}{l|}{{\bf }} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
\fi                       &                       &                       & \multicolumn{1}{c}{str{[}0{]}} & \multicolumn{1}{c}{str{[}1{]}} & \multicolumn{1}{c}{str{[}2{]}} & \multicolumn{1}{c}{str{[}3{]}} & \multicolumn{1}{c}{str{[}4{]}} &                       & {\bf pon}                    & {\bf }                      &                       &                       \\ \cline{4-8}
526 527
                       &                       &                       & \multicolumn{5}{c}{{\bf str}}                                                                                                                                      &                       &                              &                             &                       &                      
\end{tabular}
528

529 530
A partir do momento que pon está apontando para o vetor {\it str}, este ponteiro poderá ser utilizado
como se fosse o próprio vetor {\it str}.
531 532

Por exemplo:
533
\begin{alltt}
534
{\tt pon[3]} acessa o {\bf 3}º elemento de {\it str} (letra o).
535
\end{alltt}
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
536
Na linguagem C todo ponteiro pode ser indexado dessa maneira, mesmo que a posição indexada não
537
''exista" (por exemplo, {\it pon[5]} ). Naturalmente, uma tentativa de acessar posições não alocadas, quase
538 539 540 541
sempre decorrem em erros (dependendo do sistema operacional, o erro não é muito aparente).

Na verdade, ao passar uma matriz para uma função, todo o processo acima ocorre naturalmente.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
542 543
É interessante observar que para funções receberem matriz bidimensionais é necessário que seu
parâmetro seja um ponteiro para ponteiro.
544 545 546

Por exemplo:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
547 548 549
\begin{lstlisting}
tipo_retorno func(int **matriz);
\end{lstlisting}
550

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
551 552 553 554

\subsection{Exercício}

Escreva uma função que receba duas matrizes 3x3, compute a soma dessas matrizes e imprima a resposta
555 556
na tela.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
557
\section{Ponteiros para funções}
558

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
559 560 561
Ponteiros para funções são tipos especiais de ponteiros. Em vez de armazenarem o endereço de uma área
de dados, armazenam o endereço de uma função, ou seja, o endereço de memória para o qual o controle
é transferido quando a função é chamada. O quadro a seguir mostra o modelo geral de declaração de
562 563
ponteiros para funções e alguns exemplos:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
564 565
\begin{lstlisting}
tipo_retorno (*nome_ponteiro) (!parâmetros?);
566 567 568 569
void (*v fptr) ();
int (*i fptr) ();
double (*div fptr) (int, int);
struct registro* (*reg fptr) (char*, char*, int, char*);
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
570 571
\end{lstlisting}

572

573 574
Nos exemplos acima, {\it v\_ptr} é um ponteiro para qualquer função que não recebe argumentos nem
retorna nada. {\it reg\_fptr} é um ponteiro para uma função que receba como parâmetro 3 strings e um inteiro,
575 576
ê retorne um ponteiro para uma struct registro.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
577
Exemplo de utilização:
578

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
579
\begin{lstlisting}
580
double f (double x)
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
581
{
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
582
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
583
}
584 585

double g (double x)
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
586
{
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
587
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
588
}
589 590

main ()
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
591
{
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
592
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
593 594 595
	double (*fp) (double);
	double x, y;

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
596
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
597 598
	if (x != 0) fp = f;
	else fp = g;
599

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
600
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
601
	y = (*fp) (x);
602

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
603
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
604 605
}
\end{lstlisting}
606 607


Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
608
\section{Problemas com ponteiros}
609 610 611 612

Problemas com ponteiros são relativamente comuns e geralmente é muito de difícil de encontrar os erros
relativos ao ponteiro.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
613
O erro mais comum é a tentativa de usar um ponteiro que não esteja apontado para um posição válida
614 615 616
de memória. Dependendo do sistema operacional, o problema não é imediatamente acusado, mas tende
a ter dimensões catastróficas.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
617
Imagine, por exemplo, que a posição para a qual o ponteiro aponta é uma região da memória utilizada
618 619 620
pelo sistema operacional. Se o sistema operacional permitir a escrita nesta posição, o sistema pode até
mesmo travar.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
621
Exemplo:
622

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
623 624
\begin{lstlisting}
int main(void) {
625

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
626 627
	int x, *p;
	x = 10;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
628
	(*p) = x; // Em que endereço estamos armazenando x? 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
629 630 631 632
	
	return 0;
}
\end{lstlisting}
633

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
634
Atribui o valor 10 a alguma localização desconhecida da memória.
Vytor Calixto's avatar
Vytor Calixto committed
635
\end{document}