28. 【C语言】通用数据操作:`void *` 与类型无关编程

C 语言中的指针大小 `sizeof` 与通用指针类型 `void*` 详解 指针的大小:指针的大小由系统架构决定,通常在 32 位系统中为 4 字节,在 64 位系统中为 8 字节。sizeof运算符用于获取指针本身的大小,而不是它指向的数据的大小。void*指针void*是一种通用指针类型,可以指向任何类型的数据。在使用void*时,通常需要进行类型转换。sizeof运算符与指针:通过sizeof可以获取指针的大小,但它返回的是指针本身的内存大小,而不是指针指向的数据的大小。掌握了指针的大小和void*的使用,你将能够更高效地管理内存,并编写更灵活、通用的 C 语言程序! 阅读详情

前面我们写了不少函数:排序 int 的冒泡、交换 int 的 swap、求 int 数组的最大值……但你有没有发现,这些函数都被死死绑在了具体的类型上——排序只能排 int,交换只能换 int,如果哪天想排 double 或 struct Student,就得把几乎相同的逻辑重新写一遍。

这显然不够优雅。C 语言虽然没有模板和泛型,但它有一个“万能指针”——void *。配合函数指针,你可以写出类型无关的通用代码,写一次,到处用。


一、void *:可以指向任何类型的指针

void * 是一种特殊的指针类型,它能存储任意类型对象的地址,但不携带“指向什么类型”的信息。

int    a = 10;
double b = 3.14;
char   c = 'X';

void *vp;
vp = &a;   // 指向 int
vp = &b;   // 指向 double
vp = &c;   // 指向 char

你可以把 void * 理解为“一个单纯的地址”,丢掉了类型标签。正因如此,编译器不知道它指向的数据是什么类型、占多少字节,所以:

限制 1:不能直接解引用

int a = 10;
void *vp = &a;
printf("%d\n", *vp);   // 编译错误!不能解引用 void*

必须先把它强制转换成正确的类型指针,再解引用:

printf("%d\n", *(int*)vp);   // 正确

限制 2:不能做指针算术

vp + 1;   // 编译错误!不知道每次跳多少字节

GCC 扩展允许 void* 的算术(当成 char*),但标准 C 不允许。要移动 void*,先转成 char*。


二、void * 的典型用途:通用接口

尽管有这些限制,void * 却成为了 C 语言实现“泛型”的基石。标准库中大量函数都使用它:

函数用途
malloc / calloc / realloc返回 void*,可赋给任何指针
memcpy / memset / memmove操作任意类型的内存块
qsort / bsearch排序和查找任何类型的数据
线程创建函数传递任意类型的参数

它们的共同点是:操作的是“一段内存”,不关心里面存的是什么类型。只要我们告诉它这块内存的起始地址和大小,剩下的事情就能做。


三、实现一个通用的 swap 函数

以前我们写的 swap 只能交换两个 int。用 void* 加上元素大小参数,就能交换任意类型的值。

#include <stdio.h>
#include <string.h>

// 交换任意两块内存
void swap_generic(void *a, void *b, size_t size) {
    char temp[size];          // VLA,临时存储
    memcpy(temp, a, size);
    memcpy(a,    b, size);
    memcpy(b, temp, size);
}

int main(void) {
    int x = 10, y = 20;
    swap_generic(&x, &y, sizeof(int));
    printf("x=%d, y=%d\n", x, y);   // x=20, y=10

    double d1 = 1.5, d2 = 3.5;
    swap_generic(&d1, &d2, sizeof(double));
    printf("d1=%.1f, d2=%.1f\n", d1, d2);  // d1=3.5, d2=1.5

    return 0;
}

关键:我们必须传入 sizeof(类型),因为 void* 不知道元素多大。函数内部用 memcpy(也是 void* 接口)逐字节拷贝,char temp[size] 是变长数组,大小由参数决定。

变长数组在某些场合有争议(栈空间风险),但它让这个例子简洁。实际项目中若拷贝大对象,可改用动态分配或循环按机器字长拷贝。原理一样。


四、模仿 qsort:写一个泛型冒泡排序

