C Parâmetros

Na aula Funções, todas as funções faziam sempre a mesma coisa: linha() desenhava sempre a mesma linha. Uma função fica muito mais útil quando você pode entregar informações para ela trabalhar: "mostre o dobro deste número", "calcule o total desta compra". Essas informações chegam pelos parâmetros. Nesta aula você vai criar funções que recebem valores, entender por que a função recebe uma cópia (e não a variável original), ver o caso especial dos arrays e descobrir que, em C, dois nomes de função iguais não convivem.

Você vai aprender
  • A diferença entre parâmetro (na definição) e argumento (na chamada).
  • Como escrever funções com um ou vários parâmetros, cada um com o seu tipo.
  • Por que a ordem dos argumentos importa e o que acontece quando o tipo não bate.
  • A passagem por valor: a função recebe uma cópia, e mudar o parâmetro não muda a variável de quem chamou.
  • Arrays como parâmetro: por que é preciso passar o tamanho junto, e por que aqui a função consegue mudar o original.
  • Por que C não tem sobrecarga (duas funções com o mesmo nome) e o erro conflicting types.

Todos os programas desta aula foram compilados com o gcc 15.2 na máquina fictícia da Ana, na pasta ~/c, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -o programa.


A ideia: o formulário e o que você preenche

Pense num formulário de pedido da lojinha da Ana. O papel impresso tem campos com nome: Produto: ____, Quantidade: ____. Cada cliente preenche os campos com valores diferentes, mas o formulário é sempre o mesmo.

No formulárioEm CNome técnico
O campo impresso, "Quantidade: ____"A variável declarada entre os parênteses da definição: void pedir(int quantidade)parâmetro
O que o cliente escreve no campo, "3"O valor entre os parênteses da chamada: pedir(3);argumento

Muita gente (e muito livro) usa as duas palavras como se fossem a mesma coisa. Não tem problema; mas, quando o compilador fala em argument, ele quer dizer o valor da chamada.


1. Uma função com um parâmetro

#include <stdio.h>

void mostrar_dobro(int n) {
    printf("O dobro de %d é %d\n", n, n * 2);
}

int main(void) {
    mostrar_dobro(5);
    mostrar_dobro(21);
    int idade = 29;
    mostrar_dobro(idade);
    mostrar_dobro(idade + 1);
    return 0;
}
(int n)
O parâmetro: uma variável int chamada n, que só existe dentro da função. Ela não tem valor fixo: recebe um novo valor a cada chamada.
n * 2
Dentro do corpo, n é usado como qualquer variável.
mostrar_dobro(5);
O argumento 5 é copiado para n, e o corpo roda com n valendo 5.
mostrar_dobro(idade);
O argumento pode ser uma variável: o valor dela (29) é copiado para n. Os nomes não precisam combinar.
mostrar_dobro(idade + 1);
Pode ser também uma conta: o C calcula idade + 1 (30) primeiro e passa o resultado.
$ gcc -std=c23 -Wall -Wextra dobro.c -o dobro
$ ./dobro
O dobro de 5 é 10
O dobro de 21 é 42
O dobro de 29 é 58
O dobro de 30 é 60

Uma única função, quatro resultados diferentes. É isso que os parâmetros trazem: a mesma receita, com ingredientes diferentes a cada vez.


2. Vários parâmetros

Para entregar mais de uma informação, separe os parâmetros por vírgula. Cada um tem o seu tipo:

#include <stdio.h>

void mostrar_total(int quantidade, double preco) {
    printf("%d x R$ %.2f = R$ %.2f\n", quantidade, preco, quantidade * preco);
}

