Revisão da ETAPA 5 — Funções, escopo, vetores como argumentos e recursão

Revise as aulas 24 a 33 com uma folha de consulta, seis questões de leitura de código e uma lista de erros frequentes.

① Folha de consulta

Revise os conceitos essenciais da ETAPA 5nas tabelas a seguir.

🔧 Estrutura de uma função

// Tipo de retorno nome(tipo do parâmetro, ...)
int square(int x) {
    return x * x;
}

int main(void) {
    printf("%d\n", square(5)); // 25
}
  • Tipo de retorno / nome / parâmetros / corpo são as quatro partes
  • Uma função sem retorno usa void
  • return devolve um valor (e encerra a função)

🎚️ Argumentos são passados por valor (cópia)

void add10(int x) {
    x += 10; // x é uma cópia
}
int main(void) {
    int a = 5;
    add10(a);
    printf("%d\n", a); // Continua 5!
}
  • O parâmetro recebe uma cópia do valor ; alterá-lo na função não afeta a variável original
  • Para alterar a variável original, passe um ponteiro ou atribua o valor retornado à variável.

🔭 Escopo (onde uma variável é válida)

int g = 100;       // Global

void f(void) {
    int x = 1;     // Local apenas de f
}
int main(void) {
    int x = 2;     // x de main (outra variável)
    f();
    printf("%d %d\n", x, g); // 2 100
}
  • Variáveis declaradas dentro da função são válidas somente nessa função (locais)
  • Variáveis declaradas fora das funções podem ser usadas em seu escopo global (globais)
  • Mesmo nome em escopos diferentes pode representar variáveis distintas

📐 Passar um vetor como argumento

void fill(int a[], int n) {
    for (int i = 0; i < n; i++) a[i] = 7;
}
int main(void) {
    int a[3] = {0};
    fill(a, 3);
    // a passa a ser {7, 7, 7}
}
  • Ao passar um vetor, transmite-se o endereço do primeiro elemento (o vetor não é copiado)
  • Alterações nos elementos dentro da função afetam o vetor original
  • No parâmetro de vetor, sizeof não fornece o comprimento (passe-o separadamente)

🔄 Função recursiva (chama a si mesma)

int factorial(int n) {
    if (n <= 1) return 1; // Caso base!
    return n * factorial(n - 1);
}
// factorial(4) = 4*3*2*1 = 24
  • Caso base é obrigatório (sem ele, a recursão pode esgotar a pilha)
  • Chame a função para um problema menor

📋 Declaração de protótipo

// Declare antes (a implementação pode vir depois)
int add(int, int);

int main(void) {
    printf("%d\n", add(2, 3));
}

int add(int a, int b) { return a + b; }
  • Antes do uso, informe ao compilador a assinatura da função .
  • Se a definição vier após main, declare o protótipo antes

② Seis questões de leitura de código

Execute mentalmente antes de clicar em uma alternativa. Se errar, leia a explicação.

Q1. Usar o valor de retorno

int square(int x) { return x * x; }

int main(void) {
    printf("%d\n", square(3) + square(4));
}

Qual é a saída?

12
25
7
49
Explicação: square(3) vale 9 e square(4) vale 16. Portanto, 9 + 16 = 25, e a saída é 25. Essa soma também aparece na relação pitagórica 3–4–5.

Q2. Confirmar a passagem por valor

void add10(int x) { x += 10; }

int main(void) {
    int a = 5;
    add10(a);
    printf("%d\n", a);
}

Qual é a saída?

5
10
15
Indefinido
Explicação: Os argumentos escalares são passados por valor. Dentro de add10, x é uma cópia separada de a; acrescentar 10 a x não altera a. A saída continua sendo 5. Para alterar a variável original, passe seu endereço a uma função como void add10(int *p) ou atribua um valor retornado, como em a = add10(a).

Q3. Vetor como argumento

void setZero(int a[], int n) {
    for (int i = 0; i < n; i++) a[i] = 0;
}

int main(void) {
    int a[3] = {7, 8, 9};
    setZero(a, 3);
    printf("%d %d %d\n", a[0], a[1], a[2]);
}

Qual é a saída?

