Fonte: Núcleo de Ensino à Distância da UFMG

http://www.ead.cpdee.ufmg.br/

Resposta da lista de exercícios sobre ponteiros

1. Explique a diferença entre
p++; (*p)++; *(p++);
-O que quer dizer *(p+10);?
-Explique o que você entendeu da comparação entre ponteiros.


Solução:
- p++: incrementa o ponteiro, ou seja o endereço. Após esta instrução, o
ponteiro p passará a apontar para a posição de memória imediatamente superior.
Se em um vetor, o ponteiro passará a apontar a próxima posição do vetor.
- (*p)++: Incrementa o conteúdo apontado por p, ou seja, o valor armazenado na
variável para qual p está apontando.
- *(p++): Incrementa p (como em p++) e acessa o valor encontrado na nova
posição. Se em um vetor, esta expressão acessa o valor da posição imediatamente
superior a armazenada em p antes do incremento.
- *(p+10) Acessa o valor encontrado 10 posições a frente de p. Neste caso, o
apontador não é incrementado. Se em um vetor, irá acessar a décima posição após
a que está sendo apontada.
- Dois ponteiros, como outras variaveis, podem ser comparados. Podemos verificar
por exemplo se dois ponteiros apontam para a mesma posição de memória
verificando se p1 == p2 ou se p1 != p2
Podemos comparar se um ponteiro e 'menor' ou 'maior' que outro, ou melhor, se
aponta para uma posição superior a de outro.


2. Qual o valor de y no final do programa? Tente primeiro descobrir e depois verifique no computador o resultado. A seguir, escreva um /* comentário */ em cada comando de atribuição explicando o que ele faz e o valor da variável à esquerda do '=' após sua execução.
int main()
{
int y, *p, x;
y = 0;
p = &y;
x = *p;
x = 4;
(*p)++;
x--;
(*p) += x;
printf ("y = %d\n", y);
return(0);
}

Solução:
O valor de y é 4, e o programa comentado fica:
int main()
{
int y, *p, x;
y = 0; /* atribui o valor 0 a y => y=0 */
p = &y; /* atribui o endereco de y ao ponteiro p
p contem o endereco de y (ex:DS:FFF4)*/
x = *p; /* atribui o conteudo de onde p aponta
(valor de y) para x, que passa a valer 0 */
x = 4; /* atribui 4 a x */
(*p)++; /* incrementa de 1 o conteudo de onde p aponta,
alterando o valor de y para 1 */
x--; /* decrementa 1 de x => x = 3 */
(*p) += x; /* adiciona x ao conteudo de onde p aponta,
alterando o valor de y para 4 */
printf ("y = %d\n", y); /* imprime "y = 4" */
}

3. Verifique o programa abaixo. Encontre o seu erro e corrija-o para que escreva o numero 10 na tela.
#include <stdio.h>
int main()
{
int x, *p, **q;
p = &x;
q = &p;
x = 10;
printf("\n%d\n", &q);
return(0);
}

Solução:
O programa contém um erro na linha do printf, onde ele manda imprimir o endereço
de q (&q). Na realidade, para se imprimir o valor 10 (valor de x) deve-se
imprimir o valor apontado pelo valor apontado por q. Veja o esquema:
x = 10;
p aponta para x;

q aponta para p;

==> *q é igual a p ; como *p é igual a x, basta escrever *(*q) para se ter x.
Logo, o printf ficaria:
printf("\n%d\n", **q);

 

4. Escreva um programa que declare uma matriz 100x100 de inteiros. Você deve inicializar a matriz com zeros usando ponteiros. Preencha depois a matriz com os números de 1 a 10.000 usando ponteiros.


Solução:
/* Problema das matrizes ---------------- */
#include <stdio.h>
#define N 100
main ()
{
int mat[N][N];
int *p;
int i, j, soma = 0;
p = &mat[0][0]; /* Inicializa o ponteiro no inicio da matriz */
/* Inicializando a matriz com zeros.. */
for (i=0; i<N; i++)
for (j=0; j<N; j++)
{
*p = 0;
p++;
}
/* Preenchendo a matriz com numeros */
p = &mat[0][0];
for (i=0; i<N; i++)
for (j=0; j<N; j++)
{
*p = soma;
soma++;
p++;
}
}

Comentários:
Pode parecer um pouco inútil este tipo de exercício, mas apesar de não se ter um
objetivo claro (uma resposta na tela) ele é útil para desenvolver a capacidade
do aluno de trabalhar e resolver problemas usando ponteiros. O exercício aponta
o ponteiro p para o início da matriz e percorre toda ela preenchendo-a com
zeros. Em seguida, p é novamente apontado para o início (se não fizer isto, não
funciona) da matriz e faz-se então o preenchimento da matriz com os números,
usando-se uma variável auxiliar.

