Você está na página 1de 62

Algoritmos e

estruturas de dados I
Ponteiros

Elverton Fazzion

Algoritmos e estruturas de dados I


Revisão sobre variáveis
● Uma variável é uma posição de memória que armazena um
valor
○ Cada posição de memória do computador possui um endereço

Endereço Conteúdo
6612 891
6613 'a'
6614 8
6615 16.1
6616 0.4543
6617 298347

Algoritmos e estruturas de dados I 2


Revisão sobre variáveis
● A partir dos endereços, o computador sabe qual é o valor
armazenado em cada uma das posições de memória
○ Como a memória pode ter bilhões de posições, é difícil controlar em
qual endereço está armazenado um determinado valor!
○ Para facilitar o controle sobre onde armazenar informação, os
programas utilizam variáveis.
○ Uma variável corresponde a um nome simbólico (ou etiqueta) de
uma posição de memória.

Variável Endereço
idade 6614
salario 6612
frac 6615

Algoritmos e estruturas de dados I 3


Revisão sobre variáveis
● A partir dos endereços, o computador sabe qual é o valor
armazenado em cada uma das posições de memória
○ Como a memória pode ter bilhões de posições, é difícil controlar em
qual endereço está armazenado um determinado valor!
○ Para facilitar o controle sobre onde armazenar informação, os
programas utilizam variáveis.
○ Uma variável corresponde a um nome simbólico (ou etiqueta) de
uma posição de memória.

Variável Endereço
Endereço de
idade 6614 memória em
variável usada que o conteúdo
salario 6612
no programa da variável
frac 6615 está
armazenado

Algoritmos e estruturas de dados I 4


Revisão sobre variáveis

Endereço Conteúdo
6612 891
Variável Endereço
6613 'a'
idade 6614
6614 8
salario 6612
6615 16.1
frac 6615 6616 0.4543
6617 298347

Variável salario é um nome para o endereço de memória


6612. Posição 6612 tem como conteúdo o número 891

Algoritmos e estruturas de dados I 5


Revisão sobre variáveis

● Uma variável representa um endereço de memória


○ O endereço possui conteúdo

Endereço Variável Conteúdo


6612 salario 891
6613 c 'a'
6614 idade 8
6615 velocidade 16.1
6616 frac 0.4543
6617 km 298347

Algoritmos e estruturas de dados I 6


Revisão sobre variáveis
● Vimos que uma memória é endereçada por bytes
○ O endereço de uma variável representa o endereço inicial da
variável (onde o primeiro bit começa)
○ Por exemplo, se a variável tiver 2 bytes, o programa lê dois
bytes a partir do endereço inicial

Endereço Variável Conteúdo A variável salario tem 2 bytes


6612 salario e começa no endereço 6612
891
6613
Para recuperar o conteúdo da
6614 idade
variável salario, temos que ler
8
6615 2 bytes a partir do endereço 6612

Algoritmos e estruturas de dados I 7


Revisão sobre sistema hexadecimal
● A tabela abaixo lista a correspondência entre os
sistemas binário, decimal e hexadecimal
Hexa Decimal Binário
0 0 0000
bin para hex
1 1 0001
2 2 0010
110101112
3 3 0011
4 4 0100 11010111
5 5 0101
6 6 0110 D 7
7 7 0111
8 8 1000
9 9 1001 hex para bin
A 10 1010 0022FF74
B 11 1011
C 12 1100
D 13 1101
E 14 1110
0000 0000 0010 0010 1111 1111 0111 0100
F 15 1111

Algoritmos e estruturas de dados I 8


Endereços de variáveis

● Uma variável representa um endereço de memória


○ Podemos recuperar esse endereço através do operador &
○ Endereços de memória são escritos em hexadecimal

#include <stdio.h>

int main(){
int x = 3;
printf("%d %p\n", x, &x);
return 0;
}

Valor Endereço
em
Hexadecimal
Imprime o valor de um
ponteiro!

Algoritmos e estruturas de dados I 9


Endereços de variáveis