int main(void) {
    mostrar_total(3, 2.50);
    mostrar_total(10, 0.75);
    mostrar_total(2.50, 3);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra total.c -o total
$ ./total
3 x R$ 2.50 = R$ 7.50
10 x R$ 0.75 = R$ 7.50
2 x R$ 3.00 = R$ 6.00          « argumentos na ordem errada: nenhum aviso do gcc
int quantidade, double preco
Dois parâmetros, separados por vírgula, cada um com seu tipo. O primeiro argumento vai para o primeiro parâmetro, o segundo para o segundo.
mostrar_total(3, 2.50);
quantidade recebe 3 e preco recebe 2.50.
mostrar_total(2.50, 3);
A ordem é que manda, não o nome nem a intenção. O 2.50 foi para quantidade (que é int, então virou 2, cortando o .50) e o 3 foi para preco (virou 3.00).

A terceira linha mostra um erro que o gcc deixou passar calado: ele converte o número para o tipo do parâmetro, sem perguntar (as conversões têm aula própria, Conversão de Tipos). O Clang do editor é mais atento quando o número está escrito direto no código e avisa: implicit conversion from 'double' to 'int' changes value from 2.5 to 2 [-Wliteral-conversion]. No gcc, quem avisa é a opção -Wconversion, que não faz parte do -Wall (veja Avisos).

Cada parâmetro precisa do seu tipo

Nas variáveis, int largura, altura; cria as duas como int. Nos parâmetros, não: cada um repete o tipo.

#include <stdio.h>

void mostrar_area(int largura, altura) {
    printf("Área: %d\n", largura * altura);
}

int main(void) {
    mostrar_area(3, 4);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra tipojunto.c -o tipojunto
tipojunto.c:3:32: error: unknown type name ‘altura’
    3 | void mostrar_area(int largura, altura) {
      |                                ^~~~~~
tipojunto.c: In function ‘main’:
tipojunto.c:8:5: error: implicit declaration of function ‘mostrar_area’ [-Wimplicit-function-declaration]
    8 |     mostrar_area(3, 4);
      |     ^~~~~~~~~~~~

Unknown type name ‘altura’ = "nome de tipo desconhecido: altura". Depois da vírgula, o gcc esperava um tipo e achou um nome que não conhece. Como a definição inteira falhou, a função "não existe", e o segundo erro aparece no main. Conserte o primeiro e o segundo some: void mostrar_area(int largura, int altura).

Experimente: rode e confira as três linhas. Depois acrescente uma chamada sua, por exemplo mostrar_total(4, 1.25);. Por fim, troque a ordem dos argumentos de uma chamada e leia o aviso que o Clang mostra.

#include <stdio.h>

void mostrar_total(int quantidade, double preco) {
    printf("%d x R$ %.2f = R$ %.2f\n", quantidade, preco, quantidade * preco);
}

int main(void) {
    mostrar_total(3, 2.50);
    mostrar_total(10, 0.75);
    mostrar_total(1, 12.90);
    return 0;
}

3. Passagem por valor: a função recebe uma cópia

Esta é a ideia mais importante da aula. Quando você chama uma função, o C copia o valor de cada argumento para o parâmetro. A função trabalha com a cópia. Veja:

#include <stdio.h>

void zerar(int x) {
    x = 0;
    printf("Dentro de zerar: x = %d\n", x);
}

int main(void) {
    int pontos = 50;
    zerar(pontos);
    printf("No main: pontos = %d\n", pontos);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra copia.c -o copia
$ ./copia
Dentro de zerar: x = 0
No main: pontos = 50            « a variável do main não mudou
  1. O main cria pontos valendo 50.
  2. A chamada zerar(pontos) lê o valor de pontos (50) e o copia para uma variável nova, x, que pertence à função.
  3. Dentro de zerar, x = 0; muda a cópia. A tela confirma: x = 0.
  4. A função termina e x deixa de existir. A variável pontos do main nunca foi tocada: continua 50.

É como tirar uma xerox de um documento e entregar a cópia: a pessoa pode rabiscar a xerox à vontade, e o original continua limpo na sua gaveta. Isso se chama passagem por valor, e em C todo argumento é passado assim.

E se o parâmetro tiver o mesmo nome da variável? Não muda nada: são duas variáveis diferentes, em lugares diferentes, que só têm o nome igual (a aula Escopo explica por quê). Nesse caso o gcc ainda dá uma dica valiosa:

#include <stdio.h>

void zerar(int pontos) {
    pontos = 0;
}

int main(void) {
    int pontos = 50;
    zerar(pontos);
    printf("pontos = %d\n", pontos);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra mesmonome.c -o mesmonome
mesmonome.c: In function ‘zerar’:
mesmonome.c:3:16: warning: parameter ‘pontos’ set but not used [-Wunused-but-set-parameter]
    3 | void zerar(int pontos) {
      |            ~~~~^~~~~~
$ ./mesmonome
pontos = 50

Parameter ‘pontos’ set but not used = "o parâmetro pontos recebe um valor, mas nunca é usado". O gcc percebeu que guardar 0 numa cópia que ninguém mais lê é inútil: um forte sinal de que você esperava mudar a variável de fora.

E se eu quiser que a função mude a variável de quem chamou?

Há dois caminhos. O mais simples é a função devolver o novo valor, e quem chamou guarda: pontos = zerado(); (aula Valor de Retorno). O outro é entregar à função o endereço da variável, em vez de uma cópia do valor: é a passagem por ponteiro, aula Passar por Ponteiro, do Nível 2. É assim que o scanf("%d", &idade) consegue mudar a sua variável: o & entrega o endereço.

Missão: a Ana quer calcular a área de dois canteiros retangulares. Escreva a função mostrar_area com dois parâmetros int (a largura e a altura) que mostra Área: seguido de largura vezes altura. O main já chama a função com (3, 4) e (5, 10).

Área: 12
Área: 50
#include <stdio.h>

// escreva aqui a função mostrar_area

int main(void) {
    mostrar_area(3, 4);
    mostrar_area(5, 10);
    return 0;
}
#include <stdio.h>

void mostrar_area(int largura, int altura) {
    printf("Área: %d\n", largura * altura);
}

int main(void) {
    mostrar_area(3, 4);
    mostrar_area(5, 10);
    return 0;
}

4. Número errado de argumentos e tipo errado

O compilador confere a chamada com o cabeçalho da função. Faltou argumento? Erro:

#include <stdio.h>

void media(double a, double b) {
    printf("Média: %.1f\n", (a + b) / 2);
}

int main(void) {
    media(7.5);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra poucos.c -o poucos
poucos.c: In function ‘main’:
poucos.c:8:5: error: too few arguments to function ‘media’; expected 2, have 1
    8 |     media(7.5);
      |     ^~~~~
poucos.c:3:6: note: declared here
    3 | void media(double a, double b) {
      |      ^~~~~

Too few arguments = "argumentos de menos"; expected 2, have 1 = "esperava 2, recebeu 1". Com argumentos de mais, a mensagem é too many arguments. O Clang do editor escreve too few arguments to function call, expected 2, have 1. Em C, todo parâmetro precisa receber um argumento: não existe "valor padrão" para o parâmetro que faltou.

E um argumento do tipo errado? Depende de quão errado ele é:

#include <stdio.h>

void mostrar_dobro(int n) {
    printf("O dobro de %d é %d\n", n, n * 2);
}

int main(void) {
    mostrar_dobro(2.9);
    mostrar_dobro("dez");
    return 0;
}
$ gcc -std=c23 -Wall -Wextra tipo.c -o tipo
tipo.c: In function ‘main’:
tipo.c:9:19: error: passing argument 1 of ‘mostrar_dobro’ makes integer from pointer without a cast [-Wint-conversion]
    9 |     mostrar_dobro("dez");
      |                   ^~~~~
      |                   |
      |                   char *
tipo.c:3:24: note: expected ‘int’ but argument is of type ‘char *’
    3 | void mostrar_dobro(int n) {
      |                    ~~~~^
mostrar_dobro(2.9)
Número com vírgula num parâmetro int: o gcc converte em silêncio (vira 2). Nenhuma linha da saída fala da linha 8.
passing argument 1 of ‘mostrar_dobro’
"Passando o argumento 1 de mostrar_dobro…"
makes integer from pointer without a cast
"…cria um inteiro a partir de um ponteiro sem conversão explícita". Um texto entre aspas, para o C, é o endereço de onde as letras estão guardadas (um ponteiro, char *), e não um número. Transformar texto em número é outra coisa: veja Texto ↔ Número.
[-Wint-conversion]
No gcc 14 em diante, isso é erro. Em gcc mais antigos era só aviso, e o programa rodava com um número sem sentido.
note: expected ‘int’ but argument is of type ‘char *’
"Esperava int, mas o argumento é do tipo char *", apontando o parâmetro.

5. Arrays como parâmetro

Arrays (aula Arrays) também podem ir para uma função, e aqui o C tem duas surpresas. A primeira: a função não sabe o tamanho do array.

#include <stdio.h>

void mostrar(int notas[]) {
    int n = sizeof(notas) / sizeof(notas[0]);
    printf("Dentro da função: %d notas\n", n);
}

int main(void) {
    int notas[5] = {7, 9, 6, 10, 8};
    printf("No main: %zu notas\n", sizeof(notas) / sizeof(notas[0]));
    mostrar(notas);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra arrsize.c -o arrsize
arrsize.c: In function ‘mostrar’:
arrsize.c:4:19: warning: ‘sizeof’ on array function parameter ‘notas’ will return size of ‘int *’ [-Wsizeof-array-argument]
    4 |     int n = sizeof(notas) / sizeof(notas[0]);
      |                   ^
arrsize.c:3:18: note: declared here
    3 | void mostrar(int notas[]) {
      |              ~~~~^~~~~~~
$ ./arrsize
No main: 5 notas
Dentro da função: 2 notas       « errado: o array tem 5

No main, o truque sizeof(notas) / sizeof(notas[0]) (aula sizeof) dá 5. Dentro da função, deu 2, e o gcc explicou: ‘sizeof’ on array function parameter ‘notas’ will return size of ‘int *’, "o sizeof de um parâmetro array vai devolver o tamanho de um int *".

O que acontece é que o array não é copiado para a função. Copiar um array de mil números a cada chamada seria lento, então o C entrega só o endereço do primeiro elemento, um ponteiro (int *). Dizemos que o array decai para ponteiro. Para a função, int notas[] é só outro jeito de escrever int *notas. O sizeof mediu o ponteiro (8 bytes neste computador) dividido por um int (4 bytes): 2. No editor do guia, onde um ponteiro tem 4 bytes, o mesmo programa mostra 1 notas. Os dois estão errados do mesmo jeito. (Ponteiros e arrays têm aula própria: Ponteiros e Arrays.)

O conserto é o padrão de todo programa C: passe o tamanho junto, num segundo parâmetro.

#include <stdio.h>

void mostrar_media(const int notas[], int n) {
    int soma = 0;
    for (int i = 0; i < n; i++) {
        soma = soma + notas[i];
    }
    printf("Média de %d notas: %.1f\n", n, (double) soma / n);
}

int main(void) {
    int turma_a[5] = {7, 9, 6, 10, 8};
    int turma_b[3] = {5, 6, 10};
    mostrar_media(turma_a, 5);
    mostrar_media(turma_b, 3);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra media.c -o media
$ ./media
Média de 5 notas: 8.0
Média de 3 notas: 7.0
const int notas[]
O parâmetro array, sem tamanho entre os colchetes (se você escrever um número ali, o C ignora). O const é uma promessa: "esta função só lê o array". A próxima seção mostra por que ele é útil.
int n
Quantos elementos o array tem. Quem chama sabe o tamanho; a função, não. Por isso o tamanho viaja junto.
mostrar_media(turma_a, 5)
Na chamada, o array vai só com o nome, sem colchetes.
(double) soma / n
Converte a soma para double antes de dividir, para não perder a parte decimal (aula Conversão de Tipos).

A segunda surpresa: com array, a função mexe no original

Na seção 3, a função recebia uma cópia e não conseguia mudar a variável de fora. Com array é diferente: a função recebe o endereço, e portanto trabalha nos mesmos elementos.

#include <stdio.h>

void dar_bonus(int notas[], int n) {
    for (int i = 0; i < n; i++) {
        notas[i] = notas[i] + 1;
    }
}

int main(void) {
    int notas[3] = {7, 9, 6};
    dar_bonus(notas, 3);
    for (int i = 0; i < 3; i++) {
        printf("%d ", notas[i]);
    }
    printf("\n");
    return 0;
}
$ gcc -std=c23 -Wall -Wextra arrmuda.c -o arrmuda
$ ./arrmuda
8 10 7                          « as notas do main ganharam o bônus

Continua sendo passagem por valor: o que foi copiado é o endereço. Mas uma cópia do endereço aponta para o mesmo lugar, como entregar a alguém uma cópia da chave da sua casa. Às vezes é exatamente o que você quer (como aqui); às vezes é um acidente. Para impedir o acidente, use const:

#include <stdio.h>

void mostrar(const int notas[], int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", notas[i]);
    }
    printf("\n");
    notas[0] = 0;
}

int main(void) {
    int notas[3] = {7, 9, 6};
    mostrar(notas, 3);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra constarr.c -o constarr
constarr.c: In function ‘mostrar’:
constarr.c:8:14: error: assignment of read-only location ‘*notas’
    8 |     notas[0] = 0;
      |              ^

Assignment of read-only location = "atribuição a um lugar somente leitura". O *notas da mensagem é o jeito de escrever "o que está no endereço notas" (você vai ver essa notação em Ponteiros). Regra prática: se a função só lê o array, escreva const; quem lê o cabeçalho já sabe que os dados estão seguros (mais em const e Ponteiros).


6. C não tem sobrecarga

Em algumas linguagens (como C++ e Java), você pode ter duas funções com o mesmo nome, desde que recebam coisas diferentes. Isso se chama sobrecarga. Em C, não:

#include <stdio.h>

int area(int lado) {
    return lado * lado;
}

double area(double largura, double altura) {
    return largura * altura;
}

int main(void) {
    printf("%d\n", area(3));
    return 0;
}
$ gcc -std=c23 -Wall -Wextra sobrecarga.c -o sobrecarga
sobrecarga.c:7:8: error: conflicting types for ‘area’; have ‘double(double,  double)’
    7 | double area(double largura, double altura) {
      |        ^~~~
sobrecarga.c:3:5: note: previous definition of ‘area’ with type ‘int(int)’
    3 | int area(int lado) {
      |     ^~~~
sobrecarga.c: In function ‘main’:
sobrecarga.c:12:20: error: too few arguments to function ‘area’; expected 2, have 1
   12 |     printf("%d\n", area(3));
      |                    ^~~~
sobrecarga.c:7:8: note: declared here
    7 | double area(double largura, double altura) {
      |        ^~~~
int area(int lado) { return … }
As duas funções usam return para devolver um resultado; isso é assunto da próxima aula, Valor de Retorno. Aqui, o que importa é o nome repetido.
conflicting types for ‘area’
"Tipos em conflito para area". Para o C, um nome = uma função. Ao ver a segunda, com outro tipo (double(double, double)), ele acusa o conflito com a primeira (int(int)).
too few arguments to function ‘area’
Um efeito colateral: o gcc ficou com a segunda area na cabeça, que pede dois argumentos, e estranhou a chamada com um. Conserte o primeiro erro e este some.

O conserto em C é dar nomes diferentes, que digam a diferença: area_quadrado(int lado) e area_retangulo(double largura, double altura). A própria biblioteca do C faz isso: abs (inteiro), labs (long) e fabs (double) são três funções para o mesmo cálculo (aula Matemática). Para quem quer muito "um nome só", o C11 trouxe o _Generic, um recurso avançado (aula _Generic).


Qual tipo usar no parâmetro

Você quer entregar…ParâmetroObservação
Um número inteiro (quantidade, idade)int nA função recebe uma cópia
Um número com vírgula (preço, nota)double xUm int passado aqui vira double sem perda
Uma letrachar cCópia, como qualquer número
Um array que a função só lêconst int v[], int nSempre com o tamanho; o const protege os dados
Um array que a função mudaint v[], int nAs mudanças valem para o array de quem chamou
Uma variável comum que a função deve mudarint *pPassagem por ponteiro: Passar por Ponteiro
Nada(void)Veja Funções

Quando dá errado

error: too few arguments to function ‘media’; expected 2, have 1

O que significa: a chamada tem menos valores do que a função tem parâmetros (com too many, mais).

Como consertar: olhe a note: declared here, que mostra o cabeçalho, e passe um argumento para cada parâmetro, na mesma ordem.

error: passing argument 1 of ‘f’ makes integer from pointer without a cast [-Wint-conversion]

O que significa: você passou um texto (ou outro endereço) onde a função espera um número. No editor, o Clang escreve incompatible pointer to integer conversion passing 'char[4]' to parameter of type 'int'.

Como consertar: passe um número (10, não "10"). Se o número está dentro de um texto, converta antes com strtol (Texto ↔ Número).

A função mudou o parâmetro, mas a variável continuou igual

O que significa: passagem por valor. A função mudou a cópia. O gcc às vezes avisa com parameter ‘x’ set but not used.

Como consertar: faça a função devolver o novo valor (Valor de Retorno) ou receber um ponteiro (Passar por Ponteiro).

warning: ‘sizeof’ on array function parameter ‘v’ will return size of ‘int *’

O que significa: dentro da função, o array virou ponteiro, e o sizeof mede o ponteiro, não o array. O número de elementos calculado assim sai errado.

Como consertar: receba o tamanho num parâmetro (int n) e calcule o sizeof só onde o array foi criado.

error: unknown type name ‘altura’ no cabeçalho

O que significa: faltou o tipo de um parâmetro: (int largura, altura).

Como consertar: repita o tipo em cada parâmetro: (int largura, int altura).

warning: unused parameter ‘vezes’ [-Wunused-parameter]

O que significa: a função recebe um parâmetro e nunca o usa. Esse aviso vem do -Wextra. Quase sempre é um esquecimento: por exemplo, void saudar(int vezes) que mostra Olá! uma vez só, em vez de repetir vezes vezes.

Como consertar: use o parâmetro (aqui, com um for) ou, se ele realmente sobra, tire-o do cabeçalho e das chamadas.

error: conflicting types for ‘area’

O que significa: duas funções com o mesmo nome e tipos diferentes. Em C não existe sobrecarga.

Como consertar: dê um nome diferente para cada uma (area_quadrado, area_retangulo). Esse erro também aparece quando o protótipo não bate com a definição: veja Protótipos.


Referência rápida

EscritaO que faz
void f(int n) { … }Define f com um parâmetro int
void f(int a, double b)Dois parâmetros, cada um com o seu tipo, separados por vírgula
f(5); / f(x); / f(x + 1);Chamadas: o valor do argumento é copiado para o parâmetro
f(3, 2.5);Os argumentos vão para os parâmetros na ordem
void f(int v[], int n)Recebe um array (na verdade, o endereço dele) e o tamanho
void f(const int v[], int n)O mesmo, prometendo não mudar o array
f(notas, 5);Passa o array (sem colchetes) e o tamanho

Exercícios

1. O parâmetro

Complete o cabeçalho de uma função que recebe um número inteiro chamado idade:

void mostrar_idade() {

2. A chamada

A função é void mostrar_total(int quantidade, double preco). Complete a chamada para 4 unidades a 2.5 cada:

mostrar_total();

3. O tamanho junto

Complete o segundo parâmetro, que recebe quantos elementos o array tem:

void mostrar(const int v[], ) {

4. Com void dobrar(int x) { x = x * 2; }, o que o main mostra depois de int v = 5; dobrar(v); printf("%d", v);?

5. Com void bonus(int v[], int n) somando 1 a cada elemento, o que acontece com o array de quem chamou?

6. Um arquivo tem int maior(int a, int b) e double maior(double a, double b). O que o gcc diz?

Missão final: o boletim da Ana

Missão: escreva a função mostrar_maior, que recebe um array de int e o tamanho dele (int) e mostra Maior nota: seguido da maior nota do array. Dica: guarde a primeira nota numa variável maior e percorra o resto com um for, trocando maior sempre que achar uma nota maior. Use const no array, já que a função só lê.

Maior nota: 10
Maior nota: 9
#include <stdio.h>

// escreva aqui a função mostrar_maior

int main(void) {
    int turma_a[5] = {7, 9, 6, 10, 8};
    int turma_b[4] = {5, 9, 3, 8};
    mostrar_maior(turma_a, 5);
    mostrar_maior(turma_b, 4);
    return 0;
}
#include <stdio.h>

void mostrar_maior(const int notas[], int n) {
    int maior = notas[0];
    for (int i = 1; i < n; i++) {
        if (notas[i] > maior) {
            maior = notas[i];
        }
    }
    printf("Maior nota: %d\n", maior);
}

int main(void) {
    int turma_a[5] = {7, 9, 6, 10, 8};
    int turma_b[4] = {5, 9, 3, 8};
    mostrar_maior(turma_a, 5);
    mostrar_maior(turma_b, 4);
    return 0;
}

Repare que a mesma função serviu para turmas de tamanhos diferentes. É por isso que o tamanho vai no parâmetro, e não escrito dentro da função.


Resumo

  • Parâmetro é a variável do cabeçalho (int n); argumento é o valor da chamada (5, idade, idade + 1).
  • Vários parâmetros: separados por vírgula, cada um com o seu tipo. Os argumentos vão na ordem; trocar a ordem passa calado no gcc.
  • Passagem por valor: a função recebe uma cópia. Mudar o parâmetro não muda a variável de quem chamou. Para mudar, devolva o valor ou use um ponteiro.
  • Número errado de argumentos é erro (too few/too many arguments). Texto num parâmetro int é erro (-Wint-conversion); double num int é cortado em silêncio.
  • Array como parâmetro decai para ponteiro: a função não sabe o tamanho (passe int n junto) e mexe no array original. Use const quando só for ler.
  • C não tem sobrecarga: dois nomes iguais dão conflicting types. Use nomes diferentes.