ponteiros.tex 37.1 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

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}
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}
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;
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}
Vytor Calixto's avatar
Vytor Calixto committed
127
Até agora foi discutido sobre ponteiros para indexar a memória, mas também foi observado que não existe
128
um vetor de memória {\it M} para que o ponteiro possa ser utilizado para indexar esse vetor.
129 130

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

133 134
É 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).
135 136

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

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

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

146 147 148 149
É 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}.
150 151 152

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

153
\begin{tabular}{cllllllllllll}
154 155
  & 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} 
156 157
\multicolumn{1}{l}{} &                       &                       &                       &                         &                       &                       & {\bf A}                      &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
158

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

161
\begin{tabular}{cllllllllllll}
162 163
  & 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} 
164 165
\multicolumn{1}{l}{} &                       &                       &                       &                         &                       &                       & {\bf A}                      &                       &                       & {\bf P}                      &                       &                      
\end{tabular}
166

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

169 170
É 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
171

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

178 179
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}.
180

181
No entanto, se {\it P} apontasse para uma estrutura, como proposto, como os tamanhos de ambas as
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
182 183
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.
184
{\tt 
185
A = *((int*)P)
186 187
}
Considerando que {\it P} aponta para uma estrutura, faz sentido que o programador deseje acessar os
188 189
membros dessa estrutura.

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

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

197 198 199 200

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
201 202 203 204 205 206
\begin{lstlisting}
struct {
	char codigo[2];
	int n;
	float cr;
} *P;
207

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

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

215 216 217 218 219

\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}                       &                       &                       &                       &                       &                      
220
\end{tabular}
221

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

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

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
227 228
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.
229

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
230
Na realidade, um ponteiro não pode ser efetivamente usado se não estiver apontando para um região
231 232
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
233
No momento da declaração de um ponteiro, o seu conteúdo, que é a posição para onde está apontando,
234
é {\it lixo}, como acontece na declaração de quaisquer outras variáveis. Portanto, é necessário especificar para
235 236
onde deseja-se que o ponteiro aponte.

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

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
239 240 241
\begin{itemize}
	\item fazer o ponteiro apontar para uma variável existente no programa;
	\item alocar um espaço dinamicamente para o ponteiro.
242
{\it Alocação dinâmica} é assunto do próximo capítulo.
243 244
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
245
\end{itemize}
246

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
247
O operador \& , quando utilizado precedendo uma variável, obtêm o endereço de memória da variável
248 249
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).
250

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

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

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

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

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

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

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

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

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

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


290 291
A memória assumiria o seguinte aspecto:

292
\begin{tabular}{lllllllllllllllll}
293 294
\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} 
295 296 297
                                       &                       &                       & \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}
                                       &                       &                       & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{} & \multicolumn{4}{c|}{registro}                                                                         & \multicolumn{1}{l|}{} &                       &                       &                       &                              &                       &                       &                       \\ \cline{5-10}
\end{tabular}
298

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

Observe o programa abaixo:

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


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

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

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

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

318 319
Dadas as seguintes declarações:

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

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


332 333
Desenhe um diagrama da memória com a estrutura {\it comp_1} representada. Escreva o código necessário
para que o ponteiro {\it comp_ponteiro} aponte para esta estrutura, e complete o diagrama com essa nova
334 335
situação.

336 337
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 comp_ponteiro} através do {\it pcomp}.
338

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

436

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

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

448 449
Teremos:

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

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

A saída desse programa será:

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

\subsection{Exercício}
473 474 475 476

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

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
480
\section{Ponteiros e matrizes}
481

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
482 483
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.
484

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

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

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

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

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

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

515 516

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

524 525
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}.
526 527

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

Por exemplo:

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

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
546 547 548 549

\subsection{Exercício}

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

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

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

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

567

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

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
572
Exemplo de utilização:
573

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

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

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

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

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

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


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

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

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

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

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