● Note que o endereço de uma variável é um valor


○ Logo, uma variável pode armazenar um endereço!

● Uma variável que armazena um endereço de memória


é conhecida como ponteiro (pointer)

Endereço Variável Conteúdo


0022FF72 idade 8
0022FF73 velocidade 16.1
0022FF74 x 3
0022FF75 km 298347
0022FF76 y 0022FF74

Algoritmos e estruturas de dados I 10


Endereços de variáveis

● Suponha que y armazene o endereço 0022FF74 de


uma posição de memória representada pela variável x
e que x contenha o valor inteiro 3
○ Esquematicamente, podemos representar:

y 0022FF74 3 x

0022FF76 0022FF74

● Diz-se que y é um ponteiro para x, ou que y aponta para x.

Algoritmos e estruturas de dados I 11


Declarando ponteiros

● Para declarar um ponteiro, usamos a seguinte


estrutura

<Modificador> <tipo> *<nome da variável>;

● O tipo da variável é importante para que o compilador


saiba quantos bytes ler da memória a partir do
endereço inicial
○ Dessa forma, uma variável que armazena um endereço
também possui um tipo para indicar o tipo da variável apontada

Algoritmos e estruturas de dados I 12


Exemplo de declaração de ponteiros

● O código abaixo declara um ponteiro *y que aponta


para um valor short int.
○ Recuperamos o endereço de x através do operador de
endereço (&)
○ Atribuímos o endereço de x a y

#include <stdio.h>

int main(){
NULL é um valor que indica que o
short int *y = NULL;
ponteiro está apontando pra “nada”
short int x = 3;
y = &x;
Podemos fazer verificações como
printf("%p %p\n", &x, y);
if (pointer == NULL)
return 0;
}

y recebe o endereço de x

Algoritmos e estruturas de dados I 13


Acessando conteúdo do endereço

● Dado um endereço de memória, é possível acessar o


conteúdo do endereço usando o operador *<ponteiro>

y 0022FF74 3 x (ou *y)

0022FF76 0022FF74

Algoritmos e estruturas de dados I 14


Acessando conteúdo do endereço

● Dado um endereço de memória, é possível acessar o


conteúdo do endereço usando o operador *<ponteiro>

#include <stdio.h>
Endereço Variável Conteúdo
int main(){
short int *y = NULL; 0022FF74
short int x = 3;
y = &x; 0022FF75
printf("%d %d\n", x, *y);
*y = 5;
0022FF76 y NULL
printf("%d %d\n", x, *y);
return 0;
}

Algoritmos e estruturas de dados I 15


Acessando conteúdo do endereço

● Dado um endereço de memória, é possível acessar o


conteúdo do endereço usando o operador *<ponteiro>

#include <stdio.h>
Endereço Variável Conteúdo
int main(){
short int *y = NULL; 0022FF74 x 3
short int x = 3;
y = &x; 0022FF75
printf("%d %d\n", x, *y);
*y = 5;
0022FF76 y NULL
printf("%d %d\n", x, *y);
return 0;
}

Algoritmos e estruturas de dados I 16


Acessando conteúdo do endereço

● Dado um endereço de memória, é possível acessar o


conteúdo do endereço usando o operador *<ponteiro>

#include <stdio.h>
Endereço Variável Conteúdo
int main(){
short int *y = NULL; 0022FF74 x 3
short int x = 3;
y = &x; 0022FF75
printf("%d %d\n", x, *y);
*y = 5;
0022FF76 y 0022FF74
printf("%d %d\n", x, *y);
return 0;
}

Algoritmos e estruturas de dados I 17


Acessando conteúdo do endereço

● Dado um endereço de memória, é possível acessar o


conteúdo do endereço usando o operador *<ponteiro>

#include <stdio.h>
Endereço Variável Conteúdo
int main(){
short int *y = NULL; 0022FF74 x 3
short int x = 3;
y = &x; 0022FF75
printf("%d %d\n", x, *y);
*y = 5;
0022FF76 y 0022FF74
printf("%d %d\n", x, *y);
return 0;
}
O que será impresso?

