Desenvolva o projeto descrito a seguir:
  • Dado o struct Peças com os seguintes campos:
  • part_number - número da peça;
  • quantidade - quantidade de peças no estoque;
  • custo_por_peça - custo por peça;
  • preco_varejo - preço cobrado por peça no varejo;
  • preco_atacado - preço da peça no atacado;
  • Faça um script para cadastrar peças:
    (a) Pergunte se o usuário quer cadastrar uma nova peça;
  • Caso o usuário opte por sim:
    i. Peça para o usuário preencher cada um dos campos do struct Peças - tente proteger o código contra inserções erradas;
    ii. Volte para o passo 2a;
  • Caso o usuário opte por não cadastrar uma nova peça, imprima toda a lista de peças do array de struct junto com as seguintes informações;
  • Custo total por peça;
  • Lucro bruto e líquido para a venda do estoque no varejo ou atacado.
  • Quebre o código em funções sempre que achar pertinente.

Passo 1

O enunciado pede um script que permita cadastrar várias peças (cada peça é um registro com campos) e, quando o usuário parar de cadastrar, imprima a lista completa com alguns cálculos. Vou listar claramente o que temos e o que é pedido:
  • Campos do registro (struct Peças) que o programa deve usar:
    • part_number — número (ou código) da peça (texto);
    • quantidade — quantidade de peças no estoque (inteiro);
    • custo_por_peça — custo por peça (valor numérico, ex.: R$);
    • preco_varejo — preço cobrado por peça no varejo (valor numérico);
    • preco_atacado — preço cobrado por peça no atacado (valor numérico).
  • O fluxo exigido:
    1. Perguntar ao usuário se ele quer cadastrar uma nova peça.
    2. Se sim:
      • pedir cada campo do struct para aquela peça;
      • tentar proteger o código contra inserções erradas (validação dos dados);
      • voltar para a pergunta se quer cadastrar nova peça.
    3. Se não:
      • imprimir toda a lista de peças cadastradas;
      • para cada peça, mostrar:
        • custo total por peça (ou seja, custo total do estoque daquela peça);
        • lucro bruto e lucro líquido para a venda do estoque no varejo;
        • lucro bruto e lucro líquido para a venda do estoque no atacado.
  • Observações importantes (decididas para remover ambiguidade e para implementar o cálculo do lucro):
    • Vou considerar:
      • custo_total = quantidade * custo_por_peça.
      • receita_varejo = quantidade * preco_varejo.
      • receita_atacado = quantidade * preco_atacado.
      • lucro_bruto = receita - custo_total.
      • lucro_liquido = lucro_bruto - impostos - despesas; para isso pedirei ao usuário uma taxa de imposto (%) e uma taxa de despesas/outras (%) a aplicar sobre a receita (esses percentuais serão aplicados sobre a receita, e o programa permite que o usuário informe os percentuais; se o usuário quiser, pode colocar 0).
    • Todas as validações serão feitas para evitar entradas inválidas (números negativos, entradas não numéricas, códigos duplicados, strings vazias etc.).

Passo 2

