Alocação dinâmica de memória

Ver Todos os Exercícios

Teoria

E aí pessoal, aqui é o Juan do Responde Aí, e hoje vamos dar uma olhada nesse assunto importantíssimo: Alocação dinâmica de memória.

Um pouco mais sobre memória

Até agora, a gente vem criando programas que declaram muitas variáveis assim que iniciam, e essas variáveis vão existir durante toda a execução de um programa, ocupando espaço na memória.

Isso se torna um problema quando desenvolvemos programas muito grandes, e muitas variáveis ocupam espaço mesmo quando não são mais necessárias. Em sistemas com pouco espaço de memória, como um microcontrolador, isso pode ser um problema sério.

Para lidar com essas questões, a gente pode utilizar alocação dinâmica de memória, que permite que o programador criar e deletar variáveis durante a execução do programa.

Alocação dinâmica de memória dinamicamente: n e w e d e l e t e

A alocação dinâmica consiste em utilizar buscar um espaço livre na memória, e nesse espaço vazio criar variáveis e vetores do jeito que a gente quiser durante a execução do programa.

Primeiro, vamos precisar de um ponteiro:

t i p o * n o m e P t r ;

Depois vamos utilizar o operador n e w que é responsável por alocar memória. E também informamos o tipo de dado que estamos criando, que deve ser compatível com o tipo usado para criar o ponteiro.

n o m e P t r = n e w   t i p o ;

E agora podemos acessar esse novo espaço de memória através do ponteiro n o m e P t r . E quando esse espaço de memória não for mais necessário, podemos liberar o espaço de memória utilizando o operador d e l e t e

d e l e t e   n o m e P t r ;

E é só isso! Olha esse exemplo:

Na linha 06 a gente criou um ponteiro qualquer, sem endereço definido. Na linha 07 a gente usa o operador n e w que vai buscar um endereço disponível na memória do computador e guarda esse endereço no ponteiro.

Através do ponteiro a gente pode acessar o endereço de memória da forma que quiser, por exemplo, na linha 09 acessamos o endereço e armazenamos o valor 3.14 no endereço apontado por p t r . Na linha 11 o endereço de memória deixa de ser útil, então usamos o operador d e l e t e para liberar a memória.

Alocando arrays dinamicamente.

Imagine que você quer criar um programa para efetuar cálculos com vetores de qualquer dimensão, e em certo momento vai efetuar operações com vetores com centenas de elementos. Deixar esses vetores ocupando espaço na memória depois de usá-los pode deixar o programa lento.

Então a melhor ideia é criar arrays dinâmicas, que são arrays alocadas dinamicamente, que só ocuparão espaço na memória quando forem necessários, podem se adaptar a qualquer tamanho de elementos e quando não forem mais úteis poderão ser deletados.

Para fazer alocação dinâmica de array só precisamos adicionar os colchetes [   ] com a quantidade de elementos que queremos pro vetor:

t i p o * p t r V e t o r ; p t r V e t o r = n e w   t i p o   t a m a n h o   ;

E na hora de liberar a array dinâmica, colocamos colchetes   vazios logo após o operador d e l e t e

d e l e t e     p t r V e t o r ;

Uma coisa legal que aprendemos nos tópicos anteriores, é que ponteiros e arrays são intimamente relacionados. E por isso, não é necessário o operador de ponteiros * para acessar os valores do vetor dinâmico.

Olha só o exemplo:

Criamos um ponteiro vazio na linha 06. Na linha 09 utilizamos o operador n e w para iniciar uma array dinâmica com 4 espaços na memória, e guardamos o endereço dessa array no ponteiro.

Nas linhas 13 a 15 acessamos alguns dos elementos do array dinâmico e preenchemos com alguns valores quaisquer, e usamos o c o u t para exibir um desses valores na linha 19. Quando o array não tem mais utilidade podemos deletá-lo, como fazemos na linha 22.

Vazamentos de memória: erro comum e perigoso.

Disparado, o erro mais comum na hora de alocar memória é esquecer de utilizar o operador d e l e t e . Nos exemplos que demos, é bem fácil de perceber a hora em que devemos utilizar o operador d e l e t e . Porém, em problemas reais é muito comum que o local de uso do n e w e d e l e t e sejam separados por dezenas ou até centenas de linhas.

Uma segunda situação é a ocorre quando o operador n e w aloca uma variável dentro uma função, e o operador d e l e t e só vai ser usado dentro de outra função. Se o programador não tiver atenção, podem existir casos em que uma das funções não é ativada corretamente.

