Suponha a seguinte declaração

int v[5] = {10, 20, 30, 40, 50}; /* Vetor com 5 inteiros*/

int *pv;/* Ponteiro para inteiro*/

int **ppv;/* Ponteiro para Ponteiro para inteiro*/

  1. Qual o conjunto de instruções que você escreveria, de tal modo que as três variáveis ficassem, de alguma forma, relacionadas entre si?
  2. Represente, em um esquema de memória, qual o estado em que ficou a memória depois de executadas as instruções do item (a), supondo que a dimensão de todos os tipos envolvidos é de um byte. Dê valores que ache apropriados aos endereços de todas as variáveis envolvidas.
  3. Quais os parâmetros que se deve colocar em cada printf de tal forma que se obtenha a seguinte saída, sendo o primeiro parâmetro definido com base em v, o segundo com base em pv e o terceiro com base em ppv?
  4. printf(“%d %d %d\n”, ,,);101010

    printf(“%d %d %d\n”, ,,);202020

    printf(“%d %d %d\n”, ,,);304050

    printf(“%d %d %d\n”, ,,);91929

  5. Qual a saída da seguinte instrução?

printf(“\n%d %d %d”, &v[0], &pv, &ppv);

Passo 1

Fala aí! Essa aqui é bem conceitual, pra testar se estamos dominando o tópico de ponteiros. Bora começar, então.

Repare que o enunciado já nos deu algumas dicas na declaração das variáveis, por exemplo, ao dizer que *pv é um ponteiro para inteiro, quer dizer que é uma variável que aponta para uma outra variável do tipo inteiro. Assim, podemos relacionar esse cara por meio da seguinte instrução:

Similarmente, no caso de *ppv, temos um ponteiro para ponteiro para inteiro, o que quer dizer que este cara aponta para um ponteiro que aponta para um inteiro, sacou? A diferença é que, neste caso, precisamos usar o operador & (endereço de), para indicar que ppv aponta para o endereço de pv, da seguinte forma:

Passo 2

Beleza, essa aqui é um pouquinha abstrata, pois podemos representar esse esquema de memória de várias formas, a única exigência de fato é que todos os elementos do vetor fiquem em endereços sequenciais de memória. Uma possível representação é a seguinte:

Repare como os elementos de v estão em posições contíguas de memória, pv aponta para o endereço de v[0] e ppv para o de pv.

Passo 3

Para resolver a próxima, vamos buscar nossos conhecimentos de operadores e operações com vetores. Vamos sempre manter em mente que o primeiro parâmetro deve ser passado com base em v, o segundo em pv e o terceiro em ppv, como nos foi dito pelo enunciado. Dá só uma olha em como fica o primeiro:

Se liga, neste primeiro caso, todas as saídas devem ser iguais a 10. Ora, 10 é o valor do primeiro elemento de v, por isso passamos v[0] como parâmetro. Da mesma forma, como pv aponta para v e ppv aponta para pv, basta utilizarmos o operador * (apontado por). Se ficar alguma dúvida, tente olhar para o esquema de memória que fizemos no passo anterior para ajudar na visualização.

Seguindo em frente, os próximos seguirão a mesma linha de raciocínio. Olha só:

O primeiro parâmetro é bem simples, né? Basta apontarmos para o índice daquele elemento do vetor. Agora, para os demais, teremos que fazer algumas operações. Se liga, para o segundo parâmetro, como pv aponta para v[0], basta somarmos uma unidade antes de apontar. E o mesmo ocorre para o último parâmetro, mas neste caso, ao fazermos *ppv + 1, apontamos para pv + 1 e só depois aplicamos o segundo operador * do lado de fora dos parênteses. O posicionamento dos parênteses com ponteiros é extremamente importante, se escrevêssemos, por exemplo, *pv + 1, estaríamos apontando para v[0] e somando ao seu valor uma unidade, ou seja, a saída seria 11!

O próximo tem exatamente a mesma ideia do anterior:

Simplesmente utilizamos as operações de soma para chegarmos ao índice em que se encontra o valor desejado.

O próximo vai ser um pouquinho diferente, se liga:

O que acontece aqui é que os valores de saída desejados não fazem parte do vetor v, por isso, agora vamos ter que realizar algumas operações dessa vez fora dos parênteses. No primeiro parâmetro, basta apontarmos para o primeiro elemento (10) e dele subtrairmos uma unidade, chegando em 9. Para o segundo, apontamos para o segundo elemento escrevendo *(pv + 1), obtemos como resultado 20, e subtraímos uma unidade. Por fim, no terceiro parâmetro podemos apontar novamente para o segundo elemento e adicionarmos 9 ao final, aí chegamos em 29; também poderíamos escrever *(ppv + 2) – 1 no terceiro parâmetro, o resultado seria exatamente o mesmo 😉

Passo 4

Depois de todos esses exemplos, esse aqui fica tranquilo, né? Vamos responder com base nos endereços que definimos lá no Passo 2, quando fizemos aquele esquema de memória. É importante ter isso em mente pois aqui nos é pedido para identificar o endereço de cada variável (representado pelo operador &), então, basta olharmos onde colocamos cada uma delas.

Se liga, o primeiro elemento de v, v[0], colocamos no endereço 100, pv colocamos em 500 e ppv em 700. Essa seria a saída do comando descrito:

100 500 700

Resposta

  1. 100 500700