7 8 9 (sem alteração)
0 0 0
Indefinido (não inicializado)
Erro de compilação
Explicação: Ao passar um array, a função recebe um ponteiro para seu primeiro elemento, não uma cópia de todos os elementos. Assim, escrever a[i] = 0 modifica o array original, produzindo 0 0 0. Compare com a cópia do valor int na questão 2.

Q4. Variáveis locais e globais

int g = 100;

void f(void) {
    int g = 1; // Local com o mesmo nome
    printf("f: %d\n", g);
}

int main(void) {
    f();
    printf("main: %d\n", g);
}

Qual é a saída?

f: 100
main: 100
f: 1
main: 100
f: 1
main: 1
Erro de compilação (nome repetido)
Explicação: Em f, int g = 1; declara uma variável local, diferente da global g. A local oculta a global dentro da função (shadowing). Assim, f exibe f: 1, e main usa a global, exibindo main: 100.

Q5. Caso base da recursão

int fact(int n) {
    if (n <= 1) return 1;
    return n * fact(n - 1);
}
printf("%d\n", fact(4));

Qual é a saída?

10
24
4
Recursão infinita e falha
Explicação: O fatorial é 4! = 4 × 3 × 2 × 1 = 24. As chamadas se expandem em fact(4) = 4 * fact(3) = 4 * 3 * fact(2) = 4 * 3 * 2 * fact(1). O caso base n <= 1 retorna 1 e encerra a recursão. A saída é 24.

Q6. Tamanho de vetor dentro de uma função

void show(int a[]) {
    printf("%zu\n", sizeof a);
}

int main(void) {
    int a[5] = {0};
    show(a);
}

Dentro de show, sizeof a retorna o quê?

20 (= 5 × 4 bytes)
5
Tamanho de um ponteiro (8 bytes em muitos ambientes)
Erro de compilação
Explicação: Um parâmetro declarado como int a[] é ajustado para um ponteiro. Dentro da função, sizeof mede esse ponteiro (8 bytes em muitos ambientes), não o array inteiro. Passe o comprimento como outro argumento, por exemplo void show(int a[], int n).

③ Lista de erros e dificuldades frequentes

Se reconhecer um erro que já cometeu, volte à página correspondente para revisar.
  1. 1
    Esperar que alterar um parâmetro mude a variável original
    Argumentos são passados por valor. Para alterar o original, passe um ponteiro ou use um valor de retorno e atribua-o à variável.
  2. 2
    Tipo de retorno e tipo de return incompatíveis
    int como retorno converte implicitamente um double para int.void com return x; viola as regras do retorno.
  3. 3
    Tentar obter o comprimento do vetor com sizeof dentro da função
    Um parâmetro de vetor é tratado como ponteiro , perdendo a informação de comprimento.Passe o comprimento separadamente.
  4. 4
    Esquecer o caso base da recursão
    A recursão infinita causa Estouro de pilha e pode encerrar o programa. Defina primeiro o caso de término.
  5. 5
    Usar uma função definida depois de main sem protótipo
    O compilador precisa conhecer a função antes do uso em main: declare o protótipo antes .
  6. 6
    Confundir variáveis locais e globais com o mesmo nome
    Ao declarar o mesmo nome dentro da função, a variável local tem prioridade(shadowing). Evite nomes iguais para reduzir erros.
  7. 7
    Abusar de variáveis globais e dificultar a manutenção
    Fica difícil descobrir onde cada valor foi alterado.Passe dados por argumentos e retornos como prática básica.

④ Páginas para revisar — retome os pontos difíceis

Use os links para voltar diretamente à explicação correspondente.
Aula 26: Funções (Básico)Para revisar estrutura, parâmetros e retorno Aula 27: Funções (Avançado)Para revisar passagem por valor e escopo Aula 30: Protótipo & MacroPara revisar declarações antecipadas Variáveis GlobaisPara revisar a visibilidade das variáveis Aula 32: Arrays como argumentosPara revisar ponteiros e a armadilha de sizeof Quiz (Funções)Pratique com questões semelhantes RecursãoPara revisar o caso base e a redução do problema Folha de consulta rápidaRevise formatos e funções em uma página