E um outro caso comum é quando reutilizamos um mesmo ponteiro para gerar diversas variáveis dinâmicas. Acontece que quando você sobreescreve o endereço atual para onde está apontando, então não existe nenhuma forma de recuperar esse endereço. Se a variável não tiver sido deletada, então ela vai ficar ocupando memória até que o programa seja finalizado.

Em todos esses casos estamos gerando um problema conhecido como vazamento de memória (memmory leak). Basicamente, estamos ocupando a memória do computador com variáveis e arrays que nunca serão deletados. Isso gera excessivo consumo de memória e pode levar a situações em que o programa para de funcionar, e em casos muito ruins pode levar à temível “tela azul da morte do windows”

Pra piorar, nem o compilador, e nem a IDE conseguem perceber esse tipo de problema. Ou seja, se o programador não tiver atento, um vazamento de memória pode passar despercebido, até que gere um problema durante a execução do programa.

Legal demais né. Então vamos fazer uns exercícios de fixação pra você ver como isso vai funcionar na prática.

Alocação dinâmica de memória dinamicamente: n e w e d e l e t e

Alocando arrays dinamicamente.

Vazamentos de memória: erro comum e perigoso.

Exercícios Resolvidos

Exercício Resolvido #1

O que é alocação dinâmica e quais os cuidados que devemos ter ao utilizá-la?

Passo 1

A alocação dinâmica de memória é uma forma do programador controlar melhor o momento em que cada variável do programa deve ser criada, e ocupar espaço na memória, e quando elas devem ser deletadas para liberar espaço na memória ram.

O processo de alocação dinâmica busca espaços livres na memória do computador, e quando espaços vazios são encontrados, o endereço de memória é guardado em uma variável ponteiro. Através do ponteiro é possível trabalhar com este endereço de memória. E quando o endereço não for mais útil, é possível liberar essa memória, desocupando espaço na memória ram.

O processo de liberar memória é extremamente importante, e deve-se ter cuidado de sempre executá-lo na hora adequada. A não-liberação de memória é um problema conhecido como Vazamento de Memória, e pode gerar um consumo excessivo de recursos computacionais, levando a lentidão nos processos, e até pode resultar em falhas nos programas.

Resposta

Ei, a resposta está no passo a passo :)

Exercício Resolvido #2

Crie um programa que:

  1. Aloque dinamicamente um array de 5 números inteiros.
  2. Peça para o usuário digitar os 5 números no espaço alocado.
  3. Mostre na tela os 5 números
  4. Libere a memória alocada

Passo 1

Bora lá, pessoal.

Essa questão quer que a gente crie um array dinâmico, preencha e exiba essa array. Você só precisa ter uma coisa em mente quando for trabalhar com arrays dinâmicas: Elas trabalham parecido com as arrays normais!

Então, sem enrolação, vamos começar com o cabeçalho do código:

Passo 2

Primeiro de tudo, a gente precisa criar a nossa array dinâmica.

Pra criar uma array dinâmica, primeiro a gente declara um ponteiro, e em seguida utiliza o operador n e w para efetuar a alocação de memória, da seguinte forma:

t i p o * p o n t e i r o ; p o n t e i r o = n e w   t i p o [   t a m a n h o   ]

A questão pede pra criar um vetor com cinco espaços, então o t a m a n h o será 5. No código nós fazemos assim:

Na linha 07 nós criamos um ponteiro chamado v e t o r D i n a m i c o que será usado para armazenar o endereço de memória do nosso vetor dinâmico. Na linha 08 nós efetuamos a alocação dinâmica de memória.

Show! Fizemos a alocação dinâmica 😎! A partir de agora o ponteiro v e t o r D i n a m i c o pode ser tratado com uma array, e podemos trabalhar com ele utilizando os colchetes da forma como já estamos acostumados.

Passo 3

Com a alocação já feita, vamos preencher o vetor. Vamos mandar uma mensagem pra informar ao usuário que ele deve preencher o vetor:

A variável v e t o r D i n a m i c o é um ponteiro. Porém, depois que a memória é alocada, a gente pode trabalhar com o v e t o r D i n a m i c o de forma muito parecida com as arrays comuns. Da até pra usar os colchetes [   ] para acessar os elementos.

Então, pra preencher uma array dinâmica, a gente pode utilizar um loop que a cada iteração pede pro usuário inserir um dos elementos da array.

