Analise o seguinte programa:
void func1 (int x) {
    x = 9 * x;
}
void func2 (int v[]) {
    v[0] = 9 * v[0] ;
}
int main (void) {
    int x, v[2];
    x = 111;
    func1 (x); printf ("x: %d\n", x);
    v[0] = 111;
    func2 (v); printf ("v[0]: %d\n", v[0]);
    return EXIT_SUCCESS;
}
E responda por que o programa produz a seguinte resposta:
x: 111 \mathrm{v}[0]: 999

Passo 1

O enunciado dá o código em C e mostra a saída obtida:
  • O programa imprime primeiro x: 111 e depois v[0]: 999.
  • As atribuições antes das chamadas são: x = 111 e v[0] = 111.
    A pergunta implícita é: por que após as chamadas de função a variável x ficou com valor 111 enquanto v[0] ficou com valor 999?

Passo 2

Entender exatamente o que cada função recebe quando é chamada.
  • Em func1(int x) o parâmetro x é do tipo inteiro simples. Quando func1(x) é chamada, o que se passa para a função é uma cópia do valor de x. Ou seja, dentro de func1 existe uma variável local (também chamada x) que começou com uma cópia do valor 111.
  • Em func2(int v[]) o parâmetro escrito como int v[] é, na verdade, sintaticamente equivalente a int *v em C. Portanto, quando func2(v) é chamada, o que se passa para a função é um ponteiro (um endereço) que aponta para o primeiro elemento do array v do main.

Passo 3

Explicar o conceito central: passagem por valor em C.
  • Em C, todos os parâmetros são passados por valor. Isso significa que a função recebe uma cópia do que foi passado.
  • Se o que é copiado é um inteiro (como em func1), a função manipula só essa cópia; a variável original no main não muda.
  • Se o que é copiado é um ponteiro (como em func2, porque o nome do array decai para um ponteiro), a cópia é do endereço. Ambas — a cópia (no corpo da função) e o valor original (no main) — apontam para a mesma área de memória. Assim, operações que usam esse ponteiro para modificar a memória afetam o conteúdo do main.

Passo 4

Aplicar isso ao caso de func1.
  • Antes da chamada: no main, x = 111.
  • Chamada func1(x): a função recebe uma cópia do valor 111 em seu próprio parâmetro local x.
  • Dentro de func1 executa-se x = 9 * x; — isto altera só a cópia local para 999.
  • Ao retornar, essa variável local deixa de existir; o x do main não foi modificado e permanece 111.
  • Por isso o printf logo depois imprime x: 111.

Passo 5

Aplicar isso ao caso de func2.
  • Antes da chamada: no main, v[0] = 111.
  • Chamada func2(v): o nome v decai para o endereço de seu primeiro elemento; a função recebe uma cópia desse endereço (um ponteiro para v[0]).
  • Dentro de func2 a expressão v[0] = 9 * v[0]; faz desreferência do ponteiro e escreve diretamente no local de memória onde v[0] do main está armazenado. Ou seja, altera o conteúdo do array do main.
  • Depois do retorno, o mainv[0] modificado para 999.
  • Por isso o printf imprime v[0]: 999.

Passo 6

Resumo visual (conceitual) rápido:
  • Para func1(x):
    • main tem x = 111.
    • func1 recebe cópia: local x = 111 → multiplica → local x = 999 → retorna → main.x permanece 111.
  • Para func2(v):
    • main tem v[0] = 111.
    • func2 recebe ponteiro para v[0] → escreve através do ponteiro → v[0] em main fica 999.

Passo 7

Observações finais e dica prática para a prova (estilo “truque” para lembrar):
  • Em C, se quiser que uma função modifique um inteiro do chamador, passe o endereço: void func1(int *px) { *px = 9 * (*px); } e chame func1(&x);.
  • Arrays nunca são passados “por cópia” em C; o que se passa é um ponteiro para seu primeiro elemento (logo, funções podem modificar elementos do array).

Resposta

Porque em C os parâmetros são passados por valor: em func1(int x) é recebida apenas uma cópia do inteiro x, então a multiplicação altera só a cópia local (o x do main continua 111). Já em func2(int v[]) o parâmetro é, na prática, um ponteiro para o primeiro elemento do array (equivalente a int *v), portanto a atribuição v[0] = 9 * v[0] modifica diretamente a memória do array do main, tornando v[0] igual a 999.

Exercícios relacionados