C语言的那点事第十篇:从“小白”到“大神”的奇幻之旅

C语言:从“小白”到“大神”的奇幻之旅


摘要

C语言,这门古老而强大的编程语言,如同一位历经沧桑却依旧活力四射的老者,陪伴着无数程序员走过了从懵懂到精通的道路。本文以幽默诙谐的笔触,带你走进C语言的世界,从项目实践到简单程序设计,再到调试、优化以及错误排查,全方位解锁C语言的魅力。别怕,这绝对不是一本正经的学术论文,而是一场充满欢笑与惊喜的编程之旅!


一、项目实践:C语言的“初体验”

(一)项目背景:拯救“混乱的图书馆”

想象一下,你走进了一个图书馆,书架上书籍乱七八糟,管理员一脸无奈地看着你。这就是我们的项目背景——帮助图书馆管理员整理书籍。用C语言来实现一个简单的图书管理系统,让管理员能够轻松地添加、删除、查找书籍,简直是拯救世界的壮举!

(二)项目目标

  1. 能够添加书籍信息(书名、作者、ISBN等)。

  2. 能够删除指定书籍。

  3. 能够根据书名或作者查找书籍。

  4. 能够显示所有书籍信息。

(三)项目实现

#include <stdio.h>
#include <string.h>
#define MAX_BOOKS 100

typedef struct {
    char title[100];
    char author[50];
    char isbn[20];
} Book;

Book books[MAX_BOOKS];
int bookCount = 0;

// 添加书籍
void addBook() {
    if (bookCount >= MAX_BOOKS) {
        printf("图书馆已经满了,不能再添加书籍啦!\n");
        return;
    }
    printf("请输入书名:");
    scanf("%99s", books[bookCount].title);
    printf("请输入作者:");
    scanf("%49s", books[bookCount].author);
    printf("请输入ISBN:");
    scanf("%19s", books[bookCount].isbn);
    bookCount++;
    printf("书籍添加成功!\n");
}

// 删除书籍
void deleteBook() {
    char title[100];
    printf("请输入要删除的书名:");
    scanf("%99s", title);
    for (int i = 0; i < bookCount; i++) {
        if (strcmp(books[i].title, title) == 0) {
            for (int j = i; j < bookCount - 1; j++) {
                books[j] = books[j + 1];
            }
            bookCount--;
            printf("书籍删除成功!\n");
            return;
        }
    }
    printf("没有找到这本书,删除失败!\n");
}

// 查找书籍
void searchBook() {
    char title[100];
    printf("请输入要查找的书名:");
    scanf("%99s", title);
    for (int i = 0; i < bookCount; i++) {
        if (strcmp(books[i].title, title) == 0) {
            printf("找到啦!\n书名:%s\n作者:%s\nISBN:%s\n", books[i].title, books[i].author, books[i].isbn);
            return;
        }
    }
    printf("没有找到这本书,很遗憾!\n");
}

// 显示所有书籍
void displayBooks() {
    if (bookCount == 0) {
        printf("图书馆空空如也!\n");
        return;
    }
    printf("图书馆藏书:\n");
    for (int i = 0; i < bookCount; i++) {
        printf("书名:%s\n作者:%s\nISBN:%s\n", books[i].title, books[i].author, books[i].isbn);
    }
}

int main() {
    int choice;
    while (1) {
        printf("\n欢迎来到图书馆管理系统!\n");
        printf("1. 添加书籍\n");
        printf("2. 删除书籍\n");
        printf("3. 查找书籍\n");
        printf("4. 显示所有书籍\n");
        printf("5. 退出\n");
        printf("请选择操作:");
        scanf("%d", &choice);
        switch (choice) {
            case 1:
                addBook();
                break;
            case 2:
                deleteBook();
                break;
            case 3:
                searchBook();
                break;
            case 4:
                displayBooks();
                break;
            case 5:
                printf("感谢使用图书馆管理系统,再见!\n");
                return 0;
            default:
                printf("输入有误,请重新选择!\n");
        }
    }
    return 0;
}

(四)项目成果

通过这个项目,我们不仅帮助图书馆管理员解决了书籍管理的难题,还学会了如何用C语言实现一个简单的结构体数组操作。这只是一个小小的开始,C语言的世界还有很多宝藏等着我们去挖掘!


