A maior rede de estudos do Brasil

Grátis
275 pág.
Apostila C

Pré-visualização | Página 30 de 45

tipo int (count) e um
ponteiro para o mesmo tipo (p). Na linha 9, o ponteiro p e´ inicializado
com o enderec¸o da varia´vel count. Note que usamos o operador de
enderec¸amento (&) para a inicializac¸a˜o do ponteiro. Isso significa que
o ponteiro p passa a conter o enderec¸o de count, na˜o o seu valor. Para
melhor entender esse conceito, veja a figura abaixo:
190
Tendo um ponteiro armazenado um enderec¸o de memo´ria, como saber o
valor guardado dentro dessa posic¸a˜o de memo´ria? Simples, para acessar
o conteu´do da posic¸a˜o de memo´ria para a qual o ponteiro aponta, usa-se
o operador asterisco (*) na frente do nome do ponteiro.
Para acessar o valor guardado dentro de uma posic¸a˜o na
memo´ria apontada por um ponteiro, basta usar o operador
asterisco (*).
1 #include <s t d i o . h>
2 #include <s t d l i b . h>
3 i n t main ( ) {
4 / / Declara uma v a r i a´ v e l i n t contendo o va lo r 10
5 i n t count = 10;
6 / / Declara um pon te i ro para i n t
7 i n t ∗p ;
8 / / A t r i b u i ao pon te i ro o enderec¸o da v a r i a´ v e l
i n t
9 p = &count ;
10 p r i n t f ( ‘ ‘ Conteudo apontado por p : %d \n ’ ’ ,∗p ) ;
11 / / A t r i b u i um novo va lo r a` posi c¸ a˜o de memo´ria
apontada por p
12 ∗p = 12;
13 p r i n t f ( ‘ ‘ Conteudo apontado por p : %d \n ’ ’ ,∗p ) ;
14 p r i n t f ( ‘ ‘ Conteudo de count : %d \n ’ ’ , count ) ;
15
16 system ( ‘ ‘ pause ’ ’ ) ;
17 return 0;
18 }
Saı´da Conteudo apontado por p: 10
Conteudo apontado por p: 12
Conteudo de count: 12
Note, no exemplo acima, que utilizamos o operador asterisco (*) sempre
que queremos acessar o valor contido na posic¸a˜o de memo´ria apontada
por p. Note tambe´m que, se alterarmos o valor contido nessa posic¸a˜o de
memo´ria (linha 12), alteramos o valor da varia´vel count.
191
Ao se trabalhar com ponteiros, duas tarefas ba´sicas sera˜o sempre execu-
tadas:
• acessar o enderec¸o de memo´ria de uma varia´vel;
• acessar o conteu´do de um enderec¸o de memo´ria;
Para realizar essas tarefas, iremos sempre utilizar apenas dois operadores:
o operador “*” e o operador “&”.
Operador “*” versus operador “&”
“*” Declara um ponteiro: int *x;
Conteu´do para onde o ponteiro aponta: int y = *x;
“&”
Enderec¸o onde uma varia´vel esta´ guardada na memo´ria:
&y
Devemos estar sempre atento a operac¸a˜o de atribuic¸a˜o quando estamos
trabalhando com ponteiros. Na˜o so´ com relac¸a˜o ao uso corretos dos ope-
radores, mas tambe´m ao que estamos atribuindo ao ponteiro.
De modo geral, um ponteiro so´ pode receber o enderec¸o
de memo´ria de uma varia´vel do mesmo tipo do ponteiro.
Isso ocorre por que diferentes tipos de varia´veis ocupam um espac¸o de
memo´ria de tamanhos diferentes. Na verdade, no´s podemos, por exem-
plo, atribuir a um ponteiro de inteiro (int *) o enderec¸o de uma varia´vel
do tipo float. O compilador na˜o ira´ acusar nenhum erro. No entanto, o
compilador assume que qualquer enderec¸o que esse ponteiro armazene
obrigatoriamente apontara´ para uma varia´vel do tipo int. Consequente-
mente, qualquer tentativa de uso desse ponteiro causa um comportamento
indefinido no programa. Veja o exemplo abaixo:
192
Exemplo: atribuic¸a˜o de ponteiros
1 #include <s t d i o . h>
2 #include <s t d l i b . h>
3 i n t main ( ) {
4 i n t ∗p , ∗p1 , x = 10;
5 f l o a t y = 20 .0 ;
6 p = &x ;
7 p r i n t f ( ‘ ‘ Conteudo apontado por p : %d \n ’ ’ ,∗p ) ;
8 p1 = p ;
9 p r i n t f ( ‘ ‘ Conteudo apontado por p1 : %d \n ’ ’ ,∗p1
) ;
10 p = &y ;
11 p r i n t f ( ‘ ‘ Conteudo apontado por p : %d \n ’ ’ ,∗p ) ;
12 p r i n t f ( ‘ ‘ Conteudo apontado por p : %f \n ’ ’ ,∗p ) ;
13 p r i n t f ( ‘ ‘ Conteudo apontado por p : %f \n ’ ’ , ∗ ( (
f l o a t ∗ ) p ) ) ;
14
15 system ( ‘ ‘ pause ’ ’ ) ;
16 return 0;
17 }
Saı´da Conteudo apontado por p: 10
Conteudo apontado por p1: 10
Conteudo apontado por p: 1101004800
Conteudo apontado por p: 0.000000
Conteudo apontado por p: 20.000000
No exemplo acima, um enderec¸o de uma varia´vel do tipo float e´ atribuido a
um ponteiro do tipo int (linha 10). Note que qualquer tentativa de acessar
o seu conteu´do se mostra falha (linhas 11 e 12). So´ conseguimos acessar
corretamente o seu conteu´do quando utilizamos o operador de typecast
sobre o ponteiro e antes de acessar o seu conteu´do (linha 13).
Um ponteiro pode receber o enderec¸o apontado por outro
ponteiro, se ambos forem do mesmo tipo.
Se dois ponteiros sa˜o do mesmo tipo, enta˜o eles podem quardar enderec¸os
de memo´ria para o mesmo tipo de dado. Logo a atribuic¸a˜o entre eles e´
possı´vel. Isso e´ mostrado no exemplo anterior (linhas 8 e 9).
193
Um ponteiro pode receber um valor hexadecimal represen-
tado um enderec¸o de memo´ria diretamente. Isso e´ muito
u´til quando se trabalha, por exemplo, com microcontrolado-
res.
1 #include <s t d i o . h>
2 #include <s t d l i b . h>
3 i n t main ( ) {
4 / / Enderec¸o hexadecimal da por ta s e r i a l
5 i n t ∗p = 0x3F8 ;
6 / /O va lo r em decimal e´ conver t ido para seu
va lo r haxadecimal : 0x5DC
7 i n t ∗p1 = 1500;
8 p r i n t f ( ‘ ‘ Endereco em p : %p \n ’ ’ , p ) ;
9 p r i n t f ( ‘ ‘ Endereco em p1 : %p \n ’ ’ , p1 ) ;
10 system ( ‘ ‘ pause ’ ’ ) ;
11 return 0;
12 }
Saı´da Endereco em p: 000003F8
Endereco em p1: 000005DC
Na linguagem C, um valor hexadecimal deve comec¸ar com “0x” (um zero
seguido de um x), seguido pelo valor em formato hexadecimal, que pode
ser formado por:
• dı´gitos: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
• letras: A, B, C, D, E, F.
Deve-se tomar muito cuidado com esse tipo de utilizac¸a˜o de ponteiros,
principalmente quando queremos acessar o conteu´do daquela posic¸a˜o de
memo´ria. Afinal de contas, o que existe na posic¸a˜o de memo´ria 0x5DC?
Esse e´ um erro muito comum.
9.2.2 ARITME´TICA COM PONTEIROS
As operac¸o˜es aritme´tica utilizando ponteiros sa˜o bastante limitadas, o que
facilita o seu uso. Basicamente, apenas duas operac¸o˜es aritme´ticas po-
dem ser utilizadas nos enderec¸os armazenados pelos ponteiros: adic¸a˜o e
subtrac¸a˜o.
194
Sobre o valor de enderec¸o armazenado por um ponteiro
podemos apenas somar e subtrair valores INTEIROS.
1 #include <s t d i o . h>
2 #include <s t d l i b . h>
3 i n t main ( ) {
4 i n t ∗p = 0x5DC ;
5 p r i n t f ( ‘ ‘ p = Hexadecimal : %p Decimal : %d \n ’ ’ ,
p , p ) ;
6 / / Incrementa p em uma posic¸ a˜o
7 p++;
8 p r i n t f ( ‘ ‘ p = Hexadecimal : %p Decimal : %d \n ’ ’ ,
p , p ) ;
9 / / Incrementa p em 15 posi c¸ o˜es
10 p = p + 15;
11 p r i n t f ( ‘ ‘ p = Hexadecimal : %p Decimal : %d \n ’ ’ ,
p , p ) ;
12 / / Decrementa p em 2 posi c¸ o˜es
13 p = p − 2;
14 p r i n t f ( ‘ ‘ p = Hexadecimal : %p Decimal : %d \n ’ ’ ,
p , p ) ;
15 system ( ‘ ‘ pause ’ ’ ) ;
16 return 0;
17 }
Saı´da p = Hexadecimal: 000005DC Decimal: 1500
p = Hexadecimal: 000005E0 Decimal: 1504
p = Hexadecimal: 0000061C Decimal: 1564
p = Hexadecimal: 00000614 Decimal: 1556
As operac¸o˜es de adic¸a˜o e subtrac¸a˜o no enderec¸o permitem avanc¸ar ou re-
troceder nas posic¸o˜es de memo´ria do computador. Esse tipo de operac¸a˜o
e´ bastante u´til quando trabalhamos com arrays, por exemplo. Lembre-se:
um array nada mais e´ do que um conjuno de elementos adjacentes na
memo´ria.
Ale´m disso, todas as operac¸o˜es de adic¸a˜o e subtrac¸a˜o no enderec¸o devem
ser inteiras. Afinal de contas, na˜o da´ para andar apenas MEIA posic¸a˜o na
memo´ria.
No entanto, e´ possı´vel notar no exemplo anterior que a operac¸a˜o de incre-
mento p++ (linha 7) na˜o incrementou em uma posic¸a˜o o enderec¸o, mas sim
em quatro posic¸o˜es: ele foi da posic¸a˜o 1500 para a 1504. Isso aconteceu
por que nosso ponteiro e´ do tipo inteiro (int *).
195
As operac¸o˜es de adic¸a˜o e subtrac¸a˜o no enderec¸o depen-
dem do tipo de dado que o ponteiro aponta.
Suponha um ponteiro para inteiro, int *p. Esse ponteiro devera´ receber um
enderec¸o de um valor inteiro. Quando declaramos uma varia´vel interia (int
x), o computador reserva um espac¸o de 4 bytes na memo´ria para essa
varia´vel. Assim, nas operac¸o˜es de adic¸a˜o e subtrac¸a˜o sa˜o adicionados/-
subtraı´dos um total de 4 bytes por incremento/decremento,