Algoritmos e estruturas de dados I 18


Acessando conteúdo do endereço

● Dado um endereço de memória, é possível acessar o


conteúdo do endereço usando o operador *<ponteiro>

#include <stdio.h>
Endereço Variável Conteúdo
int main(){
short int *y = NULL; 0022FF74 x 5
short int x = 3;
y = &x; 0022FF75
printf("%d %d\n", x, *y);
*y = 5;
0022FF76 y 0022FF74
printf("%d %d\n", x, *y);
return 0;
} Modifica o conteúdo dos endereços 0022FF74 e
0022FF74 para 5. Isso porque y é ponteiro para
short int, então são modificados apenas 2 bytes
a partir do endereço 0022FF74

Algoritmos e estruturas de dados I 19


Acessando conteúdo do endereço

● Dado um endereço de memória, é possível acessar o


conteúdo do endereço usando o operador *<ponteiro>

#include <stdio.h>
Endereço Variável Conteúdo
int main(){
short int *y = NULL; 0022FF74 x 5
short int x = 3;
y = &x; 0022FF75
printf("%d %d\n", x, *y);
*y = 5;
0022FF76 y 0022FF74
printf("%d %d\n", x, *y);
return 0;
}
O que será impresso?

Algoritmos e estruturas de dados I 20


Aritmética com ponteiros

● Essencialmente, duas operações aritméticas podem ser


usadas nos endereços armazenados por ponteiros
○ Cada vez que um ponteiro é incrementado, o valor do endereço
incrementa um número de bytes igual ao seu tipo base;
○ Quando um ponteiro é decrementado, o valor do endereço
decrementa um número de bytes igual ao seu tipo base;

#include <stdio.h>

int main(){
int *p = 0x5DC;
printf(“Hex=%p\n”, p);
p++;
printf(“Hex=%p\n”, p);
p++; O incremento foi de 4 bytes pois o
printf(“Hex=%p\n”, p);
tipo do ponteiro é int (4 bytes)
return 0;
}

Algoritmos e estruturas de dados I 21


Ponteiros como parâmetros de função

● Parâmetros podem ser ponteiros

#include <stdio.h>

void zera_inteiro(int *x){


*x = 0;
}

int main(){
int x = 9;
printf("%d\n", x);
zera_inteiro(&x);
printf("%d\n", x);
return 0;
}

Algoritmos e estruturas de dados I 22


Ponteiros como parâmetros de função

● Parâmetros podem ser ponteiros

#include <stdio.h> Endereço Variável Conteúdo


void zera_inteiro(int *x){ 0022FF74 x
*x = 0;
0022FF75
} 9
0022FF76
int main(){
int x = 9; 0022FF77
printf("%d\n", x);
zera_inteiro(&x);
printf("%d\n", x);
return 0;
}

Algoritmos e estruturas de dados I 23


Ponteiros como parâmetros de função

● Parâmetros podem ser ponteiros

#include <stdio.h> Endereço Variável Conteúdo


void zera_inteiro(int *x){ 0022FF74 x
*x = 0;
0022FF75
} 9
0022FF76
int main(){
int x = 9; 0022FF77
printf("%d\n", x);
zera_inteiro(&x);
printf("%d\n", x);
return 0;
}

O que será impresso?

Algoritmos e estruturas de dados I 24


Ponteiros como parâmetros de função

● Parâmetros podem ser ponteiros

#include <stdio.h> Endereço Variável Conteúdo


void zera_inteiro(int *x){ 0022FF74 x
*x = 0;
0022FF75
} 9
0022FF76
int main(){
int x = 9; 0022FF77
printf("%d\n", x);
zera_inteiro(&x);
printf("%d\n", x);
return 0;
}
Chama a função zera_inteiro e passa
o endereço de x como valor
(0022FF74)

Algoritmos e estruturas de dados I 25


Ponteiros como parâmetros de função

● Parâmetros podem ser ponteiros

#include <stdio.h> Endereço Variável Conteúdo