二、简单程序设计:学生成绩管理系统

(一)需求分析

学生成绩管理系统是每个程序员的“必修课”。我们需要实现以下功能:

  1. 输入学生信息(姓名、学号、成绩)。

  2. 显示所有学生信息。

  3. 按成绩排序。

  4. 查询指定学生信息。

  5. 修改学生信息。

(二)程序设计

#include <stdio.h>
#include <string.h>
#define MAX_STUDENTS 100

typedef struct {
    char name[50];
    char id[20];
    float score;
} Student;

Student students[MAX_STUDENTS];
int studentCount = 0;

// 输入学生信息
void inputStudent() {
    if (studentCount >= MAX_STUDENTS) {
        printf("学生人数已满,无法添加新学生!\n");
        return;
    }
    printf("请输入学生姓名:");
    scanf("%49s", students[studentCount].name);
    printf("请输入学生学号:");
    scanf("%19s", students[studentCount].id);
    printf("请输入学生成绩:");
    scanf("%f", &students[studentCount].score);
    studentCount++;
    printf("学生信息添加成功!\n");
}

// 显示所有学生信息
void displayStudents() {
    if (studentCount == 0) {
        printf("暂无学生信息!\n");
        return;
    }
    printf("\n学生信息列表:\n");
    printf("姓名\t\t学号\t\t成绩\n");
    for (int i = 0; i < studentCount; i++) {
        printf("%-10s\t%-10s\t%.2f\n", students[i].name, students[i].id, students[i].score);
    }
}

// 按成绩排序
void sortStudents() {
    for (int i = 0; i < studentCount - 1; i++) {
        for (int j = 0; j < studentCount - i - 1; j++) {
            if (students[j].score > students[j + 1].score) {
                Student temp = students[j];
                students[j] = students[j + 1];
                students[j + 1] = temp;
            }
        }
    }
    printf("学生信息已按成绩排序!\n");
}

// 查询指定学生信息
void searchStudent() {
    char id[20];
    printf("请输入要查询的学生学号:");
    scanf("%19s", id);
    for (int i = 0; i < studentCount; i++) {
        if (strcmp(students[i].id, id) == 0) {
            printf("学生信息:\n姓名:%s\n学号:%s\n成绩:%.2f\n", students[i].name, students[i].id, students[i].score);
            return;
        }
    }
    printf("未找到该学生信息!\n");
}

// 修改学生信息
void modifyStudent() {
    char id[20];
    printf("请输入要修改的学生学号:");
    scanf("%19s", id);
    for (int i = 0; i < studentCount; i++) {
        if (strcmp(students[i].id, id) == 0) {
            printf("请输入新的学生姓名:");
            scanf("%49s", students[i].name);
            printf("请输入新的学生成绩:");
            scanf("%f", &students[i].score);
            printf("学生信息修改成功!\n");
            return;
        }
    }
    printf("未找到该学生信息!\n");
}

int main() {
    int choice;
    while (1) {
        printf("\n欢迎来到学生成绩管理系统!\n");
        printf("1. 输入学生信息\n");
        printf("2. 显示所有学生信息\n");
        printf("3. 按成绩排序\n");
        printf("4. 查询指定学生信息\n");
        printf("5. 修改学生信息\n");
        printf("6. 退出\n");
        printf("请选择操作:");
        scanf("%d", &choice);
        switch (choice) {
            case 1:
                inputStudent();
                break;
            case 2:
                displayStudents();
                break;
            case 3:
                sortStudents();
                break;
            case 4:
                searchStudent();
                break;
            case 5:
                modifyStudent();
                break;
            case 6:
                printf("感谢使用学生成绩管理系统,再见!\n");
                return 0;
            default:
                printf("输入有误,请重新选择!\n");
        }
    }
    return 0;
}

(三)功能测试

  1. 输入学生信息:程序会提示用户依次输入学生姓名、学号和成绩,然后将这些信息存储到结构体数组中。

  2. 显示所有学生信息:程序会以表格形式显示所有学生的信息,包括姓名、学号和成绩。

  3. 按成绩排序:程序会按照学生成绩从低到高进行排序,方便查看成绩排名。

  4. 查询指定学生信息:用户可以通过输入学号来查询特定学生的信息。

  5. 修改学生信息:用户可以通过输入学号来修改特定学生的姓名和成绩。