Na linha 12 nós iniciamos um loop f o r que fará 5 voltas. A cada iteração, na linha 14, nós exibimos uma mensagem solicitando um valor pro usuário.

Na linha 15 usamos o c i n para guardar o valor inserido na posição i do v e t o r D i n a m i c o . Pra acessar essa posição é só a gente utilizar os colchetes   .

Passo 4

O próximo passo é exibir o conteúdo do vetor. Novamente, vou te lembrar que a gente usa um array dinâmica igual usamos uma array normal. Então pra exibir os elementos de uma array é só usar um loop:

Na linha 19 imprimimos a mensagem “Exibindo o vetor: ” e saltamos uma linha. Na linha 20 a 23 criamos um loop f o r que a cada iteração vai exibir a posição i do v e t o r D i n a m i c o e saltar uma linha.

Passo 5

Sempre que a gente trabalhar com alocação dinâmica de memória, no último passo sempre devemos liberar a memória.

Para liberar a memória vamos usar o operador d e l e t e [   ] para apagar o vetor dinâmico que criamos:

E prontinho! A questão está finalizada.

Resposta

Exercício Resolvido #3

Implemente um programa em que obtenha do teclado o tamanho (inteiro) de um vetor, após isso aloque dinamicamente um array de f l o a t s com o tamanho obtido e então leia do teclado a os números digitados pelo usuário e armazene no novo vetor alocado. Exiba os valores contidos no array dinâmico.

Passo 1

Vamos nessa, galera.

Uma das vantagens dos arrays dinamicamente alocados é que podemos, de forma segura, pedir pro usuário escolher o tamanho das arrays. E essa questão quer que a gente use isso!

Então vamos lá, vamos começar com o cabeçalho do código:

E vamos precisar declarar duas variáveis. A primeira é a variável inteira t a m a n h o que vai receber do usuário o tamanho do array que vamos criar. E a segunda é o ponteiro para floats v e t o r D i n a m i c o , que vai ser o ponteiro que vamos usar para alocar a memória dinamicamente.

Passo 2

Primeiro de tudo, a gente precisa saber qual vai ser o tamanho da nossa array dinâmica. Então vamos perguntar pro usuário e guardar o valor na variável tamanho:

Passo 3

Beleza. Agora já temos um ponteiro e o tamanho, temos tudo que é preciso pra criar uma array dinâmica.

Lembre-se, pra criar uma array dinâmica a gente utiliza o operador n e w para efetuar a alocação de memória, e guardar o endereço da memória alocada em um ponteiro, da seguinte forma: p o n t e i r o = n e w   t i p o [   t a m a n h o   ]

No nosso código o ponteiro é o v e t o r D i n a m i c o , o tipo é f l o a t e o tamanho do array está contido na variável t a m a n h o .   Então, o código fica assim:

E assim temos uma array alocada com sucesso!

A partir de agora o podemos utilizar os colchetes [   ] no ponteiro v e t o r D i n a m i c o para acessar os elementos contidos na memória alocada dinamicamente.

Passo 4

Agora vamos pedir pro usuário preencher o vetor. Com o c o u t vamos imprimir uma mensagem pra informar ao usuário que ele deve preencher o vetor:

Para preencher o v e t o r D i n â m i c o é igual a preencher um array comum, vamos usar um loop que a cada iteração solicita um valor para o usuário:

Na linha 18 nós iniciamos um loop f o r , a quantidade de iterações vai ser igual ao tamanho do array dinâmico. Na linha 21 usamos o c i n para guardar o valor inserido na posição i do v e t o r D i n a m i c o . Pra acessar essa posição é só a gente utilizar os colchetes   .

Passo 5

O próximo passo é exibir o conteúdo do vetor. Lembre-se que um array dinâmico se comporta igual a um array comum. Então pra exibir os elementos de uma array é só usar um loop:

Na linha 25 imprimimos a mensagem “Exibindo o vetor: ” e saltamos uma linha. Nas linhas 26 a 28 criamos um loop f o r que a cada iteração vai exibir a posição i do v e t o r D i n a m i c o e saltar uma linha.

Passo 6

Sempre que a gente trabalhar com alocação dinâmica de memória, no último passo sempre devemos liberar a memória.

Para liberar a memória vamos usar o operador d e l e t e [   ] para apagar o vetor dinâmico que criamos:

E prontinho! A questão está finalizada.

Resposta

