C语言+MySQL学生管理系统课程设计实战项目

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本项目“C语言+MySQL学生管理系统课程设计实战项目”基于C语言、MySQL数据库和Visual Studio开发环境,构建了一个面向管理员、教师和学生的多功能学生成绩与信息管理系统。系统涵盖宿舍管理、学生管理、班级管理等核心模块,支持用户权限分级控制,具备数据增删改查、成绩录入分析、信息导出备份等功能。项目融合数据库设计与软件工程实践,适用于数据库课程设计学习与教学管理场景,帮助开发者掌握数据库连接、SQL操作及C语言在实际系统开发中的应用。配套说明书和技术支持确保项目可快速部署与使用。

C语言与MySQL构建学生管理系统的全栈实践:从理论到部署的深度解析

在如今动辄“微服务”、“云原生”的技术浪潮中,我们是否还记得那个用几百行C代码就能掌控整个系统运行的时代?🤔 想象一下:没有层层封装的框架、没有复杂的依赖注入,只有一个 main() 函数,一段内存操作,一条SQL语句——但正是这些看似原始的工具,构成了现代信息系统最坚硬的底层基石。

比如你现在正在使用的这台电脑里,操作系统内核、数据库引擎、网络协议栈……有多少是用C写的?答案可能会让你吃惊。而今天我们要讲的故事,就是关于如何 用C语言和MySQL搭建一个完整的学生管理系统 ——不是为了炫技,而是为了理解:当一切抽象都被剥去之后,数据到底是怎么流动的?💻✨


为什么选择C语言来开发数据库应用?

你可能会问:“Python不香吗?Java生态更丰富啊!”确实如此。但在某些场景下,C语言依然是无可替代的选择:

  • 极致性能需求 :嵌入式设备、工业控制系统、高频交易中间件等;
  • 资源受限环境 :内存只有几十MB的老式终端或单片机;
  • 对硬件/内存的精细控制 :比如直接访问寄存器、实现自定义内存池;
  • 学习目的 :想真正搞懂“连接数据库”背后发生了什么?

学生管理系统虽然不算复杂,但它涵盖了增删改查(CRUD)、事务处理、权限校验、数据建模等典型业务逻辑。如果能用C从零实现一遍,你会比90%只会调API的人更懂“系统是如何工作的”。

而且你知道吗?像 MySQL服务器本身 就是用C/C++写的!它的客户端库 Connector/C,也为我们提供了纯C接口,完全可以做到无缝集成。


学生管理系统的核心问题:我们到底要管什么?

别急着写代码,先回答一个问题:一个学生管理系统,本质上是在管理哪些东西?

经过调研你会发现,无论大学还是中小学,核心实体无非三个:

  1. 学生(Student)
  2. 班级(Class)
  3. 宿舍(Dormitory)

这三个对象之间有着清晰又微妙的关系:

  • 一名学生只能属于一个班级 → 一对多
  • 一间宿舍可以住多名学生 → 也是一对多
  • 如果未来加上课程模块,那就会出现“一名学生选修多门课,一门课被多人选” → 多对多

这些关系决定了我们的数据库该怎么设计。但等等……你有没有遇到过这种情况:

“老师让我做个学生系统,我上来就建了张表叫 student_info ,然后往里面疯狂加字段:姓名、年龄、性别、电话、班主任、班级名称、宿舍楼号、房间号……结果后来发现改个班名要把所有学生的记录都更新一遍。”

😅 是不是有点熟悉?这就是典型的“未做数据建模”的后果。

所以第一步,我们必须进行 实体-关系分析(ER Modeling)

让我们分别看看这三个实体该有哪些属性。

🧑‍🎓 学生实体:不只是名字和学号那么简单
字段 类型 是否主键 可空 说明
student_id VARCHAR(15) 学号,全局唯一标识
name VARCHAR(50) 姓名
gender ENUM(‘男’,’女’) 性别
birth_date DATE 出生日期
phone VARCHAR(15) 联系方式
email VARCHAR(100) 邮箱
class_id INT 所属班级ID(外键)
dormitory_id INT 宿舍ID(外键)
enrollment_date DATE 入学时间
status ENUM(‘在读’,’休学’,’毕业’,’退学’) 当前状态