qsort 是 C 标准库的通用排序函数,原型如下:

void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));

参数:

  • base:数组首地址(void*)
  • nmemb:元素个数
  • size:每个元素的字节数
  • compar:比较函数,接收两个 const void*,返回负数/零/正数

它的思想是:把数据和操作分离。排序逻辑不需要知道数据是什么类型,只要知道每个元素多大,并由调用者提供一个比较函数。

我们参照这个设计,实现自己的 generic_bubble_sort:

#include <stdio.h>
#include <string.h>
#include <stddef.h>

// 交换 size 字节的两块内存
static void swap_bytes(void *a, void *b, size_t size) {
    char *pa = (char*)a;
    char *pb = (char*)b;
    for (size_t i = 0; i < size; i++) {
        char temp = pa[i];
        pa[i] = pb[i];
        pb[i] = temp;
    }
}

// 泛型冒泡排序
void generic_bubble_sort(void *base, size_t nmemb, size_t size,
                         int (*compar)(const void *, const void *)) {
    char *arr = (char*)base;   // 转换为 char* 用于地址算术
    for (size_t i = 0; i < nmemb - 1; i++) {
        int swapped = 0;
        for (size_t j = 0; j < nmemb - 1 - i; j++) {
            // 计算相邻元素的地址
            void *elem_j   = arr + j * size;
            void *elem_next = arr + (j + 1) * size;
            if (compar(elem_j, elem_next) > 0) {
                swap_bytes(elem_j, elem_next, size);
                swapped = 1;
            }
        }
        if (!swapped) break;
    }
}

核心点:

  • base 被转成 char*,这样 arr + j * size 就能准确定位到第 j 个元素的起始地址。
  • 调用者提供的 compar 负责比较逻辑,它拿到的是两个 void*,内部再转成实际类型比较。

五、使用我们的泛型排序:对 int、double、结构体排序

1. 排序 int 数组

int compare_int(const void *a, const void *b) {
    int ia = *(const int*)a;
    int ib = *(const int*)b;
    return (ia > ib) - (ia < ib);   // 简洁的差值法,避免溢出
}