Escolha da linguagem e do método / estrutura geral do programa (por que assim):
  • Vou implementar em linguagem C:
    • o enunciado usa a palavra “struct Peças”, então C é uma escolha natural que ilustra bem structs e manipulação de arrays dinâmicos;
    • dá para mostrar claramente funções separadas (validação, leitura, impressão), como foi pedido.
  • Estrutura geral do programa:
    • Definir uma struct chamada \texttt{Peca} com os campos pedidos.
    • Usar um array dinâmico (realloc) para armazenar as peças cadastradas (cresce conforme o usuário cadastra).
    • Criar funções para:
      • ler uma linha de entrada com segurança;
      • ler int/double com validação (tratando entradas inválidas e repetindo o pedido até o usuário digitar certo);
      • ler resposta sim/não;
      • cadastrar (preencher) uma peça e checar duplicatas de part_number;
      • imprimir o relatório final com os cálculos de custo_total, lucro_bruto e lucro_liquido.
  • Fórmulas (explicando cada variável):
    • \text{custo\_total} = \text{quantidade} \times \text{custo\_por\_peça}ç.
      • quantidade: número de unidades no estoque (inteiro).
      • custo_por_peca: custo unitário (double).
    • \text{receita\_varejo} = \text{quantidade} \times \text{preco\_varejo}.
    • \text{receita\_atacado} = \text{quantidade} \times \text{preco\_atacado}.
    • \text{lucro\_bruto} = \text{receita} - \text{custo\_total}.
    • \text{lucro\_liquido} = \text{lucro\_bruto} - (\text{taxa\_impostos} \times \text{receita}) - (\text{taxa\_despesas} \times \text{receita}).
      • taxa_impostos e taxa_despesas são percentuais informados pelo usuário (por ex., 10% -> 0,10).

Passo 3

Detalhamento das funções que o programa terá (cada uma com propósito e breve justificativa):
  • read_line(char *buf, size_t size):
    • lê uma linha inteira de stdin usando fgets, remove o newline final.
    • por que: evita problemas com scanf e permite ler strings com espaços.
  • to_lower_str(char *s):
    • converte string para minúsculas para comparar respostas sim/não.
  • read_yes_no(const char *prompt):
    • pergunta algo do tipo "Deseja cadastrar nova peça? (s/n): " e aceita respostas como “s”,“sim”,“n”,“nao”,“não” (só checa a primeira letra).
    • repete enquanto não entrar algo válido.
  • read_int(const char *prompt, int min_allowed):
    • pede um inteiro, checa se a conversão foi bem-sucedida e se está >= min_allowed.
    • usa strtol para detectar entradas não-numéricas.
    • repete até entrada válida.
  • read_double(const char *prompt, double min_allowed):
    • pede um número real, aceita tanto ponto quanto vírgula como separador (troca vírgula por ponto antes de parse).
    • usa strtod para conversão com validação.
    • repete até entrada válida e >= min_allowed.
  • read_string_nonempty(const char *prompt, char *dest, size_t size):
    • pede uma string não vazia; repete se o usuário só apertar ENTER.
  • add_peca(Peca **arr, size_t *n, size_t *cap):
    • lê os campos da peça com as funções de leitura;
    • verifica se part_number já existe (evitar duplicata); se existir, informa e pede outro código;
    • expande o array dinamicamente se necessário.
  • print_report(Peca *arr, size_t n, double tax_rate, double overhead_rate):
    • calcula e imprime, para cada peça e somando totais:
      • custo_total, receita_varejo, lucro_bruto_varejo, lucro_liquido_varejo;
      • receita_atacado, lucro_bruto_atacado, lucro_liquido_atacado.
    • formata números com duas casas decimais para ficar legível.
Por que validar entradas dessa forma?
  • Entrada do usuário é sempre sujeita a erro (teclar letras onde se pergunta número, esquecer valor, digitar negativo). Validar e repetir o pedido melhora robustez e evita que o programa “quebre” na prova/uso.
  • Usar fgets + strtod/strtol é mais seguro que scanf direto, porque permite detectar conversões inválidas e controlar buffer.

Passo 4

Como proteger contra inserções erradas (algumas técnicas práticas explicadas):
  • Para inteiros: ler a linha inteira, usar strtol e checar se o ponteiro de finalização aponta para o fim da string (ou apenas espaços). Isso garante que entrada como “12abc” seja rejeitada.
  • Para doubles: mesmo procedimento com strtod; antes substituir vírgula por ponto para aceitar “10,5”.
  • Para strings (part_number): recusar string vazia; opcionalmente limitar o tamanho.
  • Para duplicatas de part_number: percorrer o array e comparar strings; se encontrar igual, pedir outro.
  • Para percentuais (impostos/despesas): exigir valores entre 0 e 100 (aceitar 0), depois converter para fração (dividir por 100) no cálculo.
  • Mensagens de erro claras e repetir até o usuário acertar.

