Buscar

Ponteiros em Arrays e Alocação Dinâmica de Memória

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 9 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 9 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 9 páginas

Prévia do material em texto

2ºAula
Ponteiros – parte II
Objetivos de aprendizagem
Ao término desta aula, vocês serão capazes de: 
•	 compreender como funcionam os ponteiros para vetores e matrizes;
•	 entender como usar os ponteiros que apontam para ponteiros e;
•	 saber como usar ponteiros para registros.
Olá, 
Prosseguindo os nossos estudos a respeito de ponteiros, 
nesta aula, vamos ver alguns usos mais avançados de ponteiros. 
Veremos como podemos criar e usar ponteiros que apontam 
para arrays (vetores e matrizes), ponteiros que apontam para 
outros ponteiros, e por fim, ponteiros que apontam para 
registros.
Lembre-se de ler atentamente este material. Se preferir, 
você pode executar os programas mostrados para entender 
melhor os conceitos apresentados. Se tiver alguma dúvida, 
manifeste no fórum ou no quadro de avisos da disciplina.
Bons estudos!
Estrutura de Dados I 14
1 - Usando ponteiros em vetores (arrays unidimensionais)
2 - Usando ponteiros em matrizes (arrays 
multidimensionais) 
3 - Alocação dinâmica de memória para vetores
4 - Ponteiros para Ponteiros
5 - Ponteiros para Registros
1 - Usando ponteiros em vetores 
(arrays unidimensionais)
Nesta seção, vamos aprender como usar ponteiros em 
arrays. Primeiramente, vamos mostrar como funciona a 
declaração de ponteiros. A declaração é similar ao que você 
viu anteriormente. Para vetores, não precisamos especificar o 
tamanho do array. Além disso, se criarmos um vetor por meio 
de uma variável comum, não precisamos usar o operador 
& para pegar o seu endereço, pois o nome da variável que 
corresponde a um vetor por si só contém o endereço do vetor.
Para entendermos isso, vamos a mais um exemplo:
Exemplo 1.8 - Testando o uso de ponteiros para vetores
Execute o programa e veja. O valor da primeira posição 
será exibido.
Seções de estudo
Isso significa que quando passamos o nome de um vetor, 
sem especificar qual é o seu índice para o ponteiro, estamos 
passando o endereço de memória da primeira posição do vetor.
Figura 1 – Figura ilustrativa que mostra uma variável p, 
que recebeu o endereço da primeira posição do vetor v.
Fonte: MARTINEZ, 2009, p. 338.
Podemos também especificar para o ponteiro a posição 
de memória que armazena um elemento de índice específico 
do vetor. Vamos demonstrar:
Exemplo 1.9 - Testando a forma direta de se declarar 
ponteiros
Comentamos anteriormente ao comando de exibição que 
esperamos que os valores 0 e 30, equivalentes as posições 0 e 
3 do vetor, seriam exibidas. Quando executamos o programa, 
observamos que o comportamento esperado foi feito, 
mostrando que podemos fazer essa forma de passagem de 
15
endereço para declararmos uma posição específica do vetor.
Outra forma que podemos utilizar é por meio de um 
ponteiro que aponta para posição do elemento inicial do 
vetor, criar um novo ponteiro, simplesmente adicionando 
quantas posições queremos avançar no vetor. Isso mesmo: 
podemos fazer operações aritméticas (adição e subtração) 
com endereços de memória para vetores, para que possamos 
chegar a um elemento em especial.
Como sempre, vamos a mais um programa que 
demonstra essa capacidade.
Exemplo 1.10 - Testando a navegação entre os elementos 
do vetor usando ponteiros
Executamos esse código e vimos que a propriedade 
aritmética é verdadeira. O primeiro e o quarto item do vetor 
são exibidos na tela.
Assim, podemos fazer várias operações usando essa 
possibilidade que a linguagem C++ oferece para nós 
programadores. Vamos a algumas outras possibilidades, dado 
o fato que o ponteiro apt recebeu o endereço de memória do 
vetor vet, de 10 posições:
1. Para salvar o número 5 no índice 4 (5ª posição do 
vetor), posso fazer isso: *(apt + 4) = 5, o que seria 
equivalente a escrever vet[4] = 5;
2. Posso usar os operadores de incremento e 
decremento para fazer a transição entre os elementos 
do vetor, da seguinte forma: apt++ e apt-- (lembre-
se de não usar o asterisco nesse caso);
3. Se eu sei a quantidade de elementos de um vetor, 
posso verificar a última posição do vetor da seguinte 
forma: apt + n, onde n é o número de elementos 
do vetor. Para testar se o ponteiro aponta para uma 
posição válida do vetor, posso testar se o endereço 
do ponteiro é menor que o ponteiro com a posição 
final do vetor. Isso é semelhante quando testamos os 
índices de um vetor, pois como os índices começam 
com zero, os índices do vetor vão de zero a n-1.
Pode parecer complicado isso. Mas, para que você 
entenda como funciona de uma vez por todas, vamos a 
mais um programa. O programa que apresentamos a seguir 
realiza a soma de cinco valores presentes em um vetor. São 
empregados neste programa dois loops, sendo que o primeiro 
realiza a leitura dos valores e o segundo, a soma propriamente 
dita. 
O primeiro loop usa uma variável contadora para 
controlar os índices do vetor. Usamos apenas um ponteiro 
para controlar esse vetor. Para propiciar o armazenamento 
dos dados lidos do teclado, usamos a forma especificada no 
item 1 acima.
Já para o segundo loop criamos um novo ponteiro, 
chamado de apt_fim, cujo endereço é somado a 5 (o número 
de elementos do vetor). Assim, esse ponteiro passa a ser usado 
como uma variável de controle para verificarmos se estamos 
usando índices válidos do nosso vetor. E o ponteiro apt é 
incrementado a cada nova interação, passando a apontar para 
o próximo item do vetor a cada loop executado.
Estrutura de Dados I 16
Vamos ao código.
Exemplo 1.10 - Interando entre índices do vetor
Executamos esse programa e inserimos os números. 
Nesse exemplo, inseri os valores 1, 2, 3, 4 e 5. A soma deve dar 
15. Como você pode perceber, o comportamento esperado 
ocorreu sem nenhum erro.
Por último, vamos falar de como usar vetores em 
funções. Você sabe que por questões de economia de 
memória, a linguagem C++ (e a sua antecessora C) adotam a 
passagem de parâmetro por referência quando os parâmetros 
são vetores e matrizes. Nesta seção, você viu que uma variável 
que declaramos como vetor é na verdade, um ponteiro para 
a primeira posição do vetor. Assim, nada impede que você 
declare ponteiros para vetores como parâmetros do vetor. 
O trecho de código a seguir mostra uma função para 
somar itens de um vetor, declarada da forma tradicional, 
como você já viu em outras disciplinas:
A segunda forma que apresentamos usa um ponteiro 
como parâmetro.
Como uma variável vetor é considerado um ponteiro 
para o primeiro elemento do vetor, as duas funções poderiam 
ser chamadas usando um mesmo trecho de código, como, por 
exemplo:
Agora que você está familiarizado sobre ponteiros 
para vetores, vamos para ponteiros em matrizes ou 
segundo a nomenclatura oficial da linguagem C++, arrays 
multidimensionais.
2 - Usando ponteiros em matrizes 
(arrays multidimensionais) 
Usar ponteiros em matrizes é quase igual que usar 
ponteiros apontando para vetores. Apenas algumas questões 
pontuam a diferença de uso entre esses dois tipos de arrays. 
A primeira diferença é que, na notação de ponteiros, uma 
matriz é vista como um vetor gigante. Ao invés de ser uma 
tabela, uma matriz é alocada na memória sequencialmente, 
linha por linha. Assim, em uma matriz de duas linhas por duas 
17
colunas, o compilador aloca primeiro o índice 0,0, depois o 
índice 0,1. Encerrada a primeira linha, é alocada a segunda 
linha, com os índices 1,0 e 1,1.
A figura a seguir mostra como funciona a alocação de 
memória para matrizes.
Figura 2 – Representação da alocação de espaço na 
memória para uma matriz.
Fonte: MARTINEZ, 2009, p. 349.
Dessa maneira, saiba que trabalhar com ponteiros para 
matrizes é igual a trabalhar com ponteiros para vetores. A 
declaração é mesma, a atribuição de valores é similar (não 
se esqueça da quantidade de índices a serem trabalhados). 
Porém, se você deseja usar operadores aritméticos para iterar 
entre as posições do vetor, saiba que devemos entender que 
a matriz é trabalhada como se fosse um vetor, e que a ordem 
de interação nesse caso é linha por linha, como esclarecemos 
na imagemacima.
Mas, para deixar ainda mais claro, vamos a mais um 
exemplo. Esse exemplo realiza a leitura (dentro da função 
principal) e a escrita na tela (através da função exibeMat) de 
valores presentes em uma matriz de 3 linhas por 3 colunas.
Exemplo 1.12 - Testando ponteiros para matrizes
A tela a seguir mostra a execução do programa.
A seguir, vamos abordar a alocação dinâmica de memória 
para vetores.
3 - Alocação dinâmica de memória 
para vetores
Podemos alocar memória para vetores e matrizes de 
forma dinâmica na linguagem C++, usando o já conhecido 
operador new, com algumas adaptações.
Para alocar memória dinamicamente a um vetor, usamos 
a seguinte sintaxe:
Nesse trecho de código, estamos alocando memória para 
o vetor valores um vetor de dez números do tipo double. A 
partir da alocação desse vetor, podemos trabalhar com esse 
ponteiro da mesma forma que mostramos anteriormente. 
Quando o vetor não for necessário, podemos desalocar a 
memória reservada com o operador delete, da seguinte forma:
O código a seguir mostra um programa que trabalha 
com a alocação dinâmica para vetores. Ele aloca um vetor 
de cinco números inteiros, e em seguida realiza a leitura e a 
soma dos valores do vetor. Quando a operação é terminada, 
desalocamos a memória desse ponteiro e verificamos se essa 
Estrutura de Dados I 18
desalocação foi feita com êxito.
Exemplo 1.13 - Testando alocação dinâmica de memória 
para vetores
Executamos o programa e vimos que o comportamento 
esperado ocorreu.
Agora, vamos ver como funcionam ponteiros para 
ponteiros.
4 - Ponteiros para ponteiros
O título desta seção é verdadeiro. É possível criar ponteiros 
que apontam para ponteiros, que por sua vez, apontam 
para valores armazenados na memória. Para entendermos 
esse conceito, vamos relembrar alguns conceitos. Quando 
escrevemos:
Estamos declarando uma variável. Por sua vez, quando 
escrevemos esse trecho:
Sabemos que está declarando um ponteiro para um 
número inteiro e que estamos atribuindo o endereço de 
memória da variável número para o ponteiro apt. Supondo 
que as variáveis apt e número estão alocadas nos endereços 
hipotéticos de memória 95 e 65, respectivamente, temos a 
seguinte disposição de memória:
Figura 3 – Figura ilustrativa que mostra a disposição de 
memória entre as variáveis apt e número.
Fonte: Acervo pessoal.
Podemos declarar um ponteiro para outro ponteiro da 
seguinte forma:
Os dois asteriscos indicam a sua situação de ponteiro. 
Essa variável só aceita um endereço de memória de outro 
ponteiro, do mesmo tipo da sua declaração. Assim, não 
podemos atribuir o endereço de memória da variável número, 
mas sim da variável apt, da seguinte forma:
Supondo que apt_duplo está alocada na posição 152, 
temos a seguinte configuração de memória:
Figura 4 – Figura ilustrativa que mostra a disposição de 
memória entre as variáveis apt_duplo, apt e número.
Fonte: Acervo pessoal.
Assim, temos as seguintes possibilidades (considerando 
19
esse cenário hipotético):
O programa a seguir testa essas possibilidades. Declaramos 
essas variáveis, e comparamos essas possibilidades.
Exemplo 1.14 - Testando ponteiros para ponteiros
Os endereços de memória podem variar, mas observe 
que quando fazemos a comparação entre os endereços de 
memória e os valores, obtemos valores iguais.
Estamos chegando ao final. Mas, antes de encerrarmos 
esse assunto, vamos a mais uma possibilidade: Ponteiros para 
registros.
5 - Ponteiros para Registros
Você sabe que os registros são variáveis compostas 
heterogêneas, possibilitando misturar variáveis de diversos 
tipos. Podemos criar ponteiros para variáveis do tipo registro. 
Antes de entendermos como funciona, vamos ver a declaração 
do nosso registro de teste:
Podemos declarar uma nova variável desse tipo da 
seguinte forma:
Da mesma forma como uma variável apontadora comum, 
podemos declarar um ponteiro e atribuir um endereço de 
memória alocado para uma variável de um registro da seguinte 
forma:
Uma vez declarado esse ponteiro, e realizada a atribuição 
do endereço no ponteiro, podemos acessar os elementos 
deste registro de duas formas:
•	 Com desreferenciamento, usando o operador 
asterisco (*) e o tradicional operador de ponto;
•	 Sem desreferenciamento, usando o operador seta 
(->) para acessar os elementos do registro, sem a 
necessidade de usar o operador asterisco.
A tabela a seguir mostra essas possibilidades de acesso 
aos elementos do registro:
Tabela 1 - Situações equivalentes de acesso aos elementos 
do registro. Em cada linha é apresentada uma sequência 
equivalente de acesso a um elemento do registro.
Na variável original Com desreferenciamento Sem desreferenciamento
reg.número (*reg).número reg->número
Fonte: Acervo pessoal.
O programa a seguir faz o teste de um ponteiro 
apontando para um registro.
Estrutura de Dados I 20
Exemplo 1.15 - Testando ponteiros para registros
A imagem a seguir mostra o programa em execução.
Além disso, podemos declarar ponteiros para vetores de 
registros. Sua declaração e uso obedecem à mesma forma com 
ponteiros para vetores de tipos primitivos, mas obedecendo 
as regras para o acesso aos dados de um registro de uma 
determinada posição. 
O programa a seguir ilustra o uso de ponteiros para 
vetores de registros. Neste exemplo, declaramos um vetor de 
três posições. O programa realiza a leitura e apresenta na tela 
os dados. Vamos ao código.
Exemplo 1.15 - Testando ponteiros para vetores de 
registros
A tela a seguir mostra uma situação de execução do 
programa:
E com isso, finalizamos a nossa aula. Na próxima aula, 
veremos sobre recursividade e noções de complexidade de 
algoritmos.
21
Retomando a aula
Chegamos	 ao	 final	 da	 nossa	 segunda	 aula.	 Vamos	
relembrar os conceitos iniciais?
1 - Usando ponteiros em vetores (arrays 
unidimensionais)
Nessa seção, aprendemos que uma variável que é 
declarada como um vetor é na verdade um apontador para a 
primeira posição do vetor. Vimos também que existem muitas 
formas de se trabalharem com declaração de índices para 
ponteiros. Observamos que para acessar posições diferentes 
do vetor, basta somar (ou subtrair) o número de posições que 
queremos chegar a um vetor, pegar o endereço de memória do 
índice do vetor diretamente (usando o já conhecido operador 
&) ou simplesmente incrementar ou decrementar o ponteiro 
usando os operadores ++ e --.
2 - Usando ponteiros em matrizes (arrays 
multidimensionais) 
Nessa seção, aprendemos que podemos usar ponteiros 
para matrizes da mesma forma que trabalhamos como vetores. 
Devemos ter em mente é uma matriz é alocada na memória 
sequencialmente, sendo cada linha da matriz concatenada 
com a próxima linha.
3 - Alocação dinâmica de memória para vetores
Nessa seção, verificamos que podemos usar as técnicas 
de alocação dinâmica de memória da linguagem C++ para 
vetores, usando os operadores new e delete. Quando um 
vetor é alocado dinamicamente, podemos utilizar da mesma 
forma como esclarecemos nas seções anteriores.
4 - Ponteiros para Ponteiros
Nessa seção, vimos que podemos fazer ponteiros para 
ponteiros, usando o conceito da indireção dupla. Devemos 
declarar esses ponteiros com dois asteriscos, e esse ponteiro 
só deve receber endereços de memória para ponteiros do 
mesmo tipo declarado.
5 - Ponteiros para Registros
Nessa seção, vimos que podemos fazer ponteiros para 
variáveis do tipo registro. Sua declaração é feita da mesma forma 
que uma variável comum. Mas, para acessar seus elementos, 
existem duas formas. Uma com o operador asterisco, chamada 
de com desreferenciamento, e outra que não exige o operador 
asterisco, mas usa-se o operador seta ao invés do ponto. Essa 
forma é chamada de sem desreferenciamento.
HOLZNER, Steven; ANTUNES, Alvaro Rodrigues. 
C++ : black book. São Paulo: Makron Books do Brasil, 
2001.
JAMSA, Kris; KLANDERM LARS; SANTOS, 
Jeremias René D. Pereira dos. Programando em C/C++ : a 
bíblia. São Paulo: Makron Books do Brasil, 1999.
KENT, Jeff. C++ desmistificado.Rio de Janeiro: Alta 
Books, 2004.
MARTINEZ, Fábio Henrique Viduani. Programação de 
Computadores I. UFMS, 2009. 
Disponível em: <http://www.facom.ufms.
br/~montera/progiv1.pdf>. Acesso em: 19 mai. 2018.
TENENBAUM, Aaron M.; AUGENSTEIN, Moshe 
J.; LANGSAN, Yedidyah. et al. Estruturas de dados usando 
C. São Paulo: Pearson Makron Books; São Paulo: Makron 
Books do Brasil; São Paulo: McGraw-Hill, 2013.
Vale	a	pena ler
FEOFILOFF, Paulo. Endereços e ponteiros. 2018. 
Disponível em: <https://www.ime.usp.br/~pf/
algoritmos/aulas/pont.html>. Acesso em: 19 mai. 2018.
SANCHES, Bruno Crivelari. Matrizes Dinâmicas. 
PontoV, 2009. Disponível em: <http://www.pontov.
com.br/site/cpp/46-conceitos-basicos/57-matrizes-
dinamicas>. Acesso em: 19 mai. 2018.
Vale	a	pena acessar
Vale a pena
Minhas anotações

Outros materiais