(四)代码注释

  • typedef struct:定义了一个Student结构体,用于存储学生信息。

  • inputStudent:通过scanf函数获取用户输入的学生信息,并存储到数组中。

  • displayStudents:使用循环遍历数组,打印每个学生的信息。

  • sortStudents:使用冒泡排序算法对学生成绩进行排序。

  • searchStudent:通过strcmp函数比较学号,查找指定学生信息。

  • modifyStudent:找到指定学生后,允许用户修改其信息。


三、调试与优化:C语言的“体检”与“健身计划”

在C语言开发过程中,调试和优化是两个至关重要的环节。调试就像是给代码做“体检”,帮助我们找出那些隐藏在代码中的“小妖精”,而优化则像是给代码制定“健身计划”,让代码变得更加高效和健壮。这两个过程相辅相成,缺一不可。

(一)调试:找出代码中的“小妖精”

调试是编程过程中不可或缺的一部分,它帮助我们发现并解决代码中的问题。C语言的调试方法多种多样,以下是几种常见的调试手段:

1. 打印调试

打印调试是最简单、最直接的调试方法。通过在代码中插入printf函数,我们可以输出变量的值,查看程序的运行状态。这种方法虽然简单,但在某些情况下非常有效,尤其是当我们需要快速定位问题时。例如:

int main() {
    int a = 10;
    int b = 0;
    printf("a = %d, b = %d\n", a, b); // 打印变量的值
    int result = a / b; // 这里可能会出现除以零的错误
    printf("result = %d\n", result);
    return 0;
}

通过打印变量的值,我们可以清楚地看到程序的运行过程,从而快速定位问题。

2. 断点调试

断点调试是一种更高级的调试方法,它允许我们在程序运行过程中暂停程序,逐步执行代码,观察变量的变化。常用的调试工具是GDB(GNU Debugger)。GDB可以设置断点、单步执行代码、查看变量的值等。例如:

int main() {
    int a = 10;
    int b = 0;
    int result = a / b; // 这里可能会出现除以零的错误
    printf("result = %d\n", result);
    return 0;
}

使用GDB调试时,我们可以在a / b处设置一个断点,然后逐步执行代码,观察变量ab的值。这样可以更清晰地发现程序中的问题。

3. 日志记录

日志记录是另一种调试方法,它通过在程序中添加日志记录功能,记录程序的运行过程。日志记录不仅可以帮助我们分析程序的运行状态,还可以在程序出现问题时提供详细的上下文信息。例如:

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

void log_message(const char *message) {
    FILE *log_file = fopen("log.txt", "a");
    if (log_file) {
        fprintf(log_file, "%s\n", message);
        fclose(log_file);
    }
}

int main() {
    int a = 10;
    int b = 0;
    log_message("Starting program");
    log_message("a = 10, b = 0");
    int result = a / b; // 这里可能会出现除以零的错误
    log_message("result = 10/0");
    printf("result = %d\n", result);
    return 0;
}

通过日志记录,我们可以清楚地看到程序的运行过程,即使程序崩溃,我们也可以通过查看日志文件来分析问题。

(二)优化:让代码“健壮”起来

优化是编程过程中的另一个重要环节,它可以让代码更加高效和健壮。优化的方法多种多样,以下是一些常见的优化手段:

1. 算法优化

算法是程序的核心,选择高效的算法可以显著提升程序的性能。例如,在学生成绩管理系统中,我们可以用快速排序代替冒泡排序。快速排序的平均时间复杂度为O(n log n),而冒泡排序的时间复杂度为O(n²)。通过优化算法,我们可以大大减少程序的运行时间。

2. 内存优化

合理使用内存可以提高程序的性能,避免内存泄漏等问题。在C语言中,动态分配内存时需要特别小心,确保在使用完内存后及时释放。例如:

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

int main() {
    int *array = (int *)malloc(10 * sizeof(int)); // 动态分配内存
    if (array == NULL) {
        printf("Memory allocation failed\n");
        return 1;
    }
    // 使用数组
    for (int i = 0; i < 10; i++) {
        array[i] = i;
    }
    // 释放内存
    free(array);
    return 0;
}

通过合理管理内存,我们可以避免内存泄漏,确保程序的稳定运行。