int main(void) {
    int arr[] = {5, 2, 9, 1, 5, 6};
    size_t n = sizeof(arr) / sizeof(arr[0]);
    generic_bubble_sort(arr, n, sizeof(int), compare_int);
    for (size_t i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");
    return 0;
}

2. 排序 double 数组

int compare_double(const void *a, const void *b) {
    double da = *(const double*)a;
    double db = *(const double*)b;
    if (da < db) return -1;
    if (da > db) return  1;
    return 0;
}

注意浮点数不能直接用减法返回,因为 NaN 和极值可能使减法失效。

3. 排序结构体(按成绩)

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

int compare_student_by_score(const void *a, const void *b) {
    const Student *sa = (const Student*)a;
    const Student *sb = (const Student*)b;
    if (sa->score < sb->score) return -1;
    if (sa->score > sb->score) return  1;
    return 0;
}

int main(void) {
    Student class[] = {
        {"Alice", 1, 92.5},
        {"Bob",   2, 85.0},
        {"Carol", 3, 78.5},
    };
    size_t n = sizeof(class) / sizeof(class[0]);
    generic_bubble_sort(class, n, sizeof(Student), compare_student_by_score);
    for (size_t i = 0; i < n; i++) {
        printf("%s: %.1f\n", class[i].name, class[i].score);
    }
    return 0;
}

你看到了吗? 同一个 generic_bubble_sort 函数,通过传入不同的比较函数,可以排序任何类型——这就是 C 语言泛型编程的核心模式:void* + 元素大小 + 函数指针。


六、void * 的更多场景

除了排序,void* 还在以下地方大显身手:

  • 动态内存管理:malloc 返回 void*,你就是用它来申请任意类型的内存。
  • 回调参数:线程创建、定时器回调等,通常接受一个 void* 参数,让你传递任意上下文。
  • 通用容器:简单的泛型栈、队列、链表可以通过 void* 存储数据(配合大小或用指针指向数据)。

例如,一个泛型栈可以这样声明:

typedef struct {
    void **data;      // 存的是各种类型的指针
    int top;
    int capacity;
} Stack;

这种“存指针”的方式省去了元素大小的麻烦,但需要注意数据生命周期。更完善的通用容器库(如 GLib、sys/queue.h)正是建立在这些概念上。


七、常见错误与陷阱

1. 忘记传递 size 或写错

void bad_sort(void *base, size_t nmemb, int (*cmp)(const void*, const void*)) {
    // 缺少 size 参数,无法知道元素多大!
}

没有 size,就无法计算第 n 个元素的地址,排序逻辑寸步难行。

2. compar 中强制转换错误

int compare_int(const void *a, const void *b) {
    return *(int*)a - *(int*)b;   // 未加 const,且解引用 void* 时忘了 const
}

应该 *(const int*)a。虽然编译器对 const 丢失可能只是警告,但保持 const 正确性是好习惯。

3. 对 void* 做算术

void *vp = ...;
vp++;  // GCC 扩展允许,但标准 C 不允许,可移植性差

统一用 (char*)vp + offset。

4. 比较函数返回值逻辑错误

qsort 风格的比较函数要求返回负数表示 a < b,零表示相等,正数表示 a > b。简单减法虽然简便,但对大整数可能溢出。对浮点数务必用 if-else 结构。


八、小结

void * 是 C 语言实现通用编程的秘密武器。它丢掉了类型标签,换来了操作任意数据的能力,但也要求程序员必须小心翼翼地管理类型转换和大小信息。

今天你学到了:

  • void* 可以指向任何类型,但不能直接解引用或做算术。
  • 配合 size 参数和函数指针,可以写出类型无关的 swap、排序、查找等算法。
  • 自己实现了一个泛型冒泡排序,理解了 qsort 的底层原理。
  • 这是 C 语言中“数据和算法分离”的经典范式。

这套模式是后面实现链表、树、哈希表等通用数据结构的基础。下一篇文章,我们就要用 void* 和动态内存,构建一个经典的动态数据结构——单向链表,让数据不在编译时固定大小,而是可以自由地增长和收缩。真正的数据结构之旅,现在开始。


课后小练习

  1. 实现一个泛型的数组逆置函数 void generic_reverse(void *base, size_t nmemb, size_t size),将数组中元素的顺序颠倒。用它逆置一个 int 数组和一个 double 数组,验证结果。
  2. 利用 qsort(标准库函数)对字符串数组 char *words[] = {"banana", "apple", "cherry"}; 按字典序排序并打印。提示:比较函数中解引用 void* 得到 char**,再用 strcmp。
  3. 实现一个泛型的 find_max 函数:void *find_max(const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)),返回指向最大元素的指针。测试对 int 数组和 struct Student 数组的查找。
  4. (小挑战)用 void* 和函数指针设计一个简单的回调式 foreach 函数:void array_foreach(void *base, size_t nmemb, size_t size, void (*func)(void *))。该函数遍历数组,对每个元素调用 func。写一个打印 int 和 double 的回调,并在 main 中测试。

我们下期见!

💡获取本系列示例代码请访问 GitCode 仓库。

【C语言】“void” 如何在 C 语言中开创无限可能 void是C语言中的一个特殊关键字,具有多种用途。它可以表示没有返回值的函数、没有参数的函数参数列表、以及通用指针类型等。本文将详细介绍void的各种用法及其在编程中的实际应用。 阅读详情

相关推荐

10bit SAR ADC电路:200多页设计与仿真文档,附gpdk045工艺与testbench,可直接导入Virtuoso仿真,含以太网、PLL电路例程及进阶ADC

拥有超过200页的详细设计和仿真文档,它以gpdk045工艺为基础,testbench均可直接导入virtuoso仿真,为我们提供了一个全面了解ADC电路设计的绝佳机会。通过对10bit SAR ADC电路的详细解析,我们不仅了解了其设计背后的原理和实现方法,还体会到了数字与模拟技术的交融之美。这个SAR ADC的结构采用了经典的电荷重分配架构。一个10bit SAR ADC电路,有200多页详细的设计和仿真文档,附带对应的gpdk045工艺,testbench都有,可直接导入virtuoso仿真。