Exercício Resolvido #4

Peça ao usuário um valor n . Crie um vetor dinâmica com tamanho n . Utilize funções para preencher e exibir os valores do vetor dinâmica.

Passo 1

Bora lá, galera.

O que essa questão quer é que a gente exercite como criar funções que recebem vetors dinâmicas. O que você precisa perceber é que com as vetors dinâmicas são ponteiros. Apesar de a gente poder trabalhar com as vetors dinâmicas como se fossem vetors comuns, você deve ter sempre em mente que o que estamos fazendo de verdade é usar um ponteiro para acessar uma parte da memória alocada como um vetor.

Ou seja, uma função que quer receber um vetor dinâmica, na verdade vai receber um ponteiro.

Mas antes de construir essas funções propriamente ditas, vamos escrever o cabeçalho do código.

Passo 2

Então vamos começar criando uma função que preencha os elementos de um vetor dinâmica.

Vamos chamar essa função de p r e e n c h e V e t o r e ela vai precisar receber dois argumentos o ponteiro que aponta pro vetor que vamos trabalhar, e o tamanho desse vetor.

É importante que a gente receba o ponteiro que aponta para o vetor, pois quando a gente trabalha com vetors dinâmicas a gente não tem acesso o vetor em si, a gente só tem acesso ao ponteiro que aponta para o vetor. Ou seja, precisamos realizar uma passagem por ponteiro.

Lembre-se que passagens por ponteiro alteram diretamente no local de memória, ou seja, não vamos precisar retornar nenhum valor, pois o vetor dinâmico já está sendo alterado.

Agora que estamos dentro da função, podemos trabalhar com o vetor dinâmico normalmente, usando os colchetes. Vamos usar um f o r que acessa todas as posições do vetor, e com o c o u t e c i n vamos solicitar que o usuário preencha o vetor

Passo 3

O próximo passo é construir uma função capaz de imprimir um vetor dinâmico. Para criar uma função que recebe um vetor dinâmico, devemos receber um ponteiro que aponta para o local dinamicamente alocado!

Vamos criar a função i m p r i m e V e t o r que recebe o ponteiro que aponta para um vetor e o tamanho do vetor a ser impresso:

Depois de receber o ponteiro que aponta para o vetor dinâmico, podemos trabar com o vetor dinâmico normalmente. Com um loop f o r acessamos os elementos do vetor e imprimimos com o c o u t

Passo 4

As funções estão construídas, agora vamos pra nossa m a i n (   ) .

Primeiro de tudo, a questão pede que a gente receba um valor n do usuário e crie um vetor dinâmico com n   posições. Então vamos precisar declarar uma variável inteira n para receber o valor do usuário, e um ponteiro para f l o a t s chamado v e t o r D i n a m i c o que usaremos para apontar para a memória alocada dinamicamente.

Em seguida, vamos receber do usuário o tamanho do vetor que vamos criar:

Passo 5

Agora vamos criar o vetor dinâmico.

Para realizar alocação dinâmica de um vetor nós utilizamos o operador n e w para alocar memória de um tipo pré-derterminado e entre colchetes informamos a quantidade de espaços de memória que devem ser alocados. O resultado do processo de alocação deve ser armazenado em um ponteiro.

p t r = n e w   t i p o   [   t a m a n h o   ]

No nosso programa vamos utilizar o operador n e w para alocar memória do tipo f l o a t , e entre os colchetes vamos informar que queremos que sejam alocados n espaços. O endereço dessa alocação deve ser armazenado no ponteiro v e t o r D i n a m i c o :

Passo 6

Agora que já temos o nosso array dinâmico, só precisamos utilizar as funções que já desenvolvemos.

Primeiro vamos preencher o vetor usando a função p r e e n c h e V e t o r

Em seguida vamos exibir o seu conteúdo com a função i m p r i m e V e t o r

Passo 7

E esse é um exercício de alocação dinâmica de memória. Então você nunca pode esquecer que a memória deve ser liberada!

Para liberar memória é só a gente aplicar o d e l e t e   [   ] no ponteiro que aponta pro vetor alocado dinamicamente

E prontinho! Finalizamos a questão!

Resposta

Exercício Resolvido #5

Em C++ os arrays são estáticos e depois de criados não podem ser ampliados.

Porém, é possível “ampliar” um array dinâmico seguindo os seguintes passos:

  1. Crie um novo array dinâmico com um espaço a mais.
  2. Copie os valores do antigo array para o novo.
  3. Na última posição do novo array, guarde o novo elemento.
  4. Apague o array antigo.