void zera_inteiro(int *x){ 0022FF74 x
*x = 0;
0022FF75
} 9
0022FF76
int main(){
int x = 9; 0022FF77
printf("%d\n", x);
zera_inteiro(&x); 0022FF78 x 0022FF74
printf("%d\n", x);
return 0;
}
Cria um ponteiro x na função
zera_inteiro e armazena o valor
0022FF74

Algoritmos e estruturas de dados I 26


Ponteiros como parâmetros de função

● Parâmetros podem ser ponteiros

#include <stdio.h> Endereço Variável Conteúdo


void zera_inteiro(int *x){ 0022FF74 x
*x = 0;
0022FF75
} 0
0022FF76
int main(){
int x = 9; 0022FF77
printf("%d\n", x);
zera_inteiro(&x); 0022FF78 x 0022FF74
printf("%d\n", x);
return 0;
}
Modifica o conteúdo do endereço
0022FF74 para 0

Algoritmos e estruturas de dados I 27


Ponteiros como parâmetros de função

● Parâmetros podem ser ponteiros

#include <stdio.h> Endereço Variável Conteúdo


void zera_inteiro(int *x){ 0022FF74 x
*x = 0;
0022FF75
} 0
0022FF76
int main(){
int x = 9; 0022FF77
printf("%d\n", x);
zera_inteiro(&x); 0022FF78 x 0022FF74
printf("%d\n", x);
return 0;
}
O que será impresso?

Algoritmos e estruturas de dados I 28


Tipos de passagem de parâmetro
● Até o momento, podemos classificar dois tipos de
parâmetros que temos para funções
○ Por valor: são feitas apenas cópias dos valores das variáveis
da chamada para os parâmetros da função
○ Por referência: passamos os endereços das variáveis ao invés
do valor da variável. Dessa forma, podemos modificar a variável

#include <stdio.h> #include <stdio.h>

//Passagem por valor //Passagem por referência


void zera_inteiro(int x){ void zera_inteiro(int *x){
x = 0; *x = 0;
} }

int main(){ int main(){


int x = 9; int x = 9;
printf("%d\n", x); printf("%d\n", x);
zera_inteiro(x); zera_inteiro(&x);
printf("%d\n", x); printf("%d\n", x);
return 0; return 0;
} }

Algoritmos e estruturas de dados I 29


Ponteiros genéricos

● Normalmente, um ponteiro aponta para um tipo específico


de dado. Porém, a linguagem C possibilita que ponteiros
genéricos sejam criados
○ Ponteiros genéricos podem apontar para todos os tipos de dados
existentes (ou que ainda serão criados)
○ Declaração de um ponteiro genérico segue a seguinte forma:

void *<nome da variável>;

Algoritmos e estruturas de dados I 30


Ponteiros genéricos

● Sempre que tivermos que acessar o conteúdo de um


ponteiro genérico, será necessário utilizar o operador de
typecast
○ Isso porque o compilador precisa saber quantos bytes deve ler a
partir do endereço armazenado no ponteiro genérico

#include <stdio.h>

int main(){
void *ponteiro = NULL; Não se sabe o
int p2 = 10;
tipo apontado!
ponteiro = &p2;
printf(“Conteúdo: %d\n”, *ponteiro); // ERRO
printf(“Conteúdo: %d\n”, *(int*)ponteiro);
return 0;
}

Algoritmos e estruturas de dados I 31


Ponteiros genéricos

● Visto que ponteiros genéricos não possuem tipos


definidos, deve-se tomar cuidado ao realizar operações
aritméticas

#include <stdio.h>

int main(){
void *p = 0x5DC;
printf("Hex=%p\n", p);
p++;
printf("Hex=%p\n", p);
p++;
printf("Hex=%p\n", p);
return 0; O incremento pulou 1 byte pois o
} tipo do ponteiro é void

Algoritmos e estruturas de dados I 32


Qual o tamanho de um ponteiro?

● Em arquiteturas de 64 bits, o espaço ocupado por um


ponteiro é de 8 bytes

#include <stdio.h>

