📚 Capítulo do curso: 08 — Modularização, Funções, Escopo e Linha de Comando (argc/argv) da Especialização em Sistemas com C. Leia o capítulo antes de começar.
Uma pequena “biblioteca” de funções matemáticas, invocada por linha de comando com argc/argv.
🔒 Regra de Ouro: até o Capítulo 08, você ganha funções (com protótipo, antes de
main), passagem de parâmetros por valor, escopo de variáveis, a palavra-chavestatice os parâmetrosargc/argvdemain. Este é o primeiro miniprojeto do curso com mais de uma função além demain— até aqui, tudo era resolvido dentro de um únicomain.
| ⏱️ Tempo estimado | 📦 Você vai entregar | ✅ Pronto quando |
|---|---|---|
| 50 min | main.c |
./app 10 20 gera os dois relatórios e ./app sozinho falha com código 1 |
main.static dentro de uma função para manter um estado que persiste entre chamadas — algo que uma variável local comum não consegue fazer.argc/argv, convertê-los com atof, e validar a quantidade de argumentos antes de usá-los.Construa uma pequena biblioteca matemática (main.c) com três funções:
double media(double a, double b) — devolve a média aritmética de a e b.double potencia(double base, int expoente) — devolve base elevado a expoente, calculado com um laço for interno (sem usar <math.h>/pow()).void relatorio(double a, double b, double valor_media, double valor_potencia) — imprime um relatório formatado e usa uma variável static int chamadas interna à própria função para contar e exibir quantas vezes relatorio já foi chamada desde o início do programa.O main recebe dois números pela linha de comando (argc/argv), convertidos com atof. Se o programa for executado sem os dois argumentos necessários, ele deve imprimir uma mensagem de uso em stderr e retornar EXIT_FAILURE — sem tentar acessar argv além do que foi fornecido.
| ID | Requisito |
|---|---|
| RF01 | O programa deve compilar sem nenhum aviso com gcc -Wall -Wextra -Wpedantic -std=c17. |
| RF02 | Deve conter #include <stdio.h> e #include <stdlib.h>, usar int main(int argc, char *argv[]) e terminar com return EXIT_SUCCESS; ou return EXIT_FAILURE;. |
| RF03 | Deve declarar pelo menos 3 funções com protótipo antes de main: media, potencia e relatorio. |
| RF04 | Se argc for menor que 3 (nome do programa + 2 números), deve imprimir a forma de uso em stderr com fprintf e retornar EXIT_FAILURE imediatamente. |
| RF05 | Deve converter argv[1] e argv[2] para double usando atof. |
| RF06 | potencia deve calcular o resultado com um laço for (sem <math.h>). |
| RF07 | relatorio deve usar static int chamadas para contar e exibir o número da chamada atual, demonstrando que o valor persiste entre invocações. |
| RF08 | O programa deve funcionar corretamente ao ser executado como ./app 10 20. |
graph LR
A["main(argc, argv)"] --> B{"argc < 3?"}
B -->|Sim| C["fprintf(stderr, uso) + EXIT_FAILURE"]
B -->|Nao| D["atof(argv[1]), atof(argv[2])"]
D --> E["media(a, b)"]
D --> F["potencia(b, 2)"]
E --> G["relatorio(...) 1a chamada"]
F --> G
G --> H["static int chamadas = 1"]
G --> I["relatorio(...) 2a chamada"]
I --> J["static int chamadas = 2"]
style G fill:#0284c7,stroke:#38bdf8,color:#ffffff
style I fill:#0d9488,stroke:#2dd4bf,color:#ffffff
style C fill:#dc2626,stroke:#f87171,color:#ffffff
O mesmo do Miniprojeto 01: gcc 8 ou mais novo. No Windows, rode chcp 65001 se os emojis aparecerem quebrados.
🎯 Objetivo: partir de um código que compila e roda, antes de escrever qualquer linha.
⌨️ Faça: crie a pasta c_mini_08, salve o código abaixo como main.c e rode:
gcc -Wall -Wextra -Wpedantic -std=c17 main.c -o app
./app # Linux/macOS
.\app.exe # Windows (PowerShell)
📄 src/esqueleto.c
/*
* Miniprojeto 08: Biblioteca Modular de Matematica com argc/argv
* Regra: funcoes com prototipo, argc/argv, static (Capitulo 08).
*/
#include <stdio.h>
#include <stdlib.h>
// TODO 1: declare os protótipos das tres funcoes:
// double media(double a, double b);
// double potencia(double base, int expoente);
// void relatorio(double a, double b, double valor_media, double valor_potencia);
int main(int argc, char *argv[]) {
// Ponto de partida: mostra o que chegou pela linha de comando
printf("Argumentos recebidos: %d\n", argc - 1);
if (argc > 1) {
printf("Primeiro argumento: %s\n", argv[1]);
}
// TODO 2: se argc < 3, imprima a forma de uso com fprintf(stderr, ...)
// e retorne EXIT_FAILURE
// TODO 3: converta argv[1] e argv[2] para double usando atof
// TODO 4: chame media(...) e potencia(...) e guarde os resultados em variaveis
// TODO 5: chame relatorio(...) pelo menos duas vezes com dados diferentes,
// para observar o contador static incrementando entre as chamadas
return EXIT_SUCCESS;
}
// TODO 6: implemente double media(double a, double b)
// (retorna (a + b) / 2.0)
// TODO 7: implemente double potencia(double base, int expoente)
// usando um "for" interno que multiplica um acumulador "resultado" por "base"
// "expoente" vezes, comecando de resultado = 1.0
// TODO 8: implemente void relatorio(double a, double b, double valor_media, double valor_potencia)
// com "static int chamadas = 0;" declarada dentro da funcao,
// incrementando a cada chamada e imprimindo o numero da chamada atual
✅ Checkpoint: zero avisos do gcc, e a saída é:
🖥️ Saída esperada:
Argumentos recebidos: 2
Primeiro argumento: 10
⚠️ A saída acima é a de ./app 10 20 (.\app.exe 10 20 no Windows). Os números depois do nome do programa chegam ao main em argv. Rode também ./app sozinho: deve aparecer Argumentos recebidos: 0.
argc (TODO 1 e 2)🎯 Objetivo: declarar as funções antes de usá-las e nunca acessar um argv[i] que não existe.
⌨️ Faça:
#include, declare os 3 protótipos (media, potencia, relatorio).main, se argc < 3, imprima a forma de uso com fprintf(stderr, "Uso: %s <numero1> <numero2>\n", argv[0]); e return EXIT_FAILURE;.Argumentos recebidos e Primeiro argumento do esqueleto.✅ Checkpoint: ./app sozinho imprime o uso e echo $? (ou echo $LASTEXITCODE) mostra 1. ./app 10 20 não imprime nada ainda, e o código de retorno é 0.
🧯 Se der errado: implicit declaration of function 'media' → faltou o protótipo, ou ele está depois do main. Em C17 uma função precisa ser declarada antes do primeiro uso.
media e potencia (TODO 3, 4, 6 e 7)🎯 Objetivo: escrever funções puras que recebem cópias dos argumentos e devolvem um valor.
⌨️ Faça:
double numero1 = atof(argv[1]); e o mesmo para numero2.media (return (a + b) / 2.0;) e potencia, com um for que multiplica um acumulador resultado = 1.0 por base, expoente vezes.main, guarde media(numero1, numero2) e potencia(numero2, 2) em variáveis e, por enquanto, imprima as duas.✅ Checkpoint: ./app 10 20 mostra 15.00 e 400.00.
🧯 Se der errado: atof devolve 0.0 quando o texto não é número. ./app dez 20 dá média 10.00 sem erro nenhum. Validar isso exige strtod, assunto do Desafio.
relatorio com contador static (TODO 5 e 8)🎯 Objetivo: ver uma variável local que não é recriada a cada chamada.
⌨️ Faça: implemente relatorio com static int chamadas = 0; no topo, incremente a cada chamada e imprima Relatorio #%d seguido dos 4 valores. No main, troque os printf do passo anterior por duas chamadas: uma com (numero1, numero2, ...) e outra com os números trocados, recalculando media e potencia para a ordem nova.
✅ Checkpoint: aparecem Relatorio #1 e Relatorio #2. No segundo, b = 10.00 e potencia(b, 2) = 100.00.
🧯 Se der errado: se os dois relatórios dizem #1, faltou o static: sem ele, chamadas volta a 0 em toda chamada.
🎯 Objetivo: validar a saída completa e o código de retorno.
Rode ./app 10 20 (.\app.exe 10 20 no Windows).
✅ Checkpoint: a saída é esta, e o código de retorno é 0 (echo $? no Linux/macOS ou echo $LASTEXITCODE no PowerShell):
🖥️ Saída esperada:
---------------------------------------------
Relatorio #1 (chamada persistente via static)
a = 10.00 | b = 20.00
media(a,b) = 15.00
potencia(b, 2) = 400.00
---------------------------------------------
---------------------------------------------
Relatorio #2 (chamada persistente via static)
a = 20.00 | b = 10.00
media(a,b) = 15.00
potencia(b, 2) = 100.00
---------------------------------------------
Só abra o gabarito depois de chegar até aqui:
src/main.c📄 src/main.c
/*
* Miniprojeto 08: Biblioteca Modular de Matematica com argc/argv
* Especializacao em Engenharia de Sistemas em C
* Regra: funcoes com prototipo, argc/argv, static (Capitulo 08).
*/
#include <stdio.h>
#include <stdlib.h>
double media(double a, double b);
double potencia(double base, int expoente);
void relatorio(double a, double b, double valor_media, double valor_potencia);
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "Uso: %s <numero1> <numero2>\n", argv[0]);
fprintf(stderr, "Exemplo: %s 10 20\n", argv[0]);
return EXIT_FAILURE;
}
double numero1 = atof(argv[1]);
double numero2 = atof(argv[2]);
double valor_media = media(numero1, numero2);
double valor_potencia = potencia(numero2, 2);
relatorio(numero1, numero2, valor_media, valor_potencia);
// Segunda chamada com os numeros trocados: o contador static passa a 2
relatorio(numero2, numero1, media(numero2, numero1), potencia(numero1, 2));
return EXIT_SUCCESS;
}
double media(double a, double b) {
return (a + b) / 2.0;
}
double potencia(double base, int expoente) {
double resultado = 1.0;
for (int i = 0; i < expoente; i++) {
resultado = resultado * base;
}
return resultado;
}
void relatorio(double a, double b, double valor_media, double valor_potencia) {
static int chamadas = 0;
chamadas = chamadas + 1;
printf("---------------------------------------------\n");
printf("Relatorio #%d (chamada persistente via static)\n", chamadas);
printf(" a = %.2f | b = %.2f\n", a, b);
printf(" media(a,b) = %.2f\n", valor_media);
printf(" potencia(b, 2) = %.2f\n", valor_potencia);
printf("---------------------------------------------\n");
}
Por que isso importa: a variável chamadas é declarada com static dentro de relatorio, não em main nem fora de qualquer função. Isso significa que ela é inicializada uma única vez (com 0, na primeira execução do programa) e preserva seu valor entre chamadas — algo que uma variável local comum (int chamadas = 0; sem static) jamais conseguiria, pois seria recriada do zero a cada chamada. Repare também que media, potencia e relatorio recebem cópias dos valores passados (passagem por valor): alterar a ou b dentro de qualquer uma dessas funções nunca afetaria numero1 ou numero2 em main.
Adicione uma quarta função double soma_quadrados(double a, double b) que devolve a² + b² (reaproveitando potencia duas vezes) e imprima o resultado no relatório. Se quiser ir além: aceite um terceiro argumento opcional argv[3] como o expoente de potencia() em vez do valor fixo 2 — sempre validando argc >= 4 antes de acessar argv[3], para nunca ler memória fora dos limites do array de argumentos.
✅ Checkpoint: com ./app 3 4, a soma dos quadrados é 25.00. Com ./app 2 3 5, potencia(3, 5) dá 243.00.
Extra: troque atof por strtod(argv[1], &fim) e recuse com EXIT_FAILURE quando *fim != '\0', ou seja, quando sobrou texto que não é número.
📋 Projetos do curso de C | 📚 Teoria do Capítulo 08 | 🗂️ Hub de projetos