Passo 5

Exemplo de uso / comportamento do programa (o que o usuário verá):
  • Programa pergunta: "Deseja cadastrar uma nova peça? (s/n): "
  • Se o usuário digitar ‘s’:
    • Pergunta: "Código da peça (part_number): "
    • Pergunta: "Quantidade no estoque: " (só aceita inteiro >= 0)
    • Pergunta: "Custo por peça: " (só aceita >= 0)
    • Pergunta: "Preço varejo: "
    • Pergunta: "Preço atacado: "
    • Volta para a pergunta inicial.
  • Se usuário digitar ‘n’:
    • Pergunta "Informe taxa de imposto (%) (por exemplo 10 para 10%): "
    • Pergunta "Informe taxa de despesas/overhead (%) (por exemplo 5): "
    • Imprime uma tabela com cada peça e os cálculos (custo_total, receita, lucro_bruto, lucro_liquido) e também os totais agregados.
  • Esse modo permite o usuário controlar as taxas para cálculo do lucro líquido.

Passo 6

Instruções rápidas de compilação e execução (C):
  • Salve o código em um arquivo, por exemplo \texttt{controle_pecas.c}.
  • Compile com: \texttt{gcc -std=c11 -O2 -o controle_pecas controle_pecas.c}
  • Execute com: \texttt{./controle_pecas}
  • Dica amistosa: se der algum erro de compilação, verifique mensagens do compilador; posso ajudar a ajustar.

Passo 7

Empurrão final de ânimo antes do código:
  • Tá bom, sei que tem prova chegando e isso parece muita coisa, mas com esse script você tem um exemplo claro de como estruturar dados com structs, validar entrada e fazer cálculos financeiros simples. Respira, copia o código, compila, testa com alguns registros — e se algo não rodar, me mostra o erro que eu te ajudo a consertar rapidinho. Vamos nessa!