int main(){
printf("%lu %lu %lu %lu %lu\n",
sizeof(int *),
sizeof(double *),
sizeof(char *),
sizeof(float *),
sizeof(void*)
);
return 0;
}

Algoritmos e estruturas de dados I 33


Ponteiros para ponteiros …

● É possível declarar um ponteiro que aponta para um


ponteiro
○ A sintaxe é a mesma que vimos até o momento, com a diferença
que, como é um ponteiro para ponteiro, declaramos com ** e
acessamos o conteúdo com **
○ Iremos retornar a essa questão mais adiante (matrizes)
#include <stdio.h>

int main(){
Declarando um ponteiro para um
int ** x2 = NULL;
ponteiro do tipo int *
int * x1 = NULL;
int x = 5;
x1 = &x;
x2 = &x1; Recebendo o endereço de um ponteiro do tipo int *
printf("%d\n", **x2); Imprimindo o conteúdo da variável x a partir de x2
printf("%p %p\n",
*x2, &x); Imprimindo o conteúdo de x1, que é o endereço de x
return 0;
}

Algoritmos e estruturas de dados I 34


Ponteiros para ponteiros …

● É possível declarar um ponteiro que aponta para um


ponteiro
○ A sintaxe é a mesma que vimos até o momento, com a diferença
que, como é um ponteiro para ponteiro, declaramos com ** e
acessamos o conteúdo com **

0022FF74 0022FF72 3

0022FF76 0022FF74 0022FF72

z y x

Algoritmos e estruturas de dados I 35


Ponteiros para ponteiros …

● É possível declarar um ponteiro que aponta para um


ponteiro

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 x2 NULL
int ** x2 = NULL;
0022FF7C
int * x1 = NULL;
int x = 5; 0022FF84
x1 = &x;
x2 = &x1; 0022FF88
printf("%d\n", **x2);
printf("%p %p\n",
*x2, &x);
return 0;
}

Algoritmos e estruturas de dados I 36


Ponteiros para ponteiros …

● É possível declarar um ponteiro que aponta para um


ponteiro

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 x2 NULL
int ** x2 = NULL;
0022FF7C x1 NULL
int * x1 = NULL;
int x = 5; 0022FF84
x1 = &x;
x2 = &x1; 0022FF88
printf("%d\n", **x2);
printf("%p %p\n",
*x2, &x);
return 0;
}

Algoritmos e estruturas de dados I 37


Ponteiros para ponteiros …

● É possível declarar um ponteiro que aponta para um


ponteiro

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 x2 NULL
int ** x2 = NULL;
0022FF7C x1 NULL
int * x1 = NULL;
int x = 5; 0022FF84 x 5
x1 = &x;
x2 = &x1; 0022FF88
printf("%d\n", **x2);
printf("%p %p\n",
*x2, &x);
return 0;
}

Algoritmos e estruturas de dados I 38


Ponteiros para ponteiros …

● É possível declarar um ponteiro que aponta para um


ponteiro

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 x2 NULL
int ** x2 = NULL;
0022FF7C x1 0022FF84
int * x1 = NULL;
int x = 5; 0022FF84 x 5
x1 = &x;
x2 = &x1; 0022FF88
printf("%d\n", **x2);
printf("%p %p\n",
*x2, &x);
return 0;
}

Algoritmos e estruturas de dados I 39


Ponteiros para ponteiros …

● É possível declarar um ponteiro que aponta para um


ponteiro

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 x2 0022FF7C
int ** x2 = NULL;
0022FF7C x1 0022FF84
int * x1 = NULL;
int x = 5; 0022FF84 x 5
x1 = &x;
x2 = &x1; 0022FF88
printf("%d\n", **x2);
printf("%p %p\n",
*x2, &x);
return 0;
}

Algoritmos e estruturas de dados I 40


Ponteiros para ponteiros …

● É possível declarar um ponteiro que aponta para um


