Sumariando:
* Resolver o problema da criação de uma função para a troca de valores entre duas variáveis.
* Aritmética de ponteiros.
* Comparação de ponteiros.
Vamos começar por resolver o segundo problema apresentado na parte 1 deste artigo que é o problema de criar uma função que dados dois argumentos para essa mesma função trocar o valor entre eles.
Vamos primeiro perceber por que razão é que uma solução como passar argumentos "normais" não resulta.
Ora bem, quando nós chamámos uma função é criado, como já disse, o seu stack frame. Nesse stack frame vão estar também as variáveis criadas como argumento. Por exemplo, se tivessemos uma definição assim: void fun (int x, int y). Neste caso seria criada, quando chamada, no stack frame da função fun uma variável x e uma variável y. Quando fossemos a chamar esta função, por exemplo assim: fun (10, 20), estaríamos a passar o quê realmente? Estaríamos a passar o valor 10 para a variável x e o valor 20 para a variável y! Ou seja, chamar a função assim: fun (10, 20) é o mesmo que fazer: x = 10, y = 20. Acontecia exactamente o mesmo se fossemos a fazer:
int k = 10, j = 20;
fun (k,j);
Neste caso nós na função fun não estaríamos a trabalhar realmente com k e j mas sim com os seus valores! Ou seja, era a mesma coisa que fazer: x = k, y = j! É muito importante reter esta ideia: quando chamámos uma função com argumentos é na realidade passado para essa função o valor dos argumentos e não os argumentos em si!
A partir disto a questão continua: como é que então vamos trabalhar com os argumentos em si, visto que é isso mesmo que nós queremos, alterá-los...?
Outra vez, a solução passa por utilizar ponteiros. Se nós arranjássemos maneira de conseguir ter o endereço das variáveis na função que vamos criar e se tivéssemos um ponteiro para as manipular e modificar podíamos alterá-las realmente! Ora, isto é perfeitamente possível de o fazer, basta fazer o seguinte:
* Criar uma função que vai ter como argumentos dois ponteiros (que vão receber os endereços das variáveis de main).
* Passar para essa função os endereços das variáveis.
A partir daqui bastava utilizar o operador * para alterar o valor para onde os ponteiros apontam (variáveis da função main).
Vamos então resolver este problema de uma vez por todas.
Exemplo nº 5
Pus diversos comentários que penso serem importantes para entenderem bem isto!
Então, no programa são passados para a função fun os endereços de k e de j para que nessa função possamos trabalhar com eles directamente, visto que o que vai receber esses valores vão ser dois ponteiros! A partir daí podemos trabalhar com essas variáveis directamente através do operador *. É importante que entendam bem este programa por isso não avancem mais no artigo sem o entender bem!
Vou deixar, já agora uma imagem que relata a situação do nosso programa (com stack frames de main e fun).

Se pensarmos um bocadinho vamos-nos lembrar de outra situação em que é preciso passar o endereço das variáveis para uma função bem conhecida por todos vocês! A função scanf:
int x = 0;
scanf ("%d", &x);
Por que razão é que temos de passar para a função scanf o endereço de x? Simplesmente porque a função scanf vai alterar o valor de x e vai "colocar" nele o valor introduzido pelo usuário. X encontra-se no stack frame de main, por exemplo (podia ser outra função qualquer) e nós estamos a criar outro stack frame para a função scanf! Para alterar o valor de x temos de "invadir" o stack frame da função onde se encontra x e depois alterar o seu valor com o valor introduzido pelo usuário. Se não passássemos o endereço de x e fizéssemos: scanf ("%d", x) estaríamos na realidade a passar para um ponteiro o valor de x, que neste caso é 0, então estaríamos a armazenar na posição 0 o valor introduzido pelo usuário, visto que foi passado para o ponteiro o valor 0, ou seja, ele iria apontar para a posição 0 na memória! Isto resultaria num segmentation fault.
Em construção [...]
Muito útil! E muito bem explicado, parabéns!
ResponderEliminarBruno F.