Crie um programa que tenha a função a d i c i o n a r E l e m e n t o que adiciona um novo elemento na última posição de uma array de inteiros.

Dica: Crie uma função auxiliares que realizem: a cópia dos elementos entre dois arrays dinâmicos, que receba os valores de uma array do usuário, e que imprima a array.

Passo 1

Vamos lá pessoal. Essa questão é um pouquinho mais cabeluda, mas com calma a gente vai fazê-la com tranquilidade.

O objetivo é criar uma função que amplie uma array. A vantagem é que a questão já explicou os passos que temos que seguir, basicamente vamos fazer uma cópia da array antiga em uma array nova com mais espaço.

Vamos iniciar com o cabeçalho do código:

Passo 2

Vamos começar criando algumas funções auxiliares.

A primeira função auxiliar que vamos precisar é uma que imprima os valores contidos no vetor dinâmico. Então vamos criar a função i m p r i m e A r r a y .

Lembre-se que a gente não tem acesso a array, mas sim a um ponteiro que aponta para essa array. Assim, a função i m p r i m e A r r a y vai receber como parâmetro o ponteiro * a r r a y que aponta para a memória alocada dinamicamente. Vamos precisar também de um parâmetro que contenha o tamanho da array que vamos chamar de t a m a n h o , para que possamos imprimi-la corretamente:

v o i d   i m p r i m e A r r a y ( i n t   * a r r a y ,   i n t   t a m a n h o )

Dentro da função, vamos usar um loop f o r para iterar sobre os elementos da array e com o c o u t vamos imprimir cada um dos elementos.

Passo 3

A segunda função auxiliar que vamos precisar é uma função que preencha o vetor com valores inseridos pelo usuário. Essa função vai ser chamada p r e e n c h e A r r a y .

A função p r e e n c h e A r r a y vai precisar acessar e modificar os valores contidos no vetor dinâmico, o que vai ser fácil de resolver pois uma array dinâmica sempre é passada por ponteiro. Então o primeiro parâmetro da função é um ponteiro que aponta pra memória alocada dinamicamente chamado * a r r a y . Vamos precisar também de um parâmetro inteiro que represente o tamanho da array que vamos chamar de t a m a n h o , para que possamos imprimi-la corretamente:

v o i d   p r e e n c h e A r r a y ( i n t   * a r r a y ,   i n t   t a m a n h o )

Para efetuar o preenchimento da array vamos utilizar um loop f o r para acessar cada um dos elementos da array e usando c o u t e c i n podemos guardar o valor inserido pelo usuário na posição adequada.

Passo 4

Vamos desenvolver agora a terceira função auxiliar. Vamos criar uma função que copia todos os dados de uma array para outra.

Pra essa função funcionar vamos precisar de três parâmetros. Primeiro é necessário receber a array atual, e segundo vamos precisar receber a nova array para onde os valores serão copiados, e terceiro é preciso conhecer o tamanho da array atual, para podermos executar um loop sobre a array atual.

v o i d   c o p i a r A r r a y ( i n t   * a r r a y ,   i n t   * n o v o A r r a y ,   i n t   t a m a n h o )

O algoritmo da função de cópia consiste em usar um loop para acessar cada um dos elementos da a r r a y e copiar esse elemento para a mesma posição na n o v a A r r a y :

Passo 5

Com todas as funções auxiliares prontas, podemos nos dedicar a função mais importante do programa: executar a ampliação de uma array.

Vamos construir a declaração da função.

A função vai se chamar a d i c i o n a r E l e m e n t o , que vai efetuar a cópia de uma array e retornar o endereço de memória de uma nova array dinâmica. Ou seja, essa função vai retornar um ponteiro, e por isso deve ser do tipo i n t * . O primeiro parâmetro é o valor do elemento a ser adicionado. O segundo parâmetro é o endereço de memória da array dinâmica que vai ser ampliada. E o terceiro parâmetro é o tamanho da array e vai ser passado por referência para que a gente possa atualizar o valor do tamanho da array.

i n t   *   a d i c i o n a r E l e m e n t o ( i n t   e l e m e n t o ,   i n t   * a r r a y ,   i n t   &   t a m a n h o )

Vamos passo a passo construir o algoritmo da função. O primeiro passo é alocar dinamicamente uma nova array dinâmica, com o detalhe de que o tamanho deve ser um espaço maior.

