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
\begin{tabular}{lllllllllllllllll}
278 279
\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|}{\textbackslash0} & \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} 
280
                                      &                       &                       & \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}
281 282
                                       &                       &                       & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{4}{c|}{registro}                                                                         & \multicolumn{1}{l|}{} &                       &                       &                       &                              &                       &                       &                       \\ \cline{5-10}
\end{tabular}
283

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
284
Após a seguinte linha de código:
285

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


291 292
A memória assumiria o seguinte aspecto:

293
\begin{tabular}{lllllllllllllllll}
294
\multicolumn{1}{c}{} & 0                     & 1                     & 2                     &                       & 3                      & 4                       & 5                       & 6                        &                       & 7                     & 8                     &                       & 9                            &                       & ...                   & N                     \\ \cline{2-17} 
295 296
\multicolumn{1}{c}{{\bf M}}                   & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{X} & \multicolumn{1}{l|}{\textbackslash0} & \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} 
                                       &                       &                       & \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}
297 298
                                       &                       &                       & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{4}{c|}{registro}                                                                         & \multicolumn{1}{l|}{} &                       &                       &                       &                              &                       &                       &                       \\ \cline{5-10}
\end{tabular}
299

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

Observe o programa abaixo:

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


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

312 313
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}.
314

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

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
317 318
\subsection{Exercício}

319 320
Dadas as seguintes declarações:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
321 322
\begin{lstlisting}
struct computador {
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
323 324 325 326
	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
327 328 329 330
} comp1;

typedef struct computador* comp_ponteiro;
\end{lstlisting}
331 332


333 334
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
335 336
situação.

337 338
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}.
339

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
340 341 342 343

\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
344 345
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
346
alterações nas variáveis utilizadas na chamada da função.
347 348

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
349
parâmetro por referência. Para que seja possível alterar o valor de uma variável passada como parâmetro
350 351
é necessário se utilizar de ponteiros.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
352 353 354
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.
355 356 357 358

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

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

364
\begin{tabular}{cllllllllllll}
365 366
   & 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} 
367 368
\multicolumn{1}{l}{} &                       &                       &                       &                       &                       &                       & {\bf A}                       &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
369

370 371
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}.
372

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

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

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

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

384
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
385
protótipo:
386

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

391
\begin{tabular}{cllllllllllll}
392 393
   & 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} 
394 395
\multicolumn{1}{l}{} &                       &                       &                       &                       &                       &                       & {\bf A}                       &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
396

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
397 398
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
399 400
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:
401

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


Ou seja, o que está acontecendo na realidade não é exatamente uma passagem por referência no
408
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
409
apontá-la e, por sua vez, através desse ponteiro a função será capaz de alterar o valor apontado pelo
410 411
ponteiro.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
412
\subsection{Exercício}
413

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

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

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
420
\section{Aritmética de ponteiros}
421

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

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
425
A aritmética de ponteiros é restrita apenas a soma, subtração e comparações.
426 427 428 429 430
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
431
\begin{lstlisting}
432 433
int vet[2] = f9, 31g;
int *P;
434
p = &vet[0]; // faz P apontar para a primeira celula de ver
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
435 436
\end{lstlisting}

437

438
\begin{tabular}{cllllllllllll}
439 440
  & 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} 
441 442
\multicolumn{1}{l}{} &                       &                       & \multicolumn{1}{c}{{\bf vet{[}0{]}}} & \multicolumn{1}{c}{{\bf vet{[}1{]}}} &                       &                       &                       &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
443

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

449 450
Teremos:

451
\begin{tabular}{cllllllllllll}
452 453
 & 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} 
454 455
\multicolumn{1}{l}{} &                       &                       & \multicolumn{1}{c}{{\bf vet{[}0{]}}} & \multicolumn{1}{c}{{\bf vet{[}1{]}}} &                       &                       &                       &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
456

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
457
Agora, o conteúdo de *P é 31. Ou seja, realizar somas ou subtrações sobre ponteiros é nada mais do
458 459 460 461
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
462
\lstinputlisting{exemplos/ponteiro2.c}
463 464 465

