Continuação da matéria de apontadores. Passagem de parâmetros em funções.
Em C, existe uma série de coisas que só se consegue fazer manipulando apontadores. Uma delas é a modificação dos valores dos argumentos durante a execução de uma função. Outra utilidade dos apontadores é o permitir a alocação dinâmica de memória. A alocação dinâmica de memória permite entre outras coisas criar arrays de dimensão variável sem ter de especificar previamente o tamanho máximo do array.
Nesta aula iremos ver a utilidade dos apontadores no que diz respeito à passagem de parâmetros em funções. A alocação dinâmica de memória fica para a próxima aula.
Imaginemos que queríamos fazer uma função para trocar o valor de 2 variáveis. Aqui vai uma tentativa:
void troca( int x, int y ) { int temp; temp = x; x = y; y = temp; }
O programa principal poderia ficar qualquer coisa deste estilo:
main() { int a,b; a = 3; b = 7; troca( a, b ); printf("%d %d", a, b ); }
O objectivo seria trocar os valores das variáveis. Como tal, o programa deveria escrever no ecrã:
7 3
mas se executarmos o programa, o computador não irá trocar coisa nenhuma e irá escrever:
3 7
O problema acontece porque aquilo que é passado quando a função troca é chamada são cópias dos valores dos argumentos a e b. Isto é, x vai receber uma cópia do valor de a (3 no exemplo) e y vai receber uma cópia do valor de b (7 no exemplo). Internamente na função, os valores de x e y vão ser trocados mas os valores de a e b manter-se-ão inalterados (repara que isso aconteceria mesmo que na função tivéssemos chamado x e y em vez de a e b, já que nesse caso, o x da função não teria nada a ver com o x que estava declarado fora da função).
Uma maneira de alterar o valor de variáveis dentro das funções é utilizando variáveis globais (o que torna os programas menos genéricos); outra é passando o endereço das variáveis e depois modificar o seu valor através do operador *. Exemplo:
void troca( int *x, int *y ) { int temp; temp = *x; *x = *y; *y = temp; } main() { int a,b; a = 3; b = 7; troca( &a, &b ); printf("%d %d", a, b ); }
Desta vez, a função troca vai trocar os valores que são apontados por x e y. No exemplo concreto, o programa irá trocar o valor das variáveis a e b. Se não perceberem isto, inventem endereços para as variáveis a e b e façam uns bonecos tal e qual como na aula anterior.
int n; scanf("%d", &n);
O que acontece é que o scanf é uma função que pretende modificar o valor da variável n (n vai passar a ser o valor que o utilizador introduzir), e a única maneira de o fazer é passando o endereço da variável n.
Uma variável definida globalmente pode ser modificada dentro de uma função sem ter de ser passada como argumento. À primeira vista, esta estratégia pode parecer mais simples do que estar a manipular apontadores. No entanto, o uso de variáveis globais deve ser evitado sempre que possível porque as funções que usam variáveis globais deixam de ser genéricas. Uma função deve resolver um sub-problema específico e deve ser feita de tal modo que possa ser reutilizada noutro contexto. Se uma função depende de variáveis globais, não podemos pegar nela e reutilizá-la noutro programa.