「C语言」超市收银管理系统

1 问题简介

设计项目名:超市收银管理系统
要求采用结构体数组存放商品数据,采用列表形式显示多行数据,界面显示的内容简明直观。标有“选做项”字样的功能,可以根据自己的能力选择是否完成,其他均为必做项。
项目功能说明:系统管理员对该系统具有最高权限,能进行商品的增删、折扣设置、查询、收银等操作。其中积分兑换与抽奖功能为选做项。主菜单如下:

-----------------
1、开始收银
2、增删商品
3、设置折扣
4、查询
5、积分兑换与抽奖(选做)
6、统计
0 退出系统
-----------------

1.1 收银功能

导入商品信息(data.txt),显示商品编号和名称。操作流程:输入商品代号、购买数量进行收银,若购买某种商品的数量大于库存,则显示“库存不足”,反之,自动生成订单编号,并显示购买信息,并提示“是否继续购买”。最后输入金额结束本单收银。

1.2 增删商品信息

可以对导入的商品信息进行删除,或添加商品信息。
操作流程:输入商品编号→查询信息→显示查询结果→增或删操作→显示操作的结果,并更新商品文件信息,以便下次导入使用。
二级菜单

----------------
1 增加商品信息(选做)
2 删除商品信息
3 编辑商品信息
4 显示所有商品信息
0 返回主菜单
----------------

1.3 设置折扣

可以对导入的商品的折扣进行修改。
操作流程:输入商品编号→查询信息→显示查询结果→修改折扣→显示操作的结果,并更新商品文件信息,以便下次导入使用。

1.4 查询与显示

可按编号或商品名称查询商品信息,也能按订单编号查询订单详情。
二级菜单

--------------------------------
1 查询商品(按编号)
2 查询商品(按名称)
3 查询订单(按编号)
0 返回主菜单
--------------------------------

1.5 积分兑换与抽奖(选做项)

该功能为选做项。导入会员积分信息,显示用户的积分值(购物花10元得1积分),可进行积分兑换成商品(1积分可当1元使用)或积分兑换抽奖(10积分换取1次抽奖机会,抽奖内容自定)。
xxx用户当期积分值:xxxx
可兑换x元的商品或兑换成x次抽奖

--------------
1 积分兑换
2 积分抽奖
0 返回主菜单
--------------

1.6 统计

统计功能包含以下3个功能,其中“3 统计销售量TOP3”为选做项

--------------
1显示全部订单
2 统计总销售额
3 统计销售量TOP3(选做)
0 返回主菜单
--------------

2 核心代码

2.1 结构体定义

  1. 商品类型
typedef struct
{
    int id;
    char name[30];   // 商品名
    char unit[5];    // 商品单位
    double cost;     // 成本
    double price;    // 商品价格
    double discount; // 折扣
    int stock;       // 存量
    int sale;        // 销售量
} Product;
  1. 订单类型
typedef struct
{
    char id[32];
    int *product; // 购买商品id数组
    int *num;     // 购买商品数量数组
    int size;
    double total;  // 总价
    double profit; // 本单利润
} Order;
  1. 会员类型
typedef struct
{
    char id[16];
    int memberPoint;//积分
} VIP;

2.2 C语言文件流操作

程序需要输入输出进行数据的存储,方便下次使用。
存储商品信息的文件格式:

2
商品代号 商品名称 单位 成本 售价 折扣 库存 销售额
1 抽纸 盒 4.00 5.20 0.90 956 44
2 牛奶 g 66.00 77.00 1.00 490 10

第一行记录商品种类数;
第二行记录数据所对应的含义;
以下每一行记录一种商品信息;

商品信息导入

// 导入商品
int importProduct(const char *path, Product *products)
{
    FILE *fin = fopen(path, "r");
    int num, i;
    char buf[1024];
    if (fin == NULL)
    {
        return 1;
    }
    fgets(buf, 1024, fin);//先获取第一行,即商品种类数
    num = atoi(buf);//atoi将 char* 转为 int 
    i = 0;
    fgets(buf, 1024, fin);//读取第二行,即字段名称,但只需要读出将文件指针下移,不需要其他操作
    while (fscanf(fin, "%d %s %s %lf %lf %lf %d %d", &products[i].id, products[i].name, products[i].unit, &products[i].cost, &products[i].price, &products[i].discount, &products[i].stock, &products[i].sale) != EOF)//判断文件指针是否到文件结尾,fscanf函数进行文件流的格式化输入
    {
        ++i;
    }
    if (fclose(fin) == EOF)//关闭文件
    {
        return 2;
    };
    return 0;
}

商品信息的导出