Resposta

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define INITIAL_CAPACITY 8
#define MAX_LINE 256
#define MAX_PART_NUMBER 64
typedef struct {
char part_number[MAX_PART_NUMBER];
int quantidade;
double custo_por_peca;
double preco_varejo;
double preco_atacado;
} Peca;
/* Lê uma linha de stdin, remove newline final */
static void read_line(char buf, size_t size) {
while (1) {
if (!fgets(buf, (int)size, stdin)) {
/
EOF, garantir string vazia /
buf[0] = ‘\0’;
return;
}
/
remover newline /
size_t len = strlen(buf);
if (len > 0 && buf[len-1] == ‘\n’) buf[len-1] = ‘\0’;
/
aceitar a linha (pode ser vazia) */
return;
}
}
/* converte string para minúsculas in-place */
static void to_lower_str(char *s) {
for (; *s; ++s) *s = (char)tolower((unsigned char)*s);
}
/* pergunta sim/não e retorna 1 para sim, 0 para não */
static int read_yes_no(const char prompt) {
char buf[MAX_LINE];
while (1) {
printf("%s", prompt);
read_line(buf, sizeof(buf));
if (buf[0] == ‘\0’) {
printf(“Resposta vazia. Digite ‘s’ para sim ou ‘n’ para não.\n”);
continue;
}
to_lower_str(buf);
/
aceitar “s”, “sim”, “n”, “nao”, “não” */
if (buf[0] == ‘s’) return 1;
if (buf[0] == ‘n’) return 0;
printf(“Resposta inválida. Digite ‘s’ para sim ou ‘n’ para não.\n”);
}
}
/* lê inteiro com validação (valor mínimo permitido) */
static int read_int(const char *prompt, int min_allowed) {
char buf[MAX_LINE];
char endptr;
long val;
while (1) {
printf("%s", prompt);
read_line(buf, sizeof(buf));
if (buf[0] == ‘\0’) {
printf(“Entrada vazia. Por favor digite um número inteiro.\n”);
continue;
}
/
usar strtol para detectar erros /
val = strtol(buf, &endptr, 10);
/
pular espaços depois */
while (*endptr == ’ ’ || *endptr == ‘\t’) endptr++;
if (*endptr != ‘\0’) {
printf(“Entrada inválida. Digite um número inteiro válido.\n”);
continue;
}
if (val < min_allowed) {
printf(“Valor deve ser maior ou igual a %d.\n”, min_allowed);
continue;
}
return (int)val;
}
}
/* troca vírgula por ponto para aceitar “10,5” */
static void comma_to_dot(char *s) {
for (; *s; ++s) if (*s == ‘,’) *s = ‘.’;
}
/* lê double com validação (valor mínimo permitido) */
static double read_double(const char *prompt, double min_allowed) {
char buf[MAX_LINE];
char *endptr;
double val;
while (1) {
printf("%s", prompt);
read_line(buf, sizeof(buf));
if (buf[0] == ‘\0’) {
printf(“Entrada vazia. Por favor digite um número.\n”);
continue;
}
comma_to_dot(buf);
val = strtod(buf, &endptr);
while (*endptr == ’ ’ || *endptr == ‘\t’) endptr++;
if (*endptr != ‘\0’) {
printf(“Entrada inválida. Digite um número válido (ex: 12.50).\n”);
continue;
}
if (val < min_allowed) {
printf(“Valor deve ser maior ou igual a %.2f.\n”, min_allowed);
continue;
}
return val;
}
}
/* lê string não vazia */
static void read_string_nonempty(const char *prompt, char dest, size_t size) {
char buf[MAX_LINE];
while (1) {
printf("%s", prompt);
read_line(buf, sizeof(buf));
/
remover espaços extremos (simples) */
char *start = buf;
while (*start == ’ ’ || *start == ‘\t’) start++;
if (start == ‘\0’) {
printf(“Valor não pode ser vazio. Tente novamente.\n”);
continue;
}
/
copiar truncando se necessário */
strncpy(dest, start, size-1);
dest[size-1] = ‘\0’;
return;
}
}
/* verifica se existe part_number duplicado */
static int existe_part_number(Peca *arr, size_t n, const char *part) {
for (size_t i = 0; i < n; ++i) {
if (strcmp(arr[i].part_number, part) == 0) return 1;
}
return 0;
}
/* adiciona uma peça ao array dinâmico, pedindo os campos ao usuário */
static void add_peca(Peca **parr, size_t *pn, size_t pcap) {
Peca temp;
/
ler part_number garantindo que não é duplicado */
while (1) {
read_string_nonempty("Código da peça (part_number): ", temp.part_number, sizeof(temp.part_number));
if (existe_part_number(*parr, *pn, temp.part_number)) {
printf(“Código já cadastrado. Digite outro código ou verifique a lista.\n”);
continue;
}
break;
}
temp.quantidade = read_int("Quantidade no estoque (inteiro >= 0): ", 0);
temp.custo_por_peca = read_double("Custo por peça (ex: 12.50): ", 0.0);
temp.preco_varejo = read_double("Preço no varejo (ex: 20.00): ", 0.0);
temp.preco_atacado = read_double("Preço no atacado (ex: 15.00): ", 0.0);
/* expandir array se necessário */
if (*pn >= *pcap) {
    size_t newcap = (*pcap == 0) ? INITIAL_CAPACITY : (*pcap * 2);
    Peca *tmp = realloc(*parr, newcap * sizeof(Peca));
    if (!tmp) {
        fprintf(stderr, "Erro de memória. Saindo.\n");
        exit(EXIT_FAILURE);
    }
    *parr = tmp;
    *pcap = newcap;
}
/* adicionar */
(*parr)[*pn] = temp;
(*pn)++;
printf("Peça cadastrada com sucesso!\n\n");
}
/* imprime relatório com cálculos */
static void print_report(Peca *arr, size_t n, double tax_rate, double overhead_rate) {
if (n == 0) {
printf(“Nenhuma peça cadastrada. Nada a imprimir.\n”);
return;
}
printf("\n— RELATÓRIO DE PEÇAS —\n\n");
printf("%-12s %-10s %-12s %-12s %-12s %-12s %-12s\n",
“part_number”, “qtd”, “custo_total”, “rec_varejo”, “luc_br_vare”, “luc_liq_vare”, “rec_atacado”);
printf("--------------------------------------------------------------------------------------------------------\n");
double total_custo = 0.0;
double total_receita_varejo = 0.0;
double total_receita_atacado = 0.0;
double total_luc_br_varejo = 0.0;
double total_luc_liq_varejo = 0.0;
double total_luc_br_atacado = 0.0;
double total_luc_liq_atacado = 0.0;

for (size_t i = 0; i < n; ++i) {
    Peca *p = &arr[i];
    double custo_total = p->quantidade * p->custo_por_peca;
    double receita_varejo = p->quantidade * p->preco_varejo;
    double receita_atacado = p->quantidade * p->preco_atacado;
    double luc_br_varejo = receita_varejo - custo_total;
    double luc_br_atacado = receita_atacado - custo_total;
    double luc_liq_varejo = luc_br_varejo - (tax_rate * receita_varejo) - (overhead_rate * receita_varejo);
    double luc_liq_atacado = luc_br_atacado - (tax_rate * receita_atacado) - (overhead_rate * receita_atacado);

    printf("%-12s %-10d %-12.2f %-12.2f %-12.2f %-12.2f %-12.2f\n",
           p->part_number,
           p->quantidade,
           custo_total,
           receita_varejo,
           luc_br_varejo,
           luc_liq_varejo,
           receita_atacado);

    total_custo += custo_total;
    total_receita_varejo += receita_varejo;
    total_receita_atacado += receita_atacado;
    total_luc_br_varejo += luc_br_varejo;
    total_luc_liq_varejo += luc_liq_varejo;
    total_luc_br_atacado += luc_br_atacado;
    total_luc_liq_atacado += luc_liq_atacado;
}
printf("--------------------------------------------------------------------------------------------------------\n");
printf("TOTALS:\n");
printf("Custo total do estoque: R$ %.2f\n", total_custo);
printf("Receita total (varejo): R$ %.2f\n", total_receita_varejo);
printf("Lucro bruto total (varejo): R$ %.2f\n", total_luc_br_varejo);
printf("Lucro líquido total (varejo): R$ %.2f\n", total_luc_liq_varejo);
printf("\n");
printf("Receita total (atacado): R$ %.2f\n", total_receita_atacado);
printf("Lucro bruto total (atacado): R$ %.2f\n", total_luc_br_atacado);
printf("Lucro líquido total (atacado): R$ %.2f\n", total_luc_liq_atacado);
printf("\n--- FIM DO RELATÓRIO ---\n");
}
int main(void) {
Peca *arr = NULL;
size_t n = 0, cap = 0;
printf("Sistema de cadastro de peças\n");
printf("---------------------------\n");

while (1) {
    int quer = read_yes_no("Deseja cadastrar uma nova peça? (s/n): ");
    if (!quer) break;
    add_peca(&arr, &n, &cap);
}

if (n == 0) {
    printf("Nenhuma peça cadastrada. Encerrando.\n");
    free(arr);
    return 0;
}

/* Ler taxas (em %) e converter para fração */
double imposto_perc = read_double("Informe taxa de imposto (%) (ex: 10 para 10%): ", 0.0);
double despesa_perc = read_double("Informe taxa de despesas/overhead (%) (ex: 5 para 5%): ", 0.0);
double tax_rate = imposto_perc / 100.0;
double overhead_rate = despesa_perc / 100.0;

print_report(arr, n, tax_rate, overhead_rate);

free(arr);
return 0;
}

Exercícios relacionados