ponteiro

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 x2 0022FF7C
int ** x2 = NULL; *
0022FF7C x1 0022FF84
int * x1 = NULL;
int x = 5; 0022FF84 x 5 *
x1 = &x;
x2 = &x1; 0022FF88
printf("%d\n", **x2);
printf("%p %p\n",
*x2, &x);
return 0;
} *x2 acessa o conteúdo de x1
**x2 acessa o conteúdo do
endereço em x1

Algoritmos e estruturas de dados I 41


Ponteiros para ponteiros …

● É possível declarar um ponteiro que aponta para um


ponteiro

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 x2 0022FF7C
int ** x2 = NULL; *
0022FF7C x1 0022FF84
int * x1 = NULL;
int x = 5; 0022FF84 x 5
x1 = &x;
x2 = &x1; 0022FF88
printf("%d\n", **x2);
printf("%p %p\n",
*x2, &x);
return 0;
} *x2 acessa o conteúdo de x1

&x recupera o endereço de x

Algoritmos e estruturas de dados I 42


Exercício

● Altere a função abaixo para retornar as duas raízes para a


função a chamou

double calcula_raizes(double a, double b, double c){


double delta, x1, x2;

delta = pow(b,2) - 4*a*c;


if(delta >= 0){
x1 = (-b + sqrt(delta))/(2*a);
x2 = (-b - sqrt(delta))/(2*a);
printf(“Raiz x1 = %f\nRaiz x1 = %f\n”, x1, x2);
} else {
printf(“Não tem raiz real\n”);
}
return 0;
}

Algoritmos e estruturas de dados I 43


Precedência dos operadores * e &
Operador Comentário Associatividade

() ++ - - ++ e -- tanto prefixo quanto posfixo Esquerda para direita


mais alta

! + - Operadores unários Direita para esquerda


(typecast)
&
*

Precedência
* / % Operadores multiplicativos Esquerda para direita

+ - Operadores aditivos Esquerda para direita

< <= Operadores relacionais Esquerda para direita


> >=

== != Operador lógico de igualdade Esquerda para direita

&& Operador lógico AND Esquerda para direita

|| Operador lógico OR Esquerda para direita

= += -= *= /= Operadores de atribuição Direita para esquerda


%= &= ^= |= mais baixa

Algoritmos e estruturas de dados I 44


Precedência dos operadores * e &

● Precedência de operadores é importante …

#include <stdio.h> #include <stdio.h> #include <stdio.h>

int main(){ int main(){ int main(){


int * p = NULL; int * p = NULL; int * p = NULL;
int x = 5; int x = 5; int x = 5;
p = &x; p = &x; p = &x;
*p++; *(p++); (*p)++;
printf("%d\n", *p); printf("%d\n", *p); printf("%d\n", *p);
return 0; return 0; return 0;
} } }

Incrementa o endereço em Incrementa o endereço em Acessa o conteúdo de


p e, depois, acessa o p e, depois, acessa o memória do endereço em
conteúdo de memória do conteúdo de memória do p e incrementa o conteúdo
novo endereço em p novo endereço em p desse endereço

Resultado: indefinido Resultado: indefinido Resultado: 6

Algoritmos e estruturas de dados I 45


Precedência dos operadores * e &

● O que é impresso abaixo?

#include <stdio.h>

int main(){
int * p = NULL;
int x = 5;
p = &x;
printf("%d\n", *(*(&p)));
return 0;
}

Algoritmos e estruturas de dados I 46


Precedência dos operadores * e &

● O que é impresso abaixo?

#include <stdio.h>

int main(){
int * p = NULL;
int x = 5;
p = &x;
printf("%d\n", *(*(&p)));
return 0;
}

p 0022FF74 3 x

0022FF76 0022FF74

Algoritmos e estruturas de dados I 47


Precedência dos operadores * e &

● O que é impresso abaixo?

#include <stdio.h>

int main(){
int * p = NULL;
int x = 5;
p = &x;
printf("%d\n", *(*(&p)));
return 0;
}

p 0022FF74 3 x

0022FF76 0022FF74

Algoritmos e estruturas de dados I 48


Precedência dos operadores * e &