OMyAVKmGPBOF的博客 1332

《深入理解 C/C++ 中的万能指针 `void*`》

深入理解 C/C++ 中的万能指针 `void*`

一名普通高校生 1044

STK之Commu模块之三仿真卫星通信链路参数计算

考虑上述衰减的影响,可以得到卫星接收机输入端的载波功 [C] = [PT] +[GT] +[GR] -[L] -[L1] -[L2] (

juanhuokang2681的博客 8267

【c语言】void* 详解与应用

1、常见`void` 与`void*` 应用;2、`void`和`void*`的使用规则;3、`void*`指针所带来的好处

Colorful___的博客 5217

STM32G0定时器中断实战:HAL库配置TIM2实现精准1秒LED闪烁(附完整代码)

本文深入解析了STM32G0系列微控制器中定时器中断的配置与应用,重点介绍了如何使用HAL库配置TIM2实现精准的1秒LED闪烁。通过详细讲解时钟树分析、预分频系数与自动重装载寄存器的计算原理,并结合CubeMX图形化配置与完整代码示例,帮助开发者从底层理解定时器工作机制,掌握可复用的工程化配置方法。

weixin_29194817的博客 252

SAP中寄售结算规则及要点分析

在做MRKO寄售结算时,系统会根据选定的期间和供应商等条件,将符合条件的寄售消耗或寄售上线的物料凭证找出。然后以供应商为单位。合并产生一张会计凭证。下图显示了通过MRKO结算后自动生成的会计凭证。 那么,在MRKO做寄售结算的规则是什么样的?做为寄售业务处理者的物流和财务需要掌握和了解哪些关于寄售结算的规则和控制逻辑。下面以笔者的经验分析一下: 1、寄售物料在系统中有两种处理方法,一种是通过MB1B 411 K ,通常该操作达到两个目的:将物料从仓库转移到线边库(表示即将要投入生产了)的同时将寄售库

专注SAP应用技术文章写作,致力于拉近用户与系统间的距离; 8294

【C语言】void和void *的区别

1.void的用法 在C语言中void 常用于2个方面:对函数返回类型的限定和对函数参数限定。   (1)对函数返回类型的限定:当函数不需要返回类型是必须用void 来限定返回类型,限定了函数的返回类型为void后,函数不能有返回值。 如:void fun(int a); (2)对函数参数类型的限定:当函数不允许接受参数时,必须用void 来限定函数参数,限定了函数的参数类型为void后函数不能有...

chengwei1128的博客 2131

Zemax实战:20×超高清变焦镜头设计全流程解析(从架构到制造)

本文详细解析了使用Zemax软件设计一款20倍变焦比、恒定F2.8光圈8K超高清镜头的全流程。从应对恒定光圈、宽光谱与8K解析力三大挑战的初始架构规划,到构建多重组态模型、分七阶段进行像差优化与公差分析,最终跨越制造鸿沟,为广播级影视与高精度工业检测应用提供了实战指南。

sun99的博客 550

【C语言】void * 指针类型及其使用

在 C++ 编程中,指针是一个重要的概念。指针允许程序访问内存地址,间接操作数据。通常情况下,指针会指向特定类型的数据,例如 int *、char * 或 float *。然而,C++ 还提供了一种特殊类型的指针——void *,即“无类型指针”。与其他类型的指针不同,void * 可以指向任何类型的数据,这使得它在某些特定场景下非常有用。然而,void * 也有其限制和注意事项,理解这些限制对于避免潜在的错误至关重要。 2025.2.5-✍32min

禅宗里有一个词叫做“因缘和合”。 所谓因缘,是指事件要发生所必须的条件。因缘和合就是当你聚集了这件事的一切条件,它就会自然而然的发生。“它就会自然而然的发生”,这种朴素而坚定的价值观让我们感到无比安心,安心到可以不用有任何担心焦虑。 1555

UFSV3.1-RPMB实现与测试

UFS RPMB功能验证与测试指南 本文介绍了UFS(通用闪存存储)中RPMB(重放保护内存块)的功能验证与测试方法。主要内容包括: RPMB基础配置: 在Linux系统中查看RPMB设备节点 读取RPMB单元描述符获取配置信息 配置RPMB区域大小(16MB)和使能状态 RPMB特性验证: 获取单次写最大请求(16KB) 测试未编程认证密钥时的读写操作 验证认证密钥编程过程 测试用例: 包含4个测试用例,验证RPMB在不同状态下的行为 提供了详细的命令行操作和预期结果 本文可作为UFS RPMB功能验证。

小码哥的博客 1254

第3章 基于三电平空间矢量的中点电位平衡策略

本文档深入探讨了基于三电平空间矢量的中点电位平衡策略。重点在于NPC型三电平逆变器的中点电位平衡问题,由于三电平结构的特点,使得直流侧两个电解电容器的充放电不均匀导致中点电压不均衡。文章通过对不同矢量作用下电流、电压的变化进行了详细的定量和定性分析,并提出了利用冗余小矢量的合理配置以及引入调制因子来解决中点电位偏移的方法,确保中点电压在一个完整的开关周期内的稳定性,进而提高系统的可靠性。

嵌入式老牛的博客 2182

void* data 数据类型参数以及void *data[ ]解释

void 在英文中作为名词的解释为 “空虚、空间、空隙”,而在 C 语言中,void 被翻译为"无类型",相应的为"无类型指针"。 似乎只有"注释"和限制程序的作用,当然,这里的"注释"不是为我们人提供注释,而是为编译器提供一种所谓的注释。void data[ ]是个什么鬼?1、先来解决形如 type name[ ]的问题。这里有一个比较实在的推断方法,指的是一个数组有48个元素,每个元素都是int类型,指的是一个数组有48个元素,每个元素都是int类型需要注意先表述元素个数再表述元素类型,这么表述的情况下

森明帮大于黑虎帮的博客 5473

1、信息与物理世界:“It from Bit”还是“Bit from It”?

这篇博文探讨了物理学与信息理论之间的深刻联系,从惠勒提出的“It from Bit”概念出发,讨论了信息是否是物质世界的基础,或者物质是否是信息的来源。文章回顾了2013年举办的征文竞赛以及众多学者对这一问题的不同观点,涵盖了量子理论、热力学、计算机科学、黑洞物理以及时空本质等多个领域。同时,文章还分析了信息理论在哲学层面的含义,并展望了其在未来理论、实验和应用研究中的潜力与方向。

water的专栏 289

论void void*及void**类型

1、void的作用 c语言中,void为“不确定类型”,不可以用void来声明变量。如:void a = 10;如果出现这样语句编译器会报错:variable or field ‘a’ declared void。在C语言中void 常常用于:对函数返回类型的限定和对函数参数限定:    (1)对函数返回类型的限定:当函数不需要返回类型是必须用void 来限定返回类型,限定了函数的返回类型为void后函数不能有返回值;如:void fun(int a);  (2)对函数参数类型的限定:当函数不允许接受

tecoes的博客 4435

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

void类型和void* 的用法

C语言中的void 和 void * 总结 1、void的作用   c语言中,void为“不确定类型”,不可以用void来声明变量。如:void a = 10;如果出现这样语句编译器会报错:variable or field ‘a’ declared void。   在C语言中void 常常用于:对函数返回类型的限定和对函数参数限定     (1)对函数返回类型的限定:当函数不...

dianzhi8696的博客 2048

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

从新手到专家:彻底搞懂C语言void*指针强制转换的4个阶段

掌握C语言void*指针强制转换规则,解决内存操作难题。详解四大阶段:通用指针原理、类型安全转换方法、动态内存与函数传参应用。清晰解析适用场景与避坑要点,提升代码健壮性,值得收藏。

LiteTrans的博客 1136

【C语言底层编程必修课】:void*转换的6条黄金准则与实战应用

掌握C语言void*指针转换难题?本文详解C语言void*指针强制转换规则,涵盖内存操作、函数传参等场景的6条黄金准则,确保类型安全与代码稳定,提升底层编程效率,值得收藏。

DevPath的博客 860

一个建立线程时常见的问题:invalid conversion from `void*' to `void*(*)(void*)

本文已移至【Linux开发技术之常见问题】一个建立线程时常见的问题:invalid conversion from `void*' to `void*(*)(void*)

gnuhpc的专栏 7136

void *通用指针

`void *` 是一种无类型指针,可以指向任何数据类型(如 `int`、`float`、结构体、数组等)。`void *` 是 C 语言中的一种特殊指针类型,称为 **通用指针(void pointer)**。// 接受 void *,可以释放任意类型的内存。- 由于 `void *` 是无类型指针,编译器不知道它指向的数据类型,因此不能直接解引用。- 使用 `void *` 时需要小心类型转换,确保转换后的类型是正确的。- `void *` 是 C 语言中的通用指针,可以指向任意类型的数据。

qq_53042961的博客 510

c语言void draw函数,c语言中的void和void*

voidvoid最常见的用法,就是在函数中限定函数的参数和返回值的 void draw(void);表明函数draw没有参数也没有返回值,void在别的的地方的应用我也没见过;实际上,如果把void 和int,char,double等类型放到一起理解的话,首先还是那句揭示本质的话:变量类型就是固定大小内存块的别名,那么void占用多大内存呢,编译器并没有定义void占用多大内存,所以对于void...

weixin_34898216的博客 2394

C语言:void的用法即解析

一、理解void的能否定义变量 二、void 作为函数返回值以及函数参数 三、void指针的用法

zhou_zhou_04的博客 2万+

C++类型转换的陷阱:void*转换的安全隐患与实践

在C++编程中,类型转换是一项常见的操作,尤其是在处理低级别数据操作或多态性时。然而,不当的类型转换可能会引发严重的安全隐患和运行时错误。在本章中,我们将探讨类型转换的需求背景,特别是那些可能导致潜在风险的操作,如将`void*`指针转换为具体类型的指针。

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 7208

c语言返回void*,C语言中的void 和 void * 的区别

1、void的作用c语言中,void为“不确定类型”,不可以用void来声明变量。如:void a = 10;如果出现这样语句编译器会报错:variable or field ‘a’ declared void。在C语言中void 常常用于:对函数返回类型的限定和对函数参数限定(1)对函数返回类型的限定:当函数不需要返回类型是必须用void 来限定返回类型,限定了函数的返回类型为void后函数不能...

weixin_34298263的博客 649

c语言pthread创建线程失败,c++创建线程的常见问题:error: invalid conversion from 'void*' to 'void* (*)(void*)'...

重点:注意,这里只能写gcc,究其原因就是C语言编译器允许隐含性的将一个通用指针转换为任意类型的指针,而C++不允许的。本人近期在做按tcp流发送数据包的学习,一来二去接触到了多线程。我百度照此写了个多线程代码,如下:#include #include #include void thread(void *arg);void thread(void *arg){int i;for(i = 0; i...

weixin_29470893的博客 3894

c语言 弱类型,关于强类型:C#是强类型还是弱类型语言?

本问题已经有最佳答案,请猛点这里访问。有人能解释一下C语言是强型还是弱型?解释原因。如果我有一个名为concat的函数,它可以接受任何对象,那么这就是弱类型吗?function concat(Object stuff){//do something here to stuff}下议院的人想给出一个理由,这样@mrshll187就可以知道将来要避免做什么了吗?@Abemiessler你的意思是像SE...

weixin_26882891的博客 1109

避免段错误的关键:void*指针类型转换必须遵守的5项铁律

掌握C语言void*指针强制转换规则,避免段错误的关键方法。适用于动态内存分配、函数通用参数等场景,详解类型对齐、目标类型一致性、合法内存访问等5项铁律。提升代码稳定性与安全性,值得收藏。

LogicWander的博客 835
上一篇: 27. 【C语言】编写可移植的头文件与模块
下一篇: 29. 【C语言】动态数据结构:单向链表
gugucoding
博客等级 码龄140天 7粉丝 102原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值