3. 代码结构优化

代码结构优化可以让代码更加清晰、易读和易维护。例如,将重复的代码封装成函数,减少代码冗余。这样不仅可以让代码更简洁,还可以提高代码的可维护性。例如:

#include <stdio.h>

void print_student_info(const char *name, const char *id, float score) {
    printf("Name: %s, ID: %s, Score: %.2f\n", name, id, score);
}

int main() {
    print_student_info("Alice", "001", 85.5);
    print_student_info("Bob", "002", 90.0);
    print_student_info("Charlie", "003", 78.5);
    return 0;
}

通过封装重复的代码,我们可以让代码更加简洁,提高代码的可维护性。

(三)调试与优化的综合实践

调试和优化是相辅相成的。通过调试,我们可以发现代码中的问题;通过优化,我们可以提升代码的性能。在实际开发中,我们需要综合运用调试和优化的方法,确保程序的高效和稳定运行。例如,在开发一个复杂的系统时,我们可以通过GDB设置断点,逐步执行代码,发现并解决内存泄漏、逻辑错误等问题。同时,我们可以通过优化算法、合理管理内存、优化代码结构等手段,提升程序的性能。

(四)调试与优化的未来展望

随着技术的不断发展,调试和优化的方法也在不断进步。例如,现代调试工具提供了更强大的功能,如可视化调试、性能分析等。同时,随着多核处理器和并行计算技术的发展,优化算法和内存管理变得更加重要。未来,调试和优化将不仅仅是一个技术问题,更是一个涉及多学科的综合问题,需要我们不断学习和探索。

通过调试和优化,我们可以让C语言代码更加高效、健壮和易维护。调试帮助我们发现并解决代码中的问题,优化则让代码在性能上“飞起来”。在未来的技术发展中,调试和优化将继续为程序员提供强大的支持,让我们在编程的道路上不断前行。


四、常见错误排查:C语言的“排雷”行动

(一)语法错误:C语言的“小感冒”

语法错误是编程中最常见的错误,就像C语言“感冒”了。比如:

  • 拼写错误int a = 10;写成了int a = 10(少了一个分号)。

  • 括号不匹配if (a > 0)后面没有写{}

  • 类型不匹配int a = "hello";(字符串赋值给整型变量)。

解决方法:仔细检查代码,对照语法规范,找出错误并修正。编译器会提示语法错误的位置,这是排查语法错误的好帮手。

(二)逻辑错误:C语言的“迷路”

逻辑错误是程序运行结果不符合预期,就像C语言“迷路”了。比如:

  • 循环条件错误for (int i = 0; i < 10; i++)写成了for (int i = 0; i <= 10; i++),导致循环多执行了一次。

  • 条件判断错误if (a > 0)写成了if (a < 0),导致程序逻辑出错。

解决方法:通过打印调试、断点调试等方法,逐步分析程序的运行过程,找出逻辑错误的原因并修正。逻辑错误是最难排查的错误,需要耐心和细心

(三)运行时错误:C语言的“心脏病”

运行时错误是程序在运行过程中出现的错误,就像C语言“心脏病”发作。比如:

  • 数组越界:访问数组时,索引超出了数组的范围。

  • 指针野指针:使用未初始化的指针,或者指针指向了非法的内存地址。

解决方法:使用调试工具(如GDB)来定位运行时错误的位置,检查数组索引、指针的使用是否正确。运行时错误可能会导致程序崩溃,后果很严重,一定要小心防范。


五、性能优化:让C语言“飞起来”

在编程的世界里,性能优化就像是给汽车换上更强劲的引擎,让代码运行得更快、更高效。C语言以其高效性和灵活性,为性能优化提供了广阔的空间。通过算法优化、内存优化和代码结构优化,我们可以让C语言程序“飞起来”,在复杂的任务中表现出色。

(一)算法优化:选择“更快的马车”

算法是程序的核心,它决定了程序的效率和性能。选择高效的算法,就像是给程序换上了一辆“更快的马车”,可以让程序运行得更快、更流畅。在学生成绩管理系统中,我们最初使用了冒泡排序算法来对学生信息进行排序。冒泡排序虽然简单易懂,但它的平均时间复杂度为O(n²),在数据量较大时,运行速度会明显变慢。