● O que é impresso abaixo?

#include <stdio.h>

int main(){
int * p = NULL;
int x = 5;
p = &x;
printf("%d\n", *(*(&p)));
return 0;
}

p 0022FF74 3 x

0022FF76 0022FF74

Algoritmos e estruturas de dados I 49


Precedência dos operadores * e &

● O que é impresso abaixo?

#include <stdio.h>

int main(){
int * p = NULL;
int x = 5;
p = &x;
printf("%d\n", *(*(&p)));
return 0;
}

p 0022FF74 3 x

0022FF76 0022FF74

Algoritmos e estruturas de dados I 50


Brincando com ponteiros …

● Podemos criar ponteiros para apontar para diferentes tipos


○ A interpretação dos bits vai depender do tipo base do ponteiro …

#include <stdio.h>

int main(){
int N = 0x494A4C4D;
char *p = (char*)&N;
printf("%c\n", *p);
p++;
printf("%c\n", *p);
p++;
printf("%c\n", *p); ➔ Dois dígitos hexadecimal tem 1 byte
p++;
printf("%c\n", *p); ➔ Um inteiro tem 4 bytes
return 0;
}
➔ Podemos compor um inteiro usando 8
dígitos hexadecimal

Algoritmos e estruturas de dados I 51


Brincando com ponteiros …

● Podemos criar ponteiros para apontar para diferentes tipos


○ A interpretação dos bits vai depender do tipo base do ponteiro …

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 N 4D
int N = 0x494A4C4D;
0022FF75 4C
char *p = (char*)&N;
printf("%c\n", *p); 0022FF76 4A
p++;
printf("%c\n", *p); 0022FF77 49
p++;
printf("%c\n", *p); 0022FF78
p++;
printf("%c\n", *p);
return 0;
}

Algoritmos e estruturas de dados I 52


Brincando com ponteiros …

● Podemos criar ponteiros para apontar para diferentes tipos


○ A interpretação dos bits vai depender do tipo base do ponteiro …

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 N 4D
int N = 0x494A4C4D;
0022FF75 4C
char *p = (char*)&N;
printf("%c\n", *p); 0022FF76 4A
p++;
printf("%c\n", *p); 0022FF77 49
p++;
printf("%c\n", *p); 0022FF78 p 0022FF74
p++;
printf("%c\n", *p);
return 0;
}

Algoritmos e estruturas de dados I 53


Brincando com ponteiros …

● Podemos criar ponteiros para apontar para diferentes tipos


○ A interpretação dos bits vai depender do tipo base do ponteiro …

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 N 4D
int N = 0x494A4C4D;
0022FF75 4C
char *p = (char*)&N;
printf("%c\n", *p); 0022FF76 4A
p++;
printf("%c\n", *p); 0022FF77 49
p++;
printf("%c\n", *p); 0022FF78 p 0022FF74
p++;
printf("%c\n", *p);
return 0;
} p tem tipo base char (1 byte), então vai ser
recuperado 1 byte a partir do endereço em p e o valor
desse byte representa o valor de um caractere

Dessa forma, será impresso a letra M (4D em hexa)

Algoritmos e estruturas de dados I 54


Brincando com ponteiros …

● Podemos criar ponteiros para apontar para diferentes tipos


○ A interpretação dos bits vai depender do tipo base do ponteiro …

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 N 4D
int N = 0x494A4C4D;
0022FF75 4C
char *p = (char*)&N;
printf("%c\n", *p); 0022FF76 4A
p++;
printf("%c\n", *p); 0022FF77 49
p++;
printf("%c\n", *p); 0022FF78 p 0022FF75
p++;
printf("%c\n", *p);
return 0;
}
p é incrementado de 1 unidade do seu
tipo base (1 byte)

Algoritmos e estruturas de dados I 55


Brincando com ponteiros …

● Podemos criar ponteiros para apontar para diferentes tipos


