Gabarito da Lista 5
Enunciado:
(a) -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.(b) Enunciado
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" */
}
Enunciado:
Fizemos a função StrCpy(). Faça uma função StrLen() e StrCat() que funcionem como as funções strlen() e strcat() de string.h, respectivamente.Solução:
/* Exemplo de funcao StrLen ---------------------------- */
#include <stdio.h>StrLen (char *str)
{
int tamanho = 0;
while (*str)
{
tamanho++;
str++;
}
return tamanho;
}main ()
{
int t;
char str1[100];
printf ("\n\nEntre com uma string: \n");
gets (str1);
t = StrLen(str1);
printf ("\n Voce digitou \n%s\ncom %d letras.",str1,t);
}Comentários:
A função StrLen percorre o vetor procurando o seu fim. A cada iteração que o fim do vetor não é encontrado, a variável tamanho é incrementada. Quando o fim é encontrado, a variável tamanho possui o número de iterações usadas até chegar ao fim, ou seja, o tamanho da string./* Exemplo de funcao StrCat --------------------------- */
#include <stdio.h>
#include <string.h>StrCat (char *primeira, char *segunda)
{
char *p;
/* --->p aponta para o final da primeira string */
p = primeira+strlen(primeira);
while (*segunda)
{
*p = *segunda;
p++;
segunda++;
}
*p = '\0';
}int main ()
{
char str1[100], str2[1003], str3[200];
printf ("\n\nEntre com uma string: \n");
gets (str1);
printf ("\n\nEntre com uma string: \n");
gets (str2);
str3[0] = '\0';
StrCat(str3, str1);
StrCat(str3, str2);
printf ("\n Voce digitou \n%s",str3);
return(0);
}Comentários:
O vetor p é apontado para o final da primeira string.Em seguida, cada posição da segunda string é copiada para o endereço p, que por sua vez é incrementado a cada iteração. Desta forma, a segunda string é copiada para o final da primeira, e a primeira se torna uma string maior, com o conteúdo das duas strings.
Enunciado:
Escreva a função int strend(char *s, char *t) que retorna 1 (um) se a cadeia de caracteres 't' ocorrer no final da cadeia 's', e 0 (zero) caso contrário.Solução:
/* Exemplo de funcao strend ---------------- */
#include <stdio.h>
#include <string.h>strend (char *str, char *t)
{
char *p;
p = str + strlen(str) - strlen(t); /* p aponta para o final da string str - tamanho de t */
while (*t)
{
if (*p != *t) return 0;
p++;
t++;
}
return 1;
}int main ()
{
char str[100], t[20];
printf ("\n\nEntre com uma string: \n");
gets (str);
printf ("\n\nEntre com a expressao de teste:\n");
gets (t);
if (strend(str, t))
printf ("\n A expressao ocorre no final da frase.\n");
else printf ("\n A expressao NAO ocorre no final da frase.\n");
return(0);
}Comentários:
Primeiro, o apontador p é apontado para uma posição que será o final da primeira string subtraído do tamanho da string t. A partir daí, cada posição é comparada, até o final da string t. Se ocorrer alguma posição diferente, a função retorna um 0 imediatamente, sem comparar o restante. Caso a função termine o loop, significa que o trecho é realmente igual e a função retorna o flag 1.
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);
Enunciado:
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 100main ()
{
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.
Exercício 1:
Aprendemos, pelo curso, que o 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.
Exercício 2:
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(void) /* 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(void) /* 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;
Curso de C do CPDEE/UFMG - 1996-1999