// 导出商品
int exportProduct(const char *path, Product *products, int num)
{
    FILE *fout = fopen(path, "w");
    if (fout == NULL)
    {
        return 1;
    }
    fprintf(fout, "%d\n", num);//按照上面的文件内容组成,这里先写入商品种类数
    fprintf(fout, "商品代号 商品名称 单位 成本 售价 折扣 库存 销售额\n");//然后写入字段名
    for (int i = 0; i < num; i++)
    {
        fprintf(fout, "%d %s %s %.2lf %.2lf %.2lf %d %d\n", products[i].id, products[i].name, products[i].unit, products[i].cost, products[i].price, products[i].discount, products[i].stock, products[i].sale);//fprintf函数进行文件流格式化输出
    }
    if (fclose(fout) == EOF)//关闭文件
    {
        return 2;
    }
    return 0;
}

2.3 C语言增加数组长度

不论是C语言还是C++,基本的数组类型在定义时就已经确定了数组的长度,后面需要修改数组长度比较麻烦。
需要用到的核心函数是:

void *malloc(size_t size);//开辟一块大小为size的空间
void *realloc(void *ptr, size_t size);//尝试在当前地址上增加长度到size,如果不可行则重新开辟一块大小size的空间,并将*ptr上的数据复制过去(ptr的大小不可为0)

以增加商品为例

// 增加商品
Product *addProduct(Product *products, int num)
{
    Product *newList;//声明一个指针变量
    if (num == 0)//如果原来的长度为0,不可使用realloc函数
    {
        newList = (Product *)malloc(sizeof(Product));//则创建一块空间
        if (!newList)
        {
            return products;
        }
    }
    else//长度不为0
    {
        newList = (Product *)realloc(products, (num + 1) * sizeof(Product));//增加长度
        if (!newList)
        {
            return products;
        }
    }
    Produce_Initial(&newList[num]);//调用商品初始化函数对新开辟的空间初始化
    return newList;//返回这个的空间的地址
}

//在调用时:
Product *productList;//声明
int product_num=0;//长度
//此处省略从文件导入商品...,长度改变
productList = addProduct(productList, product_num);//增加商品

2.4 抽奖(轮盘赌)

轮盘赌即转盘抽奖模型,将轮盘分为 n 份(可不等分),然后扔飞镖,根据飞镖所落在的区域判断中奖。
在计算上,可以处理为:将数轴上长度为 1 的线段分为 n 份,抽取一个随机数,通过判断随机数所在区间来判断中奖。
例:

n1 = 2
n2 = 4
n3 = 6
n4 = 8
将其归一
sum_n = n1 + n2 + n3 + n4 = 20
n1' = n1 / sum_n = 0.1
n2' = n2 / sum_n = 0.2
n3' = n3 / sum_n = 0.3
n4' = n4 / sum_n = 0.4
然后将其布置在数轴 0-1 上:
0---------0.1---------0.3---------0.6---------1
    n1'          n2'         n3'         n4'         --每个区间的含义
    0.1         0.2         0.3         0.4         ------长度

以商品抽奖为例:

// 轮盘赌,制作轮盘
double *probability(Product *products, int len)
{
    double offset = 0.5; // 轮盘概率的偏移量(谢谢惠顾)的占比,值越大中奖概率越低,即在轮盘上“谢谢回顾”已经占了 offset 的区域
    double pricesum = 0;//计算商品总价格(每种商品各一件)
    double sum = 0;
    double *prob = (double *)malloc((len + 1) * sizeof(double)); // 概率数组
    for (int i = 0; i < len; i++) // 计算商品总价格
    {
        pricesum += products[i].price;
    }
    double sumprob = 0;
    for (int i = 0; i < len; i++)//原本是 商品价格 / 总价,即可得出各个商品的价格占总价格的分量,价格越高其概率越大。
    //但是抽奖时,商家肯定是希望价格越高的商品中奖的概率越低,所以在 商品价/总价 的基础上,取倒数,(暂且称为“概率倒数”吧)即可让最大的概率变最小的概率,最小的概率变最大的概率
    {
        sumprob += pricesum / products[i].price;//计算这些概率倒数的总和,方便归一化
    }
    for (int i = 0; i < len; i++) // 制作轮盘// 反转概率,价格越高的商品中奖概率越低
    {
        sum += (pricesum / products[i].price) / sumprob * (1 - offset);//乘(1-offset),是因为“谢谢惠顾”已经占有了offset的概率,剩下的(1-offset)由各个商品按“概率的倒数”瓜分
        prob[i] = sum;//将概率布置到数轴上
    }
		//全部商品的概率已经布置在数轴上了,此时prob[len-1] = 1-offset
    prob[len] = 1;//将“谢谢惠顾”的概率布置到数轴上,即从 1-offset 到 1 的区间为不中奖
    return prob;
}
//布置好轮盘后,进行轮盘赌
// 轮盘赌
int roulette(Product *products, int len)
{
    srand(time(NULL));
    double num = (rand() % 1000) / 1000.0;//获取随机小数
    double *prob = probability(products, len);//制作轮盘
    for (int i = 0; i < len; i++)//遍历对比,找到随机数所在的区间
    {
        if (num <= prob[i])
        {
            return i;//确定中奖商品
        }
    }
    return -1;
}

其余功能简单且重复,不再赘述。

  • 3
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

武的阶乘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值