5. Sabendo-se que valor de uma variável ou expressão do tipo vetor é o endereço do elemento zero do vetor. Seja a[] um vetor qualquer, independente de tipo e tamanho, e pa um ponteiro para o mesmo tipo de a[]. Responda V ou F, justificando:

(V) Após a atribuição pa=&a[0]; pa e a possuem valores idênticos, isto é,
apontam para o mesmo endereço
(V) A atribuição pa=&a[0]; pode ser escrita como pa=a;
(V) a[i] pode ser escrito como *(a+i)
(V) &a[i] e a+i são idênticos
(V) a+i e' o endereço do i-ésimo elemento após a
(V) pa[i] e' idêntico a *(pa+i)
(V) pa=a e' uma operação valida
(V) pa++ e' uma operação valida
(F) a=pa e' uma operação valida ==> Um vetor não pode ter seu endereço
modificado
(F) a++ e' uma operação valida ==> Um vetor não pode ter seu endereço
modificado

Comentários:
- Se pa aponta para um elemento particular de um vetor, então, por definição,
pa+1 aponta para o próximo elemento, pa+i aponta para i elementos após pa e pa-i
aponta para i elementos antes de pa. Assim, se pa aponta para a[0], *(pa+1)
refere-se ao conteudo de a[1], pa+i é o endereço de a[i] e *(pa+i) é o conteúdo
de a[i].
- Estas observações aplicam-se independentemente do tipo ou tamanho das
variáveis no vetor a.
- A correspondência entre indexação e aritmética com ponteiros é evidentemente
muito estreita. Por definição, o valor de uma variável ou expressão do tipo
vetor é o endereço do elemento zero do vetor. Assim, após a atribuição pa=&a[0];
pa e a possuem valores idênticos. Como o nome de um vetor é sinônimo para o
local do elemento inicial, a atribuicao pa=&a[0] também pode ser escrita como
pa=a;
- a[i] pode ser escrita como *(a+i). Na avaliação de a[i], o C a converte para
*(a+i) imediatamente; as duas formas são equivalentes. Aplicando-se o operador &
a ambas as partes dessa equivalência, segue-se que &a[i] e a+i também são
idênticos: a+i é o endereço do i-esimo elemento após a. Por outro lado, se pa é
um apontador, expressões podem usá-lo como um subscrito; pa[i] é idêntico a
*(pa+i). Em suma, qualquer expressão de vetor e indice é equivalente a uma
escrita com um apontador e um deslocamento.
- Existe uma diferença importante entre o nome de um vetor e um apontador que
deve ser sempre lembrada: um apontador é uma variavel, de forma que pa=a e pa++
são operações válidas. Mas o nome de um vetor não é uma variável (poderia ser
visto como um ponteiro constante, mas não uma variável); construções como a=pa e
a++ são ilegais.

6. O que está errado com os programas abaixos? Descubra e indique a solução para consertá-los. Execute-o no computador para ver se o erro foi resolvido.
a)
void main() /* esse programa esta errado */
{
int x, *p;
x = 10;
*p = x;
}
Obs: por se tratar de um programa muito pequeno, talvez a execução deste não
mostrará de imediato o erro. Mas ele existe e é sério.

Solução:
Este programa atribui o valor 10 a alguma posição de memoria desconhecida. O
ponteiro p nunca recebeu um valor; portanto, ele contém lixo. Esse tipo de
problema sempre passa despercebido, quando o programa é pequeno, porque as
probabilidades estão a favor de que p contenha um endereço "seguro" - um
endereço que não esteja em seu código, área de dados ou sistema operacional.
Contudo, a medida que seu programa cresce, a probabilidade de p apontar para
algo vital aumenta. Eventualmente, seu programa pára de funcionar. A solução é
sempre ter certeza de que um ponteiro está apontando para algo válido antes de
usá-lo.


b)
void main() /* esse programa esta errado */
{
int x, *p;
x = 10;
p = x;
printf ("%d", *p);
}

Solução comentada:
- O erro aqui apresentado é provocado por um simples equívoco sobre como usar um
ponteiro. A chamada de printf() não imprime o valor de x, que é 10. Imprime um
valor desconhecido porque a atribuicao p=x; está errada. Esse comando atribui o
valor 10 ao ponteiro p, que se supõe conter um endereço, não um valor. Para
corrigí-lo, basta escrever p=&x;