Em seguida, vamos copiar os valores da array atual para a nova array utilizando a função c o p i a r A r r a y que nós criamos anteriormente.

Agora vamos acessar o último elemento da nova array e guardar o conteúdo de e l e m e n t o na nova array.

Pronto. Agora não precisamos mais da array antiga, e podemos deletá-la:

E para que a gente possa continuar sabendo o tamanho da array, vamos atualizar a variável t a m a n h o

E para finalizar a função, vamos retornar o endereço de memória da array expandida.

Passo 6

Show de bola. Agora vamos criar uma m a i n (   ) que faça uso das funções que criamos.

Pra começar, vamos precisar de um ponteiro do tipo inteiro que vai conter o endereço da array dinâmica. Também vamos precisar declarar uma variável que receba contenha o tamanho da array, e uma variável em que o usuário possa inserir o novo elemento da array.

Vamos pedir pro usuário inserir o tamanho que ele deseja para a array

E com isso poderemos utilizar o operador n e w para criar um novo vetor dinâmico do tipo inteiro.

Usando a função p r e e n c h e A r r a y vamos pedir pro usuário colocar valores na array criada.

E agora vamos efetuar a ampliação da array. Primeiro vamos pedir pro usuário inserir o valor do novo elemento que vai ser adicionado na array. Em seguida, na linha 60, usamos a função a d i c i o n a r E l e m e n t o para efetuar o processo de ampliação. Note que o resultado vai ser guardado dentro do mesmo ponteiro.

Agora que a array foi ampliada, podemos imprimir o seu conteúdo utilizando a função i m p r i m e A r r a y .

Passo 7

Antes de finalizar a questão, não podemos esquecer de deletar o array dinâmico. A array velha foi deletada dentro da função p r e e n c h e A r r a y , porém temos que deletar a nova array que foi criada.

O endereço dessa nova array esta contido no ponteiro a r r a y . Então vamos usar o operador d e l e t e   [   ] para liberar a memória:

E prontinho! Acabou o exercício.

Resposta

Exercício Resolvido #6

Escreva um programa que leia primeiro os 6 números gerados pela loteria e depois os 6 números do seu bilhete. O programa então compara quantos números o jogador acertou. Em seguida, ele aloca espaço para um vetor de tamanho igual a quantidade de números corretos e guarda os números corretos nesse vetor. Finalmente, o programa exibe os números sorteados e os seus números corretos.

Passo 1

Vambora!

A questão quer que a gente receba dois arrays do usuário, e depois aloque um array dinâmico que contenha a os números que pertencem às duas arrays originais. Então a gente vai precisar realizar loops para preencher as arrays, e um loop que vai procurar os números iguais nas duas arrays.

Então vamos começar declarando as variáveis necessárias. Primeiro uma array de inteiros chamada n u m S o r t e a d o s que vai conter os seis números da loteria. Depois uma outra array de inteiros chamada n u m A p o s t a d o s que vai conter os seis números que o usuário escolheu.

Para criar uma array dinâmica, a gente precisa saber quantos números o usuário acertou, então vamos criar uma variável inteira chamada q t d A c e r t o s que vamos usar pra contar a quantidade de acertos do usuário. O endereço de memória do array dinâmico precisa ser armazenado em um ponteiro, que vamos chamar de n u m A c e r t a d o s . E, por último, vamos precisar de duas variáveis i e j que vamos usar para criar os loops!

Passo 2

Primeiro de tudo, vamos perguntar pro usuário quais foram os números sorteados na loteria. Ou seja, vamos pedir pra ele preencher a array n u m S o r t e a d o .

Pra isso vamos criar um loop de seis voltas, que a cada iteração vai pedir pro usuário inserir um número, e armazenar o valor digitado na posição correspondente da array.

E em seguida, vamos fazer o mesmo processo para preencher o array que contém os números que o usuário escolheu:

Passo 3

Certo, agora vamos pra uma parte mais complicadinha da questão. Vamos precisar contabilizar a quantidade de acertos do usuário. Pra isso vai ser necessário um loop aninhado e uma estrutura condicional.

O primeiro loop vai percorrer os seis valores da array n u m A p o s t a d o s , dentro desse loop vamos criar um segundo loop que percorre os seis valores da array n u m S o r t e a d o .

Dentro do loop vamos estabelecer uma condição de que se o número apostado atual, for igual ao número sorteado atual, então a gente aumenta o valor da variável q t d A c e r t o s .