为了提升性能,我们可以改用快速排序算法。快速排序是一种分治算法,它通过选择一个“基准”值,将数组分为两部分,一部分包含小于基准值的元素,另一部分包含大于基准值的元素,然后递归地对这两部分进行排序。快速排序的平均时间复杂度为O(n log n),在大多数情况下比冒泡排序快得多。通过这种优化,学生成绩管理系统在处理大量数据时的响应速度显著提升,用户体验也得到了极大改善。

(二)内存优化:合理使用“内存仓库”

内存是程序的“仓库”,它存储了程序运行时的所有数据。合理使用内存不仅可以提高程序的性能,还可以避免内存泄漏等问题。在C语言中,内存管理是一个重要的环节,尤其是在动态分配内存时。例如,在学生成绩管理系统中,我们可能会动态分配内存来存储学生信息。如果在使用完这些内存后没有及时释放,就会导致内存泄漏。

内存泄漏就像是程序中的“黑洞”,它会不断消耗系统内存,最终可能导致程序崩溃。为了避免这种情况,我们可以在程序中添加内存释放的逻辑。例如,在删除学生信息时,不仅要从数据结构中移除对应的记录,还要释放之前分配的内存。此外,我们还可以使用内存管理工具(如Valgrind)来检测内存泄漏,确保程序的内存使用是安全和高效的。

(三)代码结构优化:让代码“井然有序”

代码结构就像程序的“骨架”,它决定了代码的可读性和可维护性。合理的代码结构可以让程序更易读、更易维护,减少开发和维护成本。在C语言中,我们可以通过封装重复的代码、合理划分模块等方式来优化代码结构。

例如,在学生成绩管理系统中,我们可能会多次使用到输入学生信息、显示学生信息等功能。为了避免代码冗余,我们可以将这些功能封装成独立的函数。这样不仅可以让代码更简洁,还可以提高代码的可复用性。此外,我们还可以将程序划分为不同的模块,例如输入模块、处理模块和输出模块。每个模块负责一个特定的功能,模块之间通过函数调用进行交互。这种模块化的结构不仅让代码更清晰,也方便了后续的扩展和维护。

(四)性能优化的综合实践

性能优化不仅仅是单一的算法优化、内存优化或代码结构优化,而是一个综合的过程。在实际项目中,我们需要综合运用这些优化手段,才能达到最佳的性能效果。例如,在一个复杂的嵌入式系统中,我们可能需要同时优化算法、管理内存并优化代码结构,以确保系统在有限的资源下高效运行。

在优化过程中,我们还需要不断测试和评估优化的效果。通过性能测试工具(如gprof),我们可以分析程序的运行时间、内存使用情况等关键指标,找出性能瓶颈并针对性地进行优化。优化是一个持续的过程,随着技术的发展和需求的变化,我们可能需要不断调整优化策略,以确保程序始终处于最佳状态。

(五)性能优化的未来展望

随着技术的不断发展,性能优化的需求也在不断变化。在未来的编程中,我们将面临更多复杂的挑战,如多核处理器的并行计算、云计算环境下的分布式计算等。C语言作为一种底层语言,将在这些领域发挥重要作用。例如,通过使用多线程和并行计算技术,我们可以进一步提升程序的性能,充分利用多核处理器的计算能力。

同时,随着人工智能和机器学习技术的兴起,C语言也将在高性能计算库中继续发挥关键作用。通过优化算法和内存管理,我们可以开发出更高效的计算框架,为人工智能和机器学习提供强大的支持。未来,性能优化将不仅仅是一个技术问题,更是一个涉及多学科的综合问题,需要我们不断学习和探索。

通过算法优化、内存优化和代码结构优化,我们可以让C语言程序在性能上“飞起来”,在复杂的任务中表现出色。性能优化不仅是一个技术挑战,更是一个持续的探索过程。在未来的技术发展中,C语言将继续以其高效性和灵活性,为程序员提供强大的支持,让我们在编程的道路上不断前行。


六、结语