⚠️ 注意: student_id 使用字符串而非自增整数,是因为现实中很多学校的学号包含年级+专业缩写(如 CS2024001)。使用自然主键有利于跨系统对接。

👨‍🏫 班级实体:教学组织的基本单元
字段 类型 是否主键 可空 说明
class_id INT AUTO_INCREMENT 自增主键
class_name VARCHAR(50) 班级全称(如“计算机科学2024级1班”)
grade INT 年级(如2024)
major VARCHAR(50) 专业方向
teacher_id INT 班主任教师ID(外键)
student_count INT DEFAULT 0 当前人数(冗余字段)
created_at DATETIME 创建时间

💡 特别提示: student_count 明明可以通过 COUNT(*) 计算得出,为什么要单独存?

因为如果你经常需要显示每个班有多少人,每次都去扫描全表计算会很慢。这时候引入适度冗余反而能提升性能——只要我们通过 触发器自动维护它的一致性 即可。

🏠 宿舍实体:物理空间的资源配置
字段 类型 是否主键 可空 说明
dormitory_id INT AUTO_INCREMENT 宿舍ID
building VARCHAR(20) 楼栋名(如“A栋”)
room_number VARCHAR(10) 房间号(如“301”)
floor INT 所在楼层
capacity TINYINT 最大入住人数(通常4人)
current_occupancy TINYINT DEFAULT 0 当前已住人数
gender_restriction ENUM(‘男’,’女’,’混合’) 性别限制
manager_id INT 宿管员ID

📌 关键点: building room_number 应建立 联合唯一索引 ,防止重复登记同一房间。

CREATE TABLE Dormitory (
    dormitory_id INT AUTO_INCREMENT PRIMARY KEY,
    building VARCHAR(20) NOT NULL,
    room_number VARCHAR(10) NOT NULL,
    floor INT NOT NULL,
    capacity TINYINT NOT NULL CHECK (capacity > 0),
    current_occupancy TINYINT DEFAULT 0 CHECK (current_occupancy >= 0),
    gender_restriction ENUM('男', '女', '混合') NOT NULL,
    manager_id INT,
    UNIQUE KEY unique_room (building, room_number)
);

🔍 解读:
- 第6行用了 CHECK 约束,确保容量和当前人数合法;
- 最后一行添加了组合唯一键,避免A栋301被录入两次;
- 后续若需支持水电费统计,可在此基础上扩展字段。


实体之间的关系:数据库的灵魂所在

光有表还不够,真正的难点在于 如何表达实体之间的联系

一对多关系的经典实现:外键 + 级联行为

以“班级 ↔ 学生”为例:

  • 一个班级有多个学生 → “一”
  • 一个学生只属于一个班级 → “多”

这种关系的标准做法是:在“多方”表(即 Student )中添加一个指向“一方”表(即 Class )主键的外键。

ALTER TABLE Student 
ADD CONSTRAINT fk_class 
FOREIGN KEY (class_id) REFERENCES Class(class_id)
ON DELETE SET NULL 
ON UPDATE CASCADE;

🧠 参数详解:
- fk_class :约束名,便于后期修改或删除;
- REFERENCES Class(class_id) :指定引用目标;
- ON DELETE SET NULL :删除班级时,相关学生的 class_id 设为NULL,保留学生档案;
- ON UPDATE CASCADE :极少见的情况,如班级ID变更,自动同步更新。

这个设计既保证了引用完整性,又不会因误删班级导致大量学生记录丢失。

多对多关系怎么办?中间表来救场!

假设以后要加“课程”功能,那就不可避免地面对一个经典问题:

一名学生可以选多门课,一门课也可以被多名学生选 —— 这是典型的 多对多关系

但关系型数据库不支持直接建模M:N,必须通过 中间关联表(Junction Table) 拆解成两个1:N。

CREATE TABLE Course (
    course_id INT AUTO_INCREMENT PRIMARY KEY,
    course_name VARCHAR(100) NOT NULL,
    credits TINYINT NOT NULL
);