Uma coisa interessante de se lembrar é que numa loteria não é possível que o mesmo número seja sorteado ou apostado duas vezes! Então podemos usar o comando b r e a k para interromper o loop de números sorteados, e partir para o próximo número apostado!

Passo 4

Prontinho! Agora que já temos a quantidade de acertos, podemos criar o nosso array dinâmico com o tamanho adequado!

Vamos usar o operador n e w   [   ] para iniciar um array de inteiros com o tamanho da variável q t d A c e r t o s

Pronto! Agora vamos poder utilizar o ponteiro n u m A c e r t a d o s para acessar os endereços do array alocado dinamicamente!

Passo 5

Agora precisamos preencher o array dinâmico com os números acertados pelo usuário.

Pra isso vamos usar novamente a mesma estrutura de loops aninhados com estrutura condicional.

O primeiro loop vai percorrer os seis valores da array n u m A p o s t a d o s , dentro desse loop vamos criar um segundo loop que percorre os seis valores da array n u m S o r t e a d o .

Só que dessa vez, se o número apostado atual, for igual ao número sorteado atual, então a gente vai armazenar esse valor na posição i do array dinâmico n u m A c e r t a d o s !

Passo 6

Agora só precisamos imprimir os números contidos no array dinâmico!

Pra isso é só a gente criar um loop que vai iniciar em zero e avançar até o número q t d A c e r t o s de um em um. E a cada iteração vai exibir o conteúdo da posição i do array dinâmico.

Passo 7

Estamos quase acabando. Mas antes de finalizar a questão, temos que lembrar que sempre que usamos alocação dinâmica, temos que liberar a memória!

Então vamos utilizar o operador d e l e t e   [   ] para apagar o array alocado dinamicamente

E finalizamos a questão!

Resposta

Exercício Resolvido #7

Utilize um ponteiro duplo para alocar dinamicamente uma matriz com números reais. Os valores de linhas e colunas são obtidos do usuário. Preencha todos os elementos da matriz com 0 e exiba a matriz.

Passo 1

Vamos nessa!

Pessoal, criar uma matriz dinâmica com C++ é uma tarefa um pouco mais complicada. Se você simplesmente tentar usar o operador new com duas chaves, vamos obter um erro:

O que vamos precisar fazer é usar o operador n e w várias vezes consecutivas. A primeira utilização vai criar as linhas da matriz. Depois, dentro de cada linha vamos criar as colunas da matriz.

Passo 2

Vamos começar. Primeiro de tudo, vamos precisar de três variáveis.

Vamos precisar de duas variáveis inteiras para armazenar a quantidade de linhas e colunas.

E também vamos precisar de um ponteiro duplo que vai armazenar o endereço de memória da matriz dinâmica.

E em seguida, vamos precisar receber do usuário a quantidade de linhas e colunas da matriz

Passo 3

Beleza, agora vamos pro coração da questão.

O que vamos fazer aqui é um uso inteligente dos ponteiro. Primeiro, pegar o ponteiro duplo p n t M a t r i z e alocar um “array de ponteiros”. E depois, vamos usar cada um dos ponteiros alocados dinamicamente, e usar esses ponteiros para alocar espaços na memória. O efeito disso será uma matriz.

Primeiro, vamos iniciar as colunas da nossa matriz. Para isso vamos usar o operador n e w     . Uma coisa que você deve notar é que p n t M a t r i z é um ponteiro

E depois vamos acessar cada uma das linhas, e em cada uma delas vamos inicializar a quantidade de colunas:

Na prática, o que fazemos na linha 14 é criar uma “array de ponteiros”. E depois no loop, acessamos cada um dos ponteiros e alocamos um array de f l o a t s . O resultado é que temos uma quantidade l i n h a s de arrays dinâmicos, e cada um desses arrays dinâmicos possui uma quantidade c o l u n a s de espaços.

Por exemplo, se o usuário digitar uma quantidade de 4 linhas, e 5 colunas, vamos ter a seguinte organização na memória:

Passo 4

Prontinho! Nossa matriz dinâmica foi alocada! E pra usar ela é só a gente utilizar as duplas chaves para acessar cada elemento, assim como faríamos com as matrizes que estamos acostumados:

p n t M a t r i z   i n d i c e L i n h a i n d i c e C o l u n a

Então vamos preencher todos os elementos com zeros. Pra isso vamos utilizar um loop aninhado para acessar todas as linhas e colunas.