回顾我们的C语言之旅,从最初的懵懂到如今的熟练,这一路走来,C语言不仅教会了我们如何用代码解决问题,更培养了我们面对技术挑战时的坚韧与智慧。通过项目实践,我们从简单的图书管理系统起步,逐步掌握了结构体、数组、指针等核心概念,学会了如何将理论转化为实际应用。调试与优化的过程则让我们在代码的世界里不断打磨技艺,从语法错误到逻辑漏洞,再到性能瓶颈,每一次的排查与改进都让我们的代码更加健壮、高效。而错误排查更是锻炼了我们的耐心与细致,那些隐藏在代码深处的“小妖精”们,最终都成了我们成长的助力。

C语言的魅力在于它的简洁与强大,它既能让我们深入硬件层面,又能构建复杂的系统级应用。从嵌入式设备到高性能计算,从操作系统内核到物联网应用,C语言始终是不可或缺的基石。它不仅是一门语言,更是一种技术传承和文化象征,承载着计算机科学的核心思维。

未来,C语言的旅程仍在继续。随着技术的演进,它在嵌入式系统、高性能计算和物联网等领域仍将发挥关键作用。我们也将继续探索,从底层原理到高级编程技巧,从开源项目到新技术应用,不断拓展C语言的边界。更重要的是,我们要将C语言的精神传承下去,让更多人感受到它的魅力,让这门古老而强大的语言在新时代继续焕发光彩。无论未来的编程世界如何变化,C语言都将是那盏永不熄灭的灯塔,指引着我们前行的方向。


参考文献

[1] 谭浩强. C语言程序设计[M]. 北京:清华大学出版社,2020.

[2] 王晓华. C语言高级编程技巧[M]. 北京:电子工业出版社,2019.

[3] 侯捷. C++ Primer[M]. 北京:机械工业出版社,2018.


C语言的传承:从个人到团队的跨越

C语言不仅仅是一门技术,它更是一种文化的传承。从最初的Unix操作系统到如今广泛使用的Linux内核,C语言的代码和思想一直被一代又一代的程序员传承和发扬。这种传承不仅体现在代码的编写上,更体现在程序员的思维方式和解决问题的方法上。C语言教会了我们如何用简洁而高效的方式表达复杂的逻辑,如何在有限的资源下实现强大的功能,以及如何在面对困难时保持坚韧和创新的精神。

在未来的学习和工作中,我们不仅要继续学习C语言的知识和技能,更要将这种传承延续下去。我们可以将自己的经验分享给其他初学者,帮助他们更快地成长。这种分享可以是线上的技术博客、开源项目,也可以是线下的技术交流会或工作坊。通过分享,我们不仅能够帮助他人,也能在这个过程中巩固自己的知识,发现新的问题和解决方案。

参与开源项目是传承C语言精神的另一种重要方式。开源社区是一个充满活力和创造力的地方,通过将自己的代码贡献给社区,我们可以让更多的人受益。同时,参与开源项目也能让我们接触到不同的编程风格和思维方式,拓宽我们的技术视野。在开源项目中,我们不仅能够学习到如何编写高质量的代码,还能学习到如何进行有效的团队协作,如何在不同的意见和需求中找到平衡。

团队合作是C语言传承中的一个重要环节。在实际工作中,我们很少独自完成一个项目,更多的是与团队成员合作,共同解决复杂的编程问题。通过团队合作,我们可以将不同的技能和经验结合起来,发挥更大的价值。在团队中,我们不仅要学会如何表达自己的想法,还要学会如何倾听他人的意见,如何在团队中找到自己的定位。这种团队合作的精神,正是C语言传承中不可或缺的一部分。

C语言的传承不仅仅是一种技术的传递,更是一种精神的传递。这种精神包括对技术的热爱、对问题的执着、对创新的追求以及对团队合作的重视。对技术的热爱让我们始终保持学习的热情,不断探索新的知识和技术;对问题的执着让我们在面对困难时不轻易放弃,寻找解决问题的方法;对创新的追求让我们不断尝试新的思路和方法,推动技术的进步;对团队合作的重视让我们能够与他人协作,共同实现更大的目标。

通过这种传承,我们可以让C语言的精神在新的时代继续发扬光大,让更多的程序员受益。无论技术如何发展,C语言所代表的这种精神都将是我们宝贵的财富。让我们继续传承这种精神,用C语言书写属于我们的技术传奇,让这门古老而强大的语言在新的时代焕发出新的光彩。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

暮雨哀尘

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

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

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

打赏作者

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

抵扣说明:

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

余额充值