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.
(a) Pergunte se o usuário quer cadastrar uma nova peça;
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;
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:
- Perguntar ao usuário se ele quer cadastrar uma nova peça.
- 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.
- 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.).
- Vou considerar:
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
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.
- Definir uma struct chamada
- Fórmulas (explicando cada variável):
-
. - quantidade: número de unidades no estoque (inteiro).
- custo_por_peca: custo unitário (double).
-
. -
. -
. -
. - 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.
- calcula e imprime, para cada peça e somando totais:
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
. - Compile com:
- Execute com:
- 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>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define INITIAL_CAPACITY 8
#define MAX_LINE 256
#define MAX_PART_NUMBER 64
#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;
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;
}
}
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);
}
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”);
}
}
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;
}
}
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 = ‘.’;
}
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;
}
}
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;
}
}
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;
}
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);
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");
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;
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;
}