Gabarito de Lista de Exercícios
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 afrente 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. Veja
o trecho de programa como exemplo:
p1 = &vet[0]; /* vet e um vetor de 100 posicoes; p1 aponta
para
o inicio de vet */
p2 = p1+50; /* p2 aponta para o meio de vet */
p3 = p1+100; /* p3 aponta para o fim de vet */
for(p=p1; p<p3; p++)
if(p>p2)
printf("\n\n Ultrapassamos o meio do vetor!");
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';
}
main ()
{
char str1[100], str2[100], 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);
}
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.
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);
while (*t)
{
if (*p != *t) return 0;
p++;
t++;
}
return 1;
}
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");
}
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.
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 matri */
/* 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.
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;
Exercício 3:
Qual o valor de y no final do programa? Tente primeiro descobrir
fazendo um teste de mesa 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 variavel à esquerda do '='
após sua execução.
Solução:
O valor de y é 4, e o programa comentado fica:
main()
{
int y, *p, x;
y = 0; /* inicializa y com
0 => 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" */
}
Exercício 4:
Verifique o programa abaixo. Encontre o seu erro e corrija-o para que
escreva o numero 10 na tela.
#include <stdio.h>
main()
{
int x, *p, **q;
p = &x;
q = &p;
x = 10;
printf("\n%d\n", &q);
}
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;
/* valor apontado por p: 10 */
/* conteudo de p: &x */
q aponta para p;
/* valor apontado por q: &x que e o conteudo do ponteiro p */
/* conteudo de q: &p */
Tente refletir nisto alguns isntantes... É meio complicado.
Exercício 5:
Reescreva o exemplo da página c510.html
alterando a forma de varrer o loop. Ao invés de você usar
os índices do array, você deverá usar um ponteiro e
ir incrementando o ponteiro para atingir cada posição.
Solução:
#include <stdio.h>
main ()
{
int num[100]; /* Declara um vetor de 100
posicoes */
int *p;
p = &num[0];
do {
printf ("\nEntre com um numero (-999 p/
terminar): ");
scanf ("%d",p);
p++;
} while (*(p-1)!=-999);
printf ("\n\n\n\t Os numeros que voce digitou foram:\n\n");
for (p=num; *p!=-999; p++)
printf (" %d\n",*p);
}
Exercicio 6:
Fazer um programa que implemente a multiplicação entre
duas matrizes (lista 4), armazenando o resultado
numa terceira matriz.A implementação deverá ser feita
usando-se a aritmética de ponteiros.
Solução:
/* Multiplicacao de Matrizes - versao 2.0 ---------- */
/* ------------------------------------------------- */
#include <stdio.h>
#define TAM 10
main()
{
int mat1[TAM][TAM], /* As matrizes */
mat2[TAM][TAM],
mat3[TAM][TAM];
int d1x, d1y,
d2x, d2y, /* As dimensoes das matrizes
*/
d3x, d3y;
int i, j, k; /* Contadores auxiliares */
int *p, *q; /* Apontadores auxiliares */
do
{
/* Leitura das dimensoes: */
printf("\nEntre com as dimensoes da primeira matriz: ");
scanf("%d%d", &d1x, &d1y);
printf("\nEntre com as dimensoes da segunda matriz: ");
scanf("%d%d", &d2x, &d2y);
}while (d1y != d2x);
/* Leitura das matrizes: */
printf("\n Matriz 1:\n");
for (i=0; i<d1x; i++)
{
p = &mat1[i][0];
for (j=0; j<d1y; j++)
{
printf("\nposicao (%d,%d): ", i, j);
scanf("%d",p);
p++;
}
}
printf("\n Matriz 2:\n");
for (i=0; i<d2x; i++)
{
p = &mat2[i][0];
for (j=0; j<d2y; j++)
{
printf("\nposicao (%d,%d): ", i, j);
scanf("%d",p);
p++;
}
}
/* Impressao das matrizes */
printf("\n\nPrimeira Matriz:");
for (i=0; i<d1x; i++)
{
p = &mat1[i][0];
printf("\n");
for (j=0; j<d1y; j++)
printf("\t%d", *p++);
}
printf("\n\nSegunda Matriz:");
for (i=0; i<d2x; i++)
{
p = &mat2[i][0];
printf("\n");
for (j=0; j<d2y; j++)
printf("\t%d", *p++);
}
/*zera a matriz produto */
d3x = d1x;
d3y = d2y;
for (i=0; i<d3x; i++)
{
p = &mat3[i][0];
for (j=0; j<d3y; j++)
{
*p = 0;
p++;
}
}
/* Calculo da matriz produto */
for (i=0; i<d3x; i++)
for (j=0; j<d3y; j++)
{
p = &mat1[i][0];
q = &mat2[0][j];
for (k=0; k<d2x; k++)
{
mat3[i][j] += (*p)*(*q);
p++;
q += TAM;
}
}
/* Imprime o resultado */
printf("\n\nMatriz Resultado:");
for (i=0; i<d3x; i++)
{
p = &mat3[i][0];
printf("\n");
for (j=0; j<d3y; j++)
printf("\t%d", *p++);
}
printf("\n");
}
Obs: O programa é praticamente 'impossível' de
ser entendido para alguém que não tenha a versão 1.0,
preparado para o exercício da aula passada. Caso você tenha
dificuldades de entendê-lo, procure o gabarito
da aula 4, e compare o exercício. Caso a dúvida persista,
comentaremos na lista.
Exercicio 7:
Refaçaa o programa que ordena um vetor de inteiros de N posições
(lista 4). Para isto você precisará
usar um loop. Verifique o número de iterações até
que o programa consiga finalmente ordenar o vetor (sugestões: use
valores superiores para N - 25 ou 35).
Solução:
/* Ordena vetores: Versao 2.0 --------------- */
/* ------------------------------------------ */
#include <stdio.h>
#define N 20
main()
{
int vet[N] = { 3, 5, 2, 9, 5, 7, 1, 3, 2, 0,
12, 13, 15, 6, 4, 2, 8, 7, 5, 4};
int i, *p, *fim, *menor, aux;
fim = &vet[N-1];
for (i=0; i<N; i++)
{
menor = p = &vet[i];
while(p<=fim)
{
if (*p < *menor)
menor = p;
p++;
}
aux = *menor;
*menor = vet[i];
vet[i] = aux;
}
printf("\n\nResultado:\n");
for (p=&vet[0]; p<=fim; p++)
printf("%d\n", *p);
}
Comentários:
Para uma melhor compreensão do programa, sugere-se que os alunos
desenvolvam o programa passo a passo, seguindo cada atribuição,
com o auxilio de lápis e papel. A idéia principal é
que o ponteiro menor aponte para a menor posição do
vetor. Troca-se então este valor pelo do início do vetor,
e uma nova busca é
feita no restante do vetor. O resultado é guardado na segunda
posição, e assim segue, até que todas as posições
estejam tomadas por valores, que serão então crescentes.
Exercicio 8:
Faça um programa que leia uma string do teclado. Em seguida
ele verifica se a string corresponde a um número (como "-987.234").
Se sim, o programa deverá calcular o valor que a string representa
(inlcusive negativo) e apresentá-lo na tela como float. Se não
(caso a string não seja correspondete a um número) o número
apresentado deverá ser zero. Utilize-se de ponteiros para percorrer
a string.
Obs: Sobre bibliotecas, para quem conhece outras bibliotecas que não estão sendo usadas com frequência no nosso curso: Você deverá fazer este exercício apenas com as bibliotecas stdio.h, string.h e ctype.h. As funções da biblioteca stdlib.h não deverão ser usadas.
Solução:
/* Conversao de string para float ---------- */
/* Versao 1.0 ------------------------------ */
#include <stdio.h>
#include <ctype.h>
main()
{
char buf[30], *p;
float res = 0;
int sinal = 1, pot;
printf("\n\nEntre com a string:\n");
scanf("%s", buf);
p = &buf[0];
/* Retira possiveis espacos no inicio da string */
while ( (!isdigit(*p)) && (*p != '\0') )
{
if (*p == '-')
sinal = -1;
p++;
}
/* Parte inteira */
for (res=0.0; isdigit(*p); p++)
res = 10.0 * res + (*p - '0');
if (*p == '.')
p++;
/* Parte decimal */
for (pot = 1.0; isdigit(*p); p++)
{
res = 10.0 * res + (*p - '0');
pot *= 10.0;
}
/* Apresentacao do resultado */
res = sinal*res/pot;
printf("\nVeja o resultado: %f\n",res);
}
Comentários:
- a partir do início da string, a função desconsidera
os brancos, examina o sinal + ou - (se existir); a seguir, espera por dígitos
e, enquanto estes ocorrerem,
vai fazendo o cálculo do valor numérico correspondente.
(ex: se for lido um '2' seguido de '8' e de '1', realiza o calculo ((2*10.)+8)*10.+1);
se então ocorrer um ponto decimal, este será pulado e
o valor numérico seguinte será calculado seguindo o mesmo
princípio anterior, a menos da potência, que vai sendo acumulada.
Ao final da rotina, o valor será multiplicado pelo sinal e dividido
pela potência obtida, chegando ao valor numérico correspondente
a string.
Exercicio 9:
Refaça o programa da página c530.html,
ordenando as strings lidas por tamanho (menores primeiro, maiores depois).
Use um vetor auxiliar com um ponteiro para cada string.
Solução:
/* Ordena Strings: Versao 2.0 --------------- */
/* ------------------------------------------ */
#include <stdio.h>
#include <string.h>
#define N 5
#define TAM 30
main()
{
char str[N][TAM];
char* ap[N];
int vet1[N], vet2[N];
int *fim, *menor, *q;
int i, j;
/* Leitura das strings: */
printf("\n\nEntre com %d Strings:\n", N);
for (i=0; i<N; i++)
{
scanf("%s",&str[i][0]);
vet1[i] = strlen(str[i]);
}
/* Ordena as strings propriamente */
fim = &vet1[N-1];
for (i=0; i<N; i++)
{
for(menor=q=&vet1[0]; q<=fim; q++)
if (*q < *menor)
menor = q;
j = menor-&vet1[i];
*menor = 50; /* Maior que o maximo...
*/
ap[i] = &str[i+j][0];
}
printf("\nConjunto de strings no final:\n");
for (i=0; i<N; i++)
printf("%s\n", ap[i]);
}
Comentários:
Este programa usa boa parte do exercício 2, na rotina de ordenação,
mas a ordenação em si, neste exemplo é mais simples.
Na realidade este é o mesmo exercício, porém mais
elaborado. Entendendo o outro exercício bem, não será
difícil entender este.