○ A interpretação dos bits vai depender do tipo base do ponteiro …

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 N 4D
int N = 0x494A4C4D;
0022FF75 4C
char *p = (char*)&N;
printf("%c\n", *p); 0022FF76 4A
p++;
printf("%c\n", *p); 0022FF77 49
p++;
printf("%c\n", *p); 0022FF78 p 0022FF75
p++;
printf("%c\n", *p);
return 0;
} p tem tipo base char (1 byte), então vai ser
recuperado 1 byte a partir do endereço em p e o valor
desse byte representa o valor de um caractere

Dessa forma, será impresso a letra L (4C em hexa)

Algoritmos e estruturas de dados I 56


Brincando com ponteiros …

● Podemos criar ponteiros para apontar para diferentes tipos


○ A interpretação dos bits vai depender do tipo base do ponteiro …

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 N 4D
int N = 0x494A4C4D;
0022FF75 4C
char *p = (char*)&N;
printf("%c\n", *p); 0022FF76 4A
p++;
printf("%c\n", *p); 0022FF77 49
p++;
printf("%c\n", *p); 0022FF78 p 0022FF76
p++;
printf("%c\n", *p);
return 0;
}
p é incrementado de 1 unidade do seu
tipo base (1 byte)

Algoritmos e estruturas de dados I 57


Brincando com ponteiros …

● Podemos criar ponteiros para apontar para diferentes tipos


○ A interpretação dos bits vai depender do tipo base do ponteiro …

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 N 4D
int N = 0x494A4C4D;
0022FF75 4C
char *p = (char*)&N;
printf("%c\n", *p); 0022FF76 4A
p++;
printf("%c\n", *p); 0022FF77 49
p++;
printf("%c\n", *p); 0022FF78 p 0022FF76
p++;
printf("%c\n", *p);
return 0;
} p tem tipo base char (1 byte), então vai ser
recuperado 1 byte a partir do endereço em p e o valor
desse byte representa o valor de um caractere

Dessa forma, será impresso a letra J (4A em hexa)

Algoritmos e estruturas de dados I 58


Brincando com ponteiros …

● Podemos criar ponteiros para apontar para diferentes tipos


○ A interpretação dos bits vai depender do tipo base do ponteiro …

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 N 4D
int N = 0x494A4C4D;
0022FF75 4C
char *p = (char*)&N;
printf("%c\n", *p); 0022FF76 4A
p++;
printf("%c\n", *p); 0022FF77 49
p++;
printf("%c\n", *p); 0022FF78 p 0022FF77
p++;
printf("%c\n", *p);
return 0;
}
p é incrementado de 1 unidade do seu
tipo base (1 byte)

Algoritmos e estruturas de dados I 59


Brincando com ponteiros …

● Podemos criar ponteiros para apontar para diferentes tipos


○ A interpretação dos bits vai depender do tipo base do ponteiro …

#include <stdio.h> Endereço Variável Conteúdo


int main(){ 0022FF74 N 4D
int N = 0x494A4C4D;
0022FF75 4C
char *p = (char*)&N;
printf("%c\n", *p); 0022FF76 4A
p++;
printf("%c\n", *p); 0022FF77 49
p++;
printf("%c\n", *p); 0022FF78 p 0022FF77
p++;
printf("%c\n", *p);
return 0;
} p tem tipo base char (1 byte), então vai ser
recuperado 1 byte a partir do endereço em p e o valor
desse byte representa o valor de um caractere

Dessa forma, será impresso a letra I (49 em hexa)

Algoritmos e estruturas de dados I 60


Brincando com ponteiros …

● Podemos criar ponteiros para apontar para diferentes tipos


○ A interpretação dos bits vai depender do tipo base do ponteiro …

#include <stdio.h>

int main(){
int N = 0x494A4C4D;
char *p = (char*)&N;
printf("%c\n", *p);
p++;
printf("%c\n", *p);
p++;
printf("%c\n", *p);
p++;
printf("%c\n", *p);
return 0;
}

Algoritmos e estruturas de dados I 61


Algoritmos e
estruturas de dados I
Ponteiros

Elverton Fazzion

Algoritmos e estruturas de dados I

Você também pode gostar