Faremos um loop externo que vai percorrer as linhas da matriz, e um loop interno que percorre as colunas de cada linha. E para cada posição da matriz vamos preencher com zero:

Passo 5

E agora vamos exibir a matriz!

Vamos fazer um outro loop aninhado igualzinho ao anterior. Mas dessa vez, ao invés de alterar o conteúdo da matriz, vamos exibir o conteúdo.

Faremos um loop externo que vai percorrer as linhas da matriz, e um loop interno que percorre as colunas de cada linha. Um detalhe a mais é que, após terminar o último elemento de uma linha, vamos imprimir um e n d l para saltar uma linha

Passo 6

E antes de finalizar a questão, precisamos liberar a memória alocada dinamicamente.

Perceba o seguinte: se foi necessário usar um loop para alocar a memória, então vai ser preciso um loop para liberar a memória também!

Vamos acessar cada uma das linhas da matriz, e liberar o vetor dinâmico existente nesta coluna.

Na prática, o que estamos fazendo é acessando cada um dos ponteiros da “array de ponteiro” e liberando a memória apontada por estes ponteiros.

E antes de finalizar totalmente a questão, lembre-se que a “array de ponteiros” foi alocada dinamicamente também. Então é necessário liberá-la:

E prontinho! Questão concluída.

Resposta

Exercício Resolvido #8

Construa uma função que aloque uma matriz n × m e retorne o ponteiro duplo dessa matriz. Crie uma segunda função que recebe o ponteiro e dimensão de uma matriz e efetue a liberação de memória.

Passo 1

Essa questão está pedindo pra gente criar funções que facilitem a criação e liberação de matrizes dinâmicas.

Pra começar, vamos escrever uma função chamada a l o c a M a t r i z .

Essa função vai receber como parâmetro as dimensões da matriz, e vai retornar um ponteiro para o endereço da matriz. Uma matriz é alocado com um ponteiro duplo para float, então tipo da função será f l o a t * * .

f l o a t * * a l o c a M a t r i z ( i n t   n ,   i n t   m )

Para criar uma matriz dinamicamente nós precisamos de um ponteiro duplo. Vamos então criar um ponteiro duplo chamado p n t M a t r i z :

O primeiro passo para criar um ponteiro dinâmico é inicializar as linhas dessa matriz. Em termos técnicos, o que estamos fazendo é inicializando uma array dinâmica de ponteiros. Para criar uma array dinâmica de ponteiros nós usamos o operador new junto com o tipo e o operador * , e armazenamos o resultado em um ponteiro duplo.

Para criar uma array de ponteiros fazemos:

p n t D u p l o = n e w   t i p o * [ t a m a n h o ]

No código, vamos alocar n ponteiros dinâmicos:

Ok. Depois que temos uma array dinâmica de ponteiros, podemos acessar cada um dos ponteiros, e fazer com que cada um deles aponte para um novo espaço alocado dinamicamente.

Pra isso, a gente pode usar um loop que vai acessar cada um dos elementos da array dinâmica de ponteiros, e para cada um dos ponteiros a gente utiliza novamente o operador n e w e aloca um novo espaço dinâmico com m espaços.

E prontinho. A matriz está alocada dinamicamente.

Agora, para concluir essa função, vamos retornar o ponteiro duplo.

Passo 2

Mas se temos uma função para alocar uma memória dinamicamente, então vamos precisar de uma função para liberar essa memória!

Essa função não precisa retornar nada. Tudo que ela precisa fazer é receber o ponteiro da matriz dinâmica e deletar os espaços alocados dinamicamente.

O detalhe, é que vai ser necessário criar um loop para acessar todas as linhas da matriz. Então também vamos precisar receber as dimensões da matriz.

Assim, vamos criar uma função chamada l i b e r a M a t r i z , do tipo v o i d (pois não precisa retornar nada) e que recebe como parâmetro o ponteiro duplo que aponta pra matriz dinâmica, e as dimensões dessa matriz.

E agora precisamos liberar a memória. Quando alocamos, nós utilizamos um loop que acessava todas as linhas e alocava a memória. Agora usaremos o mesmo loop novamente, mas dessa vez vamos utilizar o operador d e l e t e     para liberar cada uma das colunas de cada linha.

E antes de finalizar a função, também precisamos liberar a array dinâmica de ponteiros.

E prontinho! Concluímos a segunda função, e terminamos a questão!

Resposta