CREATE TABLE Enrollment (
    enrollment_id INT AUTO_INCREMENT PRIMARY KEY,
    student_id VARCHAR(15) NOT NULL,
    course_id INT NOT NULL,
    semester VARCHAR(20) NOT NULL,
    grade DECIMAL(3,1) DEFAULT NULL,
    FOREIGN KEY (student_id) REFERENCES Student(student_id),
    FOREIGN KEY (course_id) REFERENCES Course(course_id),
    UNIQUE KEY unique_enrollment (student_id, course_id, semester)
);

🔄 看起来复杂?其实很简单:

  • Enrollment 表记录每一次选课;
  • 包含学期信息,支持跨学期重修;
  • (student_id, course_id, semester) 做复合唯一键,防止重复报名。

可视化表示如下:

erDiagram
    STUDENT ||--o{ ENROLLMENT : "选修"
    COURSE ||--o{ ENROLLMENT : "被选"
    STUDENT {
        string student_id PK
        string name
        enum gender
    }
    COURSE {
        int course_id PK
        string course_name
        tinyint credits
    }
    ENROLLMENT {
        int enrollment_id PK
        string student_id FK
        int course_id FK
        string semester
        decimal grade
    }

✅ 图解:
- 左边 STUDENT ENROLLMENT 是一对多;
- 右边 COURSE ENROLLMENT 也是;
- 中间表承载了原始的M:N关系。

这就是数据库设计中的“ 化繁为简 ”思想。


数据库规范化:消灭冗余的艺术

有了初步结构,下一步就是 规范化(Normalization) ——听起来高大上,其实就是一句话: 让每条数据只在一个地方存储,改一次就行

国际标准有五个范式,但我们重点关注前三:

范式 目标
1NF 字段原子化,不可再分
2NF 消除部分函数依赖
3NF 消除传递依赖

举个反面例子你就明白了👇

❌ 错误示范:把班主任名字存在学生表里?

有人图省事,在 Student 表里加个字段叫 teacher_name ,方便显示。结果呢?

  • 班主任换人了,得挨个改几百个学生记录;
  • 不同人拼写不一样,“李老师”、“李明”、“李 敏”混着来;
  • 浪费空间,同一个名字存了几百遍。

💥 更新异常、插入异常、删除异常全来了!

✅ 正确做法是:

  1. Class 表里存 teacher_id
  2. 单独建个 Teacher
  3. 查询时用 JOIN 获取姓名
SELECT 
    s.name AS student_name,
    c.class_name,
    t.name AS teacher_name
FROM Student s
JOIN Class c ON s.class_id = c.class_id
JOIN Teacher t ON c.teacher_id = t.teacher_id;

📌 这样才符合第三范式(3NF):所有非主属性完全依赖于主键,且没有传递依赖。

⚖️ 但是!规范 ≠ 绝对真理

现实世界总有例外。比如前面提到的 student_count 字段,明显违反3NF(因为它可以从其他表推导出来),但我们还是保留了它。

为什么?

因为性能优先。每次查看班级都要执行一次 COUNT(*) ?太慢了!

所以聪明的做法是:

  • 接受适度冗余;
  • 触发器自动维护一致性
DELIMITER $$
CREATE TRIGGER tr_update_class_count_after_insert
AFTER INSERT ON Student
FOR EACH ROW
BEGIN
    UPDATE Class SET student_count = student_count + 1 
    WHERE class_id = NEW.class_id;
END$$
DELIMITER ;

同样地,删除学生时也要减一:

CREATE TRIGGER tr_update_class_count_after_delete
AFTER DELETE ON Student
FOR EACH ROW
BEGIN
    UPDATE Class SET student_count = student_count - 1 
    WHERE class_id = OLD.class_id;
END$$

🎯 结论: 规范化是手段,不是目的 。要在一致性、性能、可维护性之间找到平衡点。


SQL实战:CRUD操作背后的细节陷阱

现在轮到动手了。你以为写个 INSERT INTO ... VALUES ... 就完事了?Too young too simple 😏

🟢 插入新学生:外键检查不能少

INSERT INTO Student (
    student_id, name, gender, birth_date, phone, email, 
    class_id, dormitory_id, enrollment_date, status
) VALUES (
    'CS2024001', '张伟', '男', '2006-03-15', '13800138000', 'zhangwei@edu.cn',
    101, 205, '2024-09-01', '在读'
);

✅ 成功的前提是:
- class_id=101 必须存在于 Class 表;
- dormitory_id=205 必须存在于 Dormitory 表;
否则会抛出外键约束错误。

建议程序中先做有效性校验,再提交SQL。

🔍 查询在读学生:分页别用 OFFSET!

SELECT student_id, name, class_name, building, room_number
FROM Student s
JOIN Class c ON s.class_id = c.class_id
JOIN Dormitory d ON s.dormitory_id = d.dormitory_id
WHERE s.status = '在读'
ORDER BY s.enrollment_date DESC
LIMIT 20 OFFSET 0;

看起来没问题?但如果数据量上万, OFFSET 10000 会导致数据库扫描前10000条再丢弃,极其低效!

✅ 更好的方案是使用 游标分页(Cursor-based Pagination)

-- 记录上次最后一条的时间戳
WHERE s.enrollment_date < '2024-09-01'
ORDER BY s.enrollment_date DESC
LIMIT 20;

效率提升可达数十倍!

🔄 修改宿舍分配:必须加事务!

START TRANSACTION;

UPDATE Student SET dormitory_id = 206 WHERE student_id = 'CS2024001';

UPDATE Dormitory SET current_occupancy = current_occupancy + 1 WHERE dormitory_id = 206;
UPDATE Dormitory SET current_occupancy = current_occupancy - 1 WHERE dormitory_id = 205;

COMMIT;

🛑 如果中途失败,比如第二条成功但第三条失败,就会造成计数错乱!

所以一定要包在事务里,失败就回滚,保持原子性。

🗑️ 删除毕业生:软删除才是王道

DELETE FROM Student WHERE status = '毕业' AND enrollment_date < '2020-01-01';

物理删除风险太大!万一哪天领导说“查一下十年前谁在这儿读过书”,你就傻眼了。

✅ 推荐做法:改为软删除

ALTER TABLE Student ADD COLUMN is_deleted BOOLEAN DEFAULT FALSE;
-- 标记删除
UPDATE Student SET is_deleted = TRUE WHERE ...;
-- 查询时过滤
SELECT * FROM Student WHERE is_deleted = FALSE;

既能释放业务视角的数据,又能保留历史记录。


C语言如何连接MySQL?手把手教你避坑

终于到了编码环节!🎉

要在C程序里操作MySQL,我们需要官方提供的 MySQL Connector/C 库。它是纯C API,轻量高效,适合嵌入式或本地应用。

🔧 开发环境配置(Windows + Visual Studio)

  1. 下载 MySQL Connector/C 的 ZIP 包;
  2. 解压到 C:\mysql-connector-c
  3. 在VS项目中设置:
    - 包含目录 C:\mysql-connector-c\include
    - 库目录 C:\mysql-connector-c\lib
    - 附加依赖项 libmysql.lib
  4. libmysql.dll 放到 .exe 同级目录,否则运行时报错“找不到模块”。

完成配置后,就可以开始写代码啦!

#include <stdio.h>
#include <stdlib.h>
#include "mysql.h"

int main() {
    MYSQL *conn = mysql_init(NULL);
    if (conn == NULL) {
        fprintf(stderr, "初始化失败:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }

    // 连接数据库
    if (!mysql_real_connect(
            conn, "localhost", "root", "password",
            "student_db", 3306, NULL, 0)) {
        fprintf(stderr, "连接失败:%s\n", mysql_error(conn));
        mysql_close(conn);
        return EXIT_FAILURE;
    }

    printf("✅ 成功连接到MySQL!\n");

    // 设置字符集,防止中文乱码
    if (mysql_set_character_set(conn, "utf8")) {
        fprintf(stderr, "设置字符集失败:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }

    mysql_close(conn);
    return EXIT_SUCCESS;
}

⚙️ 小贴士:
- mysql_real_connect() 第七个参数是Unix socket,本地连接填 NULL
- 第八个是客户端标志位,一般传0;
- 务必调用 mysql_set_character_set(conn, "utf8") ,否则中文变问号。

流程图展示整个连接过程:

graph TD
    A[启动程序] --> B{mysql_init()成功?}
    B -- 是 --> C[调用mysql_real_connect()]
    B -- 否 --> D[打印错误并退出]
    C --> E{连接成功?}
    E -- 是 --> F[设置UTF8字符集]
    E -- 否 --> G[打印错误信息]
    G --> H[关闭连接并退出]
    F --> I[执行SQL操作]
    I --> J[mysql_close()]
    J --> K[结束]

每一步都有错误检测,这才是生产级代码应有的样子。


权限控制怎么做?基于角色的菜单系统来了

不同用户看到的功能应该不一样:

角色 能做什么
管理员 创建/删除班级、分配宿舍、查看日志
教师 查看所带班级学生、录成绩、申请调班
学生 查看自己信息、申请换宿、请假

我们可以用枚举定义角色:

typedef enum {
    ROLE_ADMIN,
    ROLE_TEACHER,
    ROLE_STUDENT
} UserRole;

然后根据角色动态生成菜单:

void show_menu(UserRole role) {
    printf("\n=== 主菜单 ===\n");
    switch (role) {
        case ROLE_ADMIN:
            printf("1. 添加学生\n");
            printf("2. 删除学生\n");
            printf("3. 创建班级\n");
            printf("4. 分配宿舍\n");
            break;
        case ROLE_TEACHER:
            printf("1. 查看班级学生\n");
            printf("2. 录入学生成绩\n");
            break;
        case ROLE_STUDENT:
            printf("1. 查看个人信息\n");
            printf("2. 申请换宿\n");
            break;
    }
}

登录时从数据库查询角色:

SELECT role FROM users WHERE username='zhangsan' AND password=MD5('123456');

再结合 mysql_fetch_row() 提取结果,实现个性化界面。


安全防护三板斧:加密、防注入、权限校验

别忘了,你的系统可能面临各种攻击。

🔐 密码不能明文存!用MD5哈希加密

#include <openssl/md5.h>

void encrypt_password(const char* input, char* output) {
    unsigned char digest[MD5_DIGEST_LENGTH];
    MD5((unsigned char*)input, strlen(input), digest);

    for (int i = 0; i < 16; ++i) {
        sprintf(&output[i*2], "%02x", (unsigned int)digest[i]);
    }
    output[32] = '\0';
}

这样密码就变成了像 e10adc3949ba59abbe56e057f20f883e 这样的哈希值,即使数据库泄露也无法还原。

🛑 注意:MD5已被破解,仅适用于教学项目;生产环境请用 bcrypt 或 Argon2。

🛡️ SQL注入?预处理语句安排!

千万别这么写:

sprintf(query, "SELECT * FROM Student WHERE name='%s'", user_input);

用户输入 ' OR '1'='1 直接让你的系统裸奔。

✅ 正确姿势:预处理语句

MYSQL_STMT *stmt = mysql_stmt_init(conn);
mysql_stmt_prepare(stmt, "SELECT id, name FROM Student WHERE name LIKE ?", 59);

MYSQL_BIND bind[1];
memset(bind, 0, sizeof(bind));
bind[0].buffer_type = MYSQL_TYPE_STRING;
bind[0].buffer = (char *)search_name;
bind[0].buffer_length = strlen(search_name);

mysql_stmt_bind_param(stmt, bind);
mysql_stmt_execute(stmt);

参数与SQL逻辑分离,从根本上杜绝注入风险。

🔐 细粒度权限控制:内存缓存+实时校验

建一张权限表:

role_id module can_read can_write can_delete
1 student_info 1 1 1
2 student_info 1 1 0
3 student_info 1 0 0

启动时加载进内存,每次操作前检查:

int check_permission(int role_id, const char* module, const char* op) {
    // 遍历权限数组,判断是否有权
}

形成闭环安全管理链路:

graph TD
    A[用户登录] --> B{身份验证}
    B -->|成功| C[加载角色权限]
    C --> D[进入主菜单]
    D --> E[选择功能]
    E --> F{检查权限?}
    F -->|允许| G[执行操作]
    F -->|拒绝| H[提示无权限]
    G --> I[记录日志]

数据备份与恢复:别等出事才后悔

硬盘坏了怎么办?误删数据怎么救?

💾 每天自动备份:mysqldump走起

mysqldump -u root -p --single-transaction student_db > backup_$(date +%Y%m%d_%H%M%S).sql

参数说明:
- --single-transaction :保证InnoDB一致性,不锁表;
- 加上 --routines --triggers 可导出函数和触发器。

C语言中可以用 system() 调用:

int trigger_backup() {
    char cmd[512];
    snprintf(cmd, sizeof(cmd),
        "mysqldump -uroot -pYourPass student_db > ./backup/backup_%s.sql",
        get_timestamp());
    return system(cmd);  // 返回0表示成功
}

🔄 恢复流程要清晰

  1. 停服务;
  2. 重建数据库;
  3. 导入SQL文件:
DROP DATABASE IF EXISTS student_db;
CREATE DATABASE student_db CHARACTER SET utf8mb4;
USE student_db;
SOURCE /path/to/backup.sql;

建议采用多层次备份策略:

类型 频率 RTO RPO
全量备份 每日 ~30分钟 24小时
增量备份 每小时 ~10分钟 1小时
binlog 实时 <5分钟 <1分钟

越关键的系统,RPO(数据丢失容忍)就越小。


写在最后:C语言+数据库的真正价值在哪?

也许你会觉得:“现在谁还用手写C连数据库啊?太原始了。”

但我想说的是:

掌握底层原理的人,永远不怕上层框架变迁。

当你知道 mysql_query() 内部是怎么组装TCP包、怎么解析响应协议的时候,你就不会再害怕任何“连接超时”或“字符集错乱”的问题。

而且C语言结合数据库的应用场景依然广泛:

  • 边缘计算设备上的本地持久化;
  • 工控机实时状态存储;
  • POS终端交易记录管理;
  • 国产化替代项目中的底层驱动配套模块;

甚至你可以进一步拓展:

  • 用 SQLite 替代 MySQL,实现零配置部署;
  • 集成 cJSON 库,支持JSON格式交互;
  • 写一个微型 ORM 框架,提升开发效率;
  • 构建 TCP 代理服务,让外部系统远程访问本地数据库。

🔚 所以,这不是复古,而是回归本质。

就像建筑师不会因为有了CAD软件就不学画图一样,程序员也不该因为有了Spring Boot就忘了 malloc free 的意义。

真正的高手,既能驾驭高级抽象,也能深入机器之心。

而这套学生管理系统,只是你通往系统级编程之路的第一步。🚀

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本项目“C语言+MySQL学生管理系统课程设计实战项目”基于C语言、MySQL数据库和Visual Studio开发环境,构建了一个面向管理员、教师和学生的多功能学生成绩与信息管理系统。系统涵盖宿舍管理、学生管理、班级管理等核心模块,支持用户权限分级控制,具备数据增删改查、成绩录入分析、信息导出备份等功能。项目融合数据库设计与软件工程实践,适用于数据库课程设计学习与教学管理场景,帮助开发者掌握数据库连接、SQL操作及C语言在实际系统开发中的应用。配套说明书和技术支持确保项目可快速部署与使用。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

OFDM通信系统Python实现源码 本资源包提供了一套完整的正交频分复用通信系统仿真实现,采用Python编程语言开发。该实现涵盖了OFDM系统的主要构成模块,包括: 核心功能模块: - 基带信号生成与QAM调制解调单元 - 串并转换与循环前缀添加机制 - 快速傅里叶变换及其逆变换处理单元 - 多径信道建模与均衡算法实现 - 符号定时与载波同步误差补偿 技术特性: 系统采用离散傅里叶变换实现频域并行传输,通过插入循环前缀有效对抗多径时延扩展。信道编码部分采用卷积码与交织器相结合的设计方案,有效提升系统抗突发错误能力。同步模块包含精确定时同步和频偏估计补偿算法,确保系统在存在载波频率偏移和采样时钟偏差时仍能保持稳定工作。 实现细节: 代码结构采用模块化设计,各功能单元接口清晰明确。信道模型支持AWGN和多径瑞利衰落两种典型无线传输环境。性能评估模块可输出误码率曲线和星座图等关键指标,便于系统性能分析验证。 应用价值: 该实现可作为通信系统教学演示工具,也可为无线通信算法研究人员提供基础开发框架。所有源代码均采用标准Python语法编写,兼容主流科学计算库,具有较好的可移植性和扩展性。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值