A saída desse programa será:

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

\subsection{Exercício}
474 475 476 477

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
478
Escreva um programa que obtenha como entrada do teclado uma palavra (que será armazenada em
479 480
uma string) e imprima a string de trás para a frente.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
481
\section{Ponteiros e matrizes}
482
\label{sec:ponteiro_matrizes}
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
483 484
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.
485

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

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
488 489
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
490 491 492 493 494
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
495 496 497 498 499
\begin{lstlisting}
char str[5] = "sapo";
\end{lstlisting}

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

501 502
\begin{tabular}{lllllllllllll}
\multicolumn{1}{c}{}   & 0                     & 1                     & 2                              & 3                              & 4                              & 5                              & 6                              & 7                     & 8                     & 9                           & ...                   & N                     \\ \cline{2-13} 
503 504
\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 \textbackslash0}}  & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf }} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 

505
&                       &                       & \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}
506 507
                       &                       &                       & \multicolumn{5}{c}{{\bf str}}                                                                                                                                      &                       &                       &                             &                       &                      
\end{tabular}
508

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

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

517 518

O efeito será:
519 520
\begin{tabular}{lllllllllllll}
\multicolumn{1}{c}{}   & 0                     & 1                     & 2                              & 3                              & 4                              & 5                              & 6                              & 7                     & 8                            & 9                           & ...                   & N                     \\ \cline{2-13} 
521 522
\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 \textbackslash0}}  & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{{\bf 2}} & \multicolumn{1}{l|}{{\bf }} & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} \\ \cline{2-13} 
                       &                       &                       & \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}
523 524
                       &                       &                       & \multicolumn{5}{c}{{\bf str}}                                                                                                                                      &                       &                              &                             &                       &                      
\end{tabular}
525

526 527
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}.
528 529

Por exemplo:
530
\begin{alltt}
531
{\tt pon[3]} acessa o {\bf 3}º elemento de {\it str} (letra o).
532
\end{alltt}
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
533
Na linguagem C todo ponteiro pode ser indexado dessa maneira, mesmo que a posição indexada não
534
''exista" (por exemplo, {\it pon[5]} ). Naturalmente, uma tentativa de acessar posições não alocadas, quase
535 536 537 538
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
539 540
É interessante observar que para funções receberem matriz bidimensionais é necessário que seu
parâmetro seja um ponteiro para ponteiro.
541 542 543

Por exemplo:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
544 545 546
\begin{lstlisting}
tipo_retorno func(int **matriz);
\end{lstlisting}
547

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
548 549 550 551

\subsection{Exercício}

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

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

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
556 557 558
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
559 560
ponteiros para funções e alguns exemplos:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
561 562
\begin{lstlisting}
tipo_retorno (*nome_ponteiro) (!parâmetros?);
563 564 565 566
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
567 568
\end{lstlisting}

569

570 571
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,
572 573
ê retorne um ponteiro para uma struct registro.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
574
Exemplo de utilização:
575

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
576
\begin{lstlisting}
577
double f (double x)
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
578
{
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
579
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
580
}
581 582

double g (double x)
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
583
{
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
584
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
585
}
586 587

main ()
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
588
{
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
589
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
590 591 592
	double (*fp) (double);
	double x, y;

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
593
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
594 595
	if (x != 0) fp = f;
	else fp = g;
596

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
597
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
598
	y = (*fp) (x);
599

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
600
	// ... 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
601 602
}
\end{lstlisting}
603 604


Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
605
\section{Problemas com ponteiros}
606 607 608 609

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
610
O erro mais comum é a tentativa de usar um ponteiro que não esteja apontado para um posição válida
611 612 613
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
614
Imagine, por exemplo, que a posição para a qual o ponteiro aponta é uma região da memória utilizada
615 616 617
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
618
Exemplo:
619

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
620 621
\begin{lstlisting}
int main(void) {
622

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

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