请求分页内存管理的模拟 c++代码_C开发实战-内存管理

作用域和变量

作用域就是作用的范围,当定义变量时不同作用域的变量位于不同的内存空间。
变量按照不同的作用域可以分为局部变量和全局变量。而局部变量和全局变量都可以使用static修饰,static修饰的局部变量叫静态局部变量,static修饰的全局变量叫静态全局变量。当定义一个变量时,除了要考虑初始化赋值以外,还要注意变量的作用域和生命周期。

局部变量

局部变量定义在{}内,其作用域在{}内部有效,出了{}变量就无法使用。
局部变量如果没有初始化赋值,系统会给局部变量随机赋垃圾数值。

生命周期表示变量从开辟内存空间(生)、释放内存空间(死)的过程。

通常局部变量的生命周期在定义时开辟内存空间,在所在的函数执行结束后释放内存空间

#define _CRT_SECURE_NO_WARNINGS#include #include /*在自定义方法中定义和使用局部变量*/void print_local_variable_value() {printf("execute print_local_vairbale_value() method ");//局部变量 ,作用域在定义时{}之内int age = 29;//静态局部变量static double dbl = 3.14;printf("局部变量 age =%d", age);printf("静态局部变量 dbl =%lf", dbl);//定义局部变量时开辟内存空间,函数结束之后释放内存空间int number = 10;int* p = NULL;if (number) {//局部变量在函数结束之后释放空间int data = 20;p = &data;printf("number = %d ", number);}//超过了data的作用域,无法访问data变量//data = 100;//通过指针获取局部变量的值printf("*p=%d ", *p);//通过指针修改局部变量的值*p = 30;printf("*p=%d ", *p);}/*局部变量定义和使用注意事项@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){printf("execute main method ");//无法在main()函数中使用print_local_variable_value()方法定义的局部变量//printf("局部变量 age =%d",age);//printf("静态局部变量 dbl =%lf",dbl);print_local_variable_value();system("pause");return 0;}

程序运行结果

1e38bc839c4db213353e07b73bcbdcae.png

在使用局部变量时不应该将局部变量的地址用作函数的返回值,否则会引发程序异常。

#define _CRT_SECURE_NO_WARNINGS#include #include #include /*自定义方法返回定义的局部变量地址*/int* return_local_variable_address() {int x = 100;Sleep(5000);//返回局部变量x的地址return &x;}/*局部变量的返回值问题@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){int* p = return_local_variable_address();printf("return_local_variable_address()方法的返回值是%d", *p);*p = 800; // p所指向的空间已经被释放,不能操作这块内存printf("*p = %d", *p);system("pause");return 0;}

形参的本质就是局部变量,基本类型作为形参时不能返回形参的地址,而指针类型的形参可以作为返回值

#define _CRT_SECURE_NO_WARNINGS#include #include /*形参的本质就是局部变量*/int* change_value(int data) {data += 100;return &data; //不可以返回形参的地址}int* change_pointer(int *p) {int i = 10;*p = *p + i;return p; //返回地址 }/*返回指针的地址@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){int value = 200; change_value(value);int* p=change_pointer(&value);system("pause");return 0;}

静态局部变量

静态局部变量是使用static修饰的局部变量,如果在定义静态局部变量时没有赋值,如果变量类型是整数类型默认初始化值为0,其作用域和局部变量一样,也是在其定义的{}之内有效。
静态局部变量在main函数运行之前就已经开辟空间,而且静态全局变量只会有唯一一份内存空间,在程序结束之后释放内存空间。

#define _CRT_SECURE_NO_WARNINGS#include #include /*在自定义方法中使用静态局部变量*/void print_static_local_variable_value() {//静态局部变量//在main函数之前会开辟内存空间存储number的值static int number=1;number++;//第一次调用print_static_local_variable_value()方法 number = 2;//第二次调用print_static_local_variable_value()方法 number = 3;printf("number = %d",number);{static int sum = 5050;}//此处不能使用sum,因为除了sum的作用域//printf("sum = %d ",sum):}/*静态局部变量的定义和使用@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){print_static_local_variable_value();//当再次调用print_static_local_variable_value()方法修改静态全局变量时不会再为静态局部变量number开辟内存空间print_static_local_variable_value();system("pause");return 0;}

当在main函数中多次调用print_static_local_variable_value()方法修改静态全局变量时不会再为静态局部变量number开辟内存空间,即static int number=1;在整个程序的生命周期只会执行一次。

程序运行结果

81fb411251e803a399aa5b86fd57a3c9.png

由于静态据变量的声明周期是在程序退出时才会释放内存空间,因此静态局部变量可以作为函数的返回值。

#define _CRT_SECURE_NO_WARNINGS#include #include /*自定义方法返回定义的局部变量地址*/int* return_static_local_variable_address() {static int x = 100;printf("x = %d",x);//返回静态局部变量x的地址return &x;}/*    静态局部变量作为函数的返回值@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){int* p = return_static_local_variable_address();printf("return_static_local_variable_address()方法的返回值是%d", *p);//修改变量x的值*p = 800;printf("*p = %d", *p);return_static_local_variable_address();system("pause");return 0;}

程序运行结果

205f01c8afd64cfc19362a5256d7e642.png

全局变量

全局变量即定义在函数外部的变量,如果全局变量类型是int,声明全局变量时默认初始化值为0。全局变量的生命周期是在main函数执行之前开辟空间,在程序结束后释放内存空间。

由于全局变量在程序结束运行时才会释放内存空间,因此在日常开发中尽量少用全局变量。

#define _CRT_SECURE_NO_WARNINGS#include #include //全局变量定义在函数外部,作用域在整个项目//执行main函数之前开辟内存空间,程序结束释放内存空间int x;void changex() {printf("execute changex()method");printf("初始化全局变量x = %d ",x);//在自定义函数修改全局变量的值x = 20;printf("修改全局变量x之后x = %d ", x);}/*全局变量的定义和使用@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){printf("inside method()");//在不同的函数之间访问全局变量xchangex();printf("main method x = %d ",x);system("pause");return 0;}

全局变量的作用域在整个项目内都可以访问,例如在global_variable.c中定义了全局变量int x;在同一个项目的另外一个文件global_variable_acces.c中访问。不过在使用之前需要使用extern关键字显示声明 extern int x;

#define _CRT_SECURE_NO_WARNINGS#include #include /*不同文件的全局变量的访问@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*///显示声明整型变量x,即告知编译器x在其他地方定义过,此处通过编译extern int x;int main(int argc, char* argv[]){//修改全局变量x的值为100x = 100;printf("全局变量x = %d",x);system("pause");return 0;}

程序运行结果

b014d48739df02809cc02679d8e9070a.png

静态全局变量

静态全局变量就是使用static修饰的全局变量,静态全局变量的作用域在当前文件有效,而不能像全局变量一样跨文件使用。也不能使用extern关键字显示声明。
静态全局变量的声明周期也是在执行main()函数之前开辟内存空间,在程序结束时释放内存空间。静态局部变量声明时如果是int类型,那么初始化默认值也是0。如果是double类型初始化默认值为0.0;

#define _CRT_SECURE_NO_WARNINGS#include #include static double dbl;void change_dbl() {dbl = 5.67;printf("dbl = %.2lf", dbl);}/*静态全局变量的定义和使用@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){//打印静态全局变量dbl的默认初始化值printf("静态全局变量dbl的默认初始化值为:%.2lf",dbl);dbl = 3.14;printf("dbl = %.2lf",dbl);//在自定义方法中修改静态全局变量的值change_dbl();system("pause");return 0;}

程序运行结果

b01d515a72c637741cb59be4ddfe4b75.png

静态成员变量的注意事项

#define _CRT_SECURE_NO_WARNINGS#include #include // 不能使用extern显示声明静态全局变量//extern double dbl;/*静态全局变量的使用注意事项@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){// 不能跨文件使用静态全局变量//dbl = 3.14;//printf("静态全局变量dbl = %.2lf", dbl);system("pause");return 0;}

作用域和变量最佳实践

在多文件编程时,通常将变量、函数的定义放在源文件中(例如这里的global_variable.c),将变量、函数的声明放在和源文件同名的头文件(例如这里的global_variable_access.h)中。

#pragma once#pragma once//显示声明整型变量x,即告知编译器x在其他地方定义过,此处通过编译extern int x;//显示声明函数extern void changex();

然后在源文件global_variable_access.c中包含头文件global_variable_access.h,就可以使用声明的全局变量和函数

##define _CRT_SECURE_NO_WARNINGS#include #include #include "global_variable_access.h"/*不同文件的全局变量的访问@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){//修改全局变量x的值为100x = 100;printf("全局变量x = %d",x);changex();system("pause");return 0;}

程序运行结果

6227c4d166a57b7ac5e61b1109025461.png

不同作用域的变量名相同是可以共存的,但是需要注意的是相同作用域的变量名重名是不行滴。

在源文件diff_scope_static_global_variable.c中定义静态全局变量并在方法中打印初始值

#include static int number = 10;void print_static_global_variable_number() {printf("static global variable number = %d",number);}

在头文件diff_scope_variable_duplication.h中显示声明print_static_global_variable_number()函数。

#pragma onceextern void print_static_global_variable_number();

在源文件diff_scope_variale_duplication.c中定义和使用全局变量,局部变量

#define _CRT_SECURE_NO_WARNINGS#include #include #include "diff_scope_variable_duplication.h"//定义全局变量 初始化赋值为10int data = 10;int get_value() {int data = 100;{int data = 200;}//此时打印输出data =10 printf("get_value() method local variable data= %d",data);return data;} /*不同作用域的变量重名@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){print_static_global_variable_number();int value = get_value();printf("value = %d",value);printf("global variable data= %d",data);system("pause");return 0;}

程序运行结果

ca1403853678b348265950146c8c3bbb.png

局部变量的地址不能作为方法的返回值,因为局部变量的内存空间在所在的函数结束后就会被释放,而静态局部变量,全局变量和静态全局变量的地址可以作为函数的返回值。因为程序结束之前静态局部变量,全局变量,和静态全局变量在程序结束之前内存空间不会被释放。

静态函数

默认定义的函数就是全局函数,其作用域可以在整个工程中使用,如果是跨文件使用,在头文件中使用extern显示声明即可,没有局部函数。
而使用static修饰的函数是静态函数,其作用域是只能在当前源文件中使用。

当前文件中定义和使用静态函数是ok的

#define _CRT_SECURE_NO_WARNINGS#include #include /*定义静态函数*/static double get_dbl() {double dbl = 3.14;return dbl;}/*静态函数的定义和使用@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){double dbl = get_dbl();printf("dbl = %.2lf",dbl);system("pause");return 0;}

但是跨文件使用时,系统会提示无法解析的外部符号_get_dbl

9e907e5b7452ccb7659e21ade8df3459.png

内存的结构

当程序编译、链接完成时,编译器已经规划好了内存空间,拿出当年写的helloworld程序

#include int main(){    printf("Hello c with Windows10 1903 & Visual Studio Code & MinGW7.3.0 ");    return 0;}

在Windows上使用size helloworld.exe查看内存,单位大小以字节(Byte)为单位

c84d77071887e521d04d5d410cf4c020.png
  • text表示代码区
  • data表示数据区,用于存放全局变量,
  • bss表示未初始化的数据区
  • dec表示 text+data+bss的大小

当在helloworld源程序中定义一个全局变量时,编译器会重新规划数据区的大小

#include int number=100; //定义全局变量,初始化赋值为100int main(){    printf("Hello c with Windows10 1903 & Visual Studio Code & MinGW7.3.0 ");    return 0;}
fde6656d25e79627763d043bcb4835ce.png

data

当在helloworld源程序汇中声明一个全局变量时,未初始化数据区也会发生变化。

#include int number=100; //定义全局变量,初始化赋值为100int age;int main(){    printf("Hello c with Windows10 1903 & Visual Studio Code & MinGW7.3.0 ");    return 0;}
1350b3869c7571e48598f1839908c0f5.png

bss

而局部变量时在程序运行时分配空间,内存由栈区、堆区、静态全局区、代码区组成。

2d922bf919dc62bdc6796c1da15e2afa.png

内存结构

定义不同类型的变量

  • 未初始化的全局变量a,未初始化的静态全局变量b,g位于未初始化的静态全局区
  • 初始化的全局变量c,初始化的静态全局变量d,h位于已初始化的静态全局区
  • 未初始化的局部变量e,i和初始化的局部变量f,j位于栈区
#define _CRT_SECURE_NO_WARNINGS#include #include //未初始化的全局变量aint a;//未初始化的静态全局变量static int b;//初始化的全局变量int c = 10;//初始化的静态全局变量static int d = 20;/*内存的结构@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){//未初始化的局部变量int e;//初始化的局部变量int f = 10;//未初始化的静态局部变量static int g;//初始化的静态局部变量static int h = 10;//初始化的局部变量 test在常量区char* i = "test";//初始化的局部变量char* j = NULL;printf("未初始化的全局变量a的地址是%p",&a);printf("未初始化的静态全局变量b的地址是%p",&b);printf("初始化的全局变量c的地址是%p",&c);printf("初始化的静态全局变量d的地址是%p",&d);printf("未初始化的局部变量e的地址是%p",&e);printf("初始化的局部变量f的地址是%p",&f);printf("未初始化的静态局部变量g的地址是%p",&g);printf("初始化的静态局部变量h的地址是%p",&h);printf("初始化的char*类型局部变量i的地址是%p",&i);printf("初始化的char*类型局部变量j的地址是%p",&j);system("pause");return 0;}

获取变量的地址时,相同类型的存储区域的地址编号是相近的

程序运行结果

35454b5504542f49fd8cfbb1db3b72f4.png

内存处理函数

内存清零函数memset()

memeset()函数用于将指定的内存清零

#define _CRT_SECURE_NO_WARNINGS#include #include #include /*memset()函数的使用@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){int number = 10;//等价于 number = 0;memset(&number, 0, sizeof(number));printf("number = %d ",number);char buf[10]="";//清空bufmemset(buf, 0, sizeof(buf));for (int i = 0; i < sizeof(buf) / sizeof(buf[0]);i++) {printf("buf[%d]=%s ",i,buf[i]);}printf("将buf数组的前九个元素置为a");//将buf数组的前九个元素置为amemset(buf,'a',sizeof(buf)-sizeof(buf[0]));for (int i = 0; i < (sizeof(buf) / sizeof(buf[0]))-1; i++) {printf("buf[%d]=%c ", i, buf[i]);}system("pause");return 0;}

程序运行结果

a9cbb21cf8b39fed37b80c04fd5fa450.png

内存拷贝memcpy()函数

memcpy()函数实现整数数组指定大小的元素拷贝

#define _CRT_SECURE_NO_WARNINGS#include #include #include /*memcpy()函数拷贝整数数组@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){int source[10] = {1,2,3,4,5,6,7,8,9,10};int target[10] = {0};//将source数组的元素拷贝10个到targetmemcpy(target, source, sizeof(source));printf("遍历拷贝之前source数组的元素");for (int i = 0; i < sizeof(source) / sizeof(source[0]); i++) {printf("target[%d] = %d ", i, source[i]);}printf("遍历拷贝之后target数组的元素");for (int i = 0;i

程序运行结果

fed5d859fed333e5bc10f976c6df45e7.png

memcpy()函数实现指定字符串的拷贝,相比于strncpy()函数,memcpy()函数在拷贝字符串时遇到了'0'也不会停止拷贝

#define _CRT_SECURE_NO_WARNINGS#include #include #include /*memcpy()函数拷贝字符数组memcpy()函数对比strncpy()函数@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){char str1[128] = "";char str2[128] = "hello0wo0rld";printf("使用memcpy()函数将str2数组的10个元素拷贝到str1数组中");memcpy(str1, str2, 10 * sizeof(char));printf("遍历拷贝之后的str1数组的元素列表");for (int i = 0; i < 10;i++) {printf("%d",str1[i]);}printf("");//相对于strnpy()函数,memcpy()遇到'0'不会停止拷贝printf("使用memset()函数将str1数组的元素清空");memset(str1, 0, sizeof(str1));printf("使用strncpy()函数将str2数组的10个元素拷贝到str1数组中");strncpy(str1, str2, 10);printf("遍历拷贝之后的str1数组的元素列表");for (int i = 0; i < strlen(str1); i++) {printf("%d", str1[i]);}printf("");system("pause");return 0;}

内存比较memcmp()函数

memcmp函数用于实现内存的比较,相较于strcmp()函数在遇到‘0’时不会停止比较

#define _CRT_SECURE_NO_WARNINGS#include #include #include /*内存比较memcmp()函数@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){int source[10] = {1,2,3,4,5,6,7,8,9,10};int target[10] = {1,2,3,4,5,6,7,8,9,10};int result =memcmp(source, target, 10 * sizeof(int));printf("source和target两个整数数组比较的结果是%d",result);//清空target数组的内容memset(target, 0, sizeof(target));result = memcmp(source, target, 10 * sizeof(int));printf("清空target数组的内容后source和target两个整数数组比较的结果是%d", result);//memcmp函数和strncmp函数的比较char str1[128] = "hello0agian";char str2[128] = "hello0seeyouagain";//strcmp函数遇到0会结束比较printf("使用strcmp函数比较str1和str2大小的结果是%d",strcmp(str1,str2));//memcmp函数遇到0不会结束比较printf("使用memcmp函数比较str1和str2大小的结果是%d",memcmp(str1,str2,128*sizeof(char)));system("pause");return 0;}

程序运行结果

e80f5e04676b7b41539cdc9a6ea84dfd.png

因此得出结论:内存操作函数遇到0或者0都不会结束处理,而字符串处理函数遇到0结束处理。

堆内存申请和释放

当处理的数据比较大,可以向堆申请空间,C语言提供了malloc()函数来申请堆内存空间。
malloc()函数需要的参数是字节数量,返回类型为void *即万能指针,如果申请的空间存放的数据是字符,void * 可以转换为char *,如果申请的空间存放的是整数,void *可以转换为int *。

如果malloc()函数申请的堆内存空间不再使用,可以使用free()函数来释放堆内存空间,不能释放栈空间,需要注意的是只能申请一次,释放一次,而且是同一内存地址。如果释放了多次会造成系统异常。

#define _CRT_SECURE_NO_WARNINGS#include #include #include /*堆内存申请和释放malloc()函数:申请堆内存空间,返回内存首地址,返回类型为void *,参数为字节的数量@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){//申请4个字节的堆内存空间,返回一个地址 void *// 需要将void *强制类型转换为int* int * p=(int *)malloc(sizeof(int));//操作堆内存*p = 100;printf("堆内存:*p = %d",*p);// 申请一个数组,数组有10个元素,元素的类型为intint *p_array=(int*)malloc(sizeof(int[10]));//给第六个元素赋值为200*(p_array + 5) = 200; //给最后一个元素赋值100p_array[9] = 100;for (int i = 0; i < sizeof(int[10]) / sizeof(int);i++) {printf("*p_array[%d] = %d",i,*(p_array+i));}// 申请一个字符数组 存储1024个元素char* p_char =(char*)malloc(1024);//空间清零memset(p_char, 0, 1024);// 空间释放,malloc申请的空间只能释放一次free(p_char);system("pause");return 0;}

程序运行结果

4fa7b817a88ca5bc511cbe5c7791ba72.png

生产环境的都是7*24小时不间断运行,如果程序一直在申请内存空间,而不释放内存空间,导致程序使用的内存空间一直增长,就会造成内存泄漏。程序退出后,程序使用的所有内存才会释放。日常开发中应该尽量避免内存泄漏,除此以外还有内存污染的问题,即没有申请空间,就往空间中写数据。

堆内存地址可以作为函数的返回值,因为堆内存在函数结束时不会被释放空间,但是在操作堆内存时需要注意一些问题

#define _CRT_SECURE_NO_WARNINGS#include #include char* malloc_heap() {//申请128个字节的堆内存char* q = malloc(128);return q; //堆区的地址是可以返回,因为函数结束不会释放堆内存}/*返回堆内存的地址@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){char* p = malloc_heap();//将hello字符串拷贝到p指向的堆内存空间strcpy(p, "hello");//释放堆内存free(p);/*********错误的堆操作*********///此时p指向了文字常量区//p = "hello";//此时释放的不是堆内存//free(p);system("pause");return 0;}

通过函数的值传递不能改变变量的值,即实参的值不会改变形参的值,但是传递实参的地址可以调用函数改变实参的值。
能不能返回地址,需要看地址指向的空间有没有被释放。

#define _CRT_SECURE_NO_WARNINGS#include #include #include void malloc_q(char *q ) {// q指向堆内存q = malloc(1024);return;}/*实参作为一级指针地址@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){//实参是一级指针char* p = NULL;malloc_q(p);//bug 因为p指向NULL,无法实现字符串复制strcpy(p,"helloworld");printf("p = %s",p);system("pause");return 0;}

如果要解决该问题,将q的指针返回即可。

#define _CRT_SECURE_NO_WARNINGS#include #include #include char* malloc_q(char *q ) {// q指向堆内存q = malloc(1024);return q;}/*实参作为一级指针地址@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){//实参是一级指针char* p = NULL;p=malloc_q(p);strcpy(p,"helloworld");printf("p = %s",p);system("pause");return 0;}

程序运行结果

b143a51418c31bbd09b4cc35e70a85d8.png

另外一种解决方法

#define _CRT_SECURE_NO_WARNINGS#include #include #include char* malloc_q(char **q ) {// q指向堆内存*q = malloc(1024);return q;}/*实参作为一级指针地址@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/27*/int main(int argc, char* argv[]){//实参是一级指针char* p = NULL;malloc_q(&p);//bug 因为p指向NULL,无法实现字符串复制strcpy(p,"helloworld");printf("p = %s ",p);system("pause");return 0;}

程序运行结果

d9282f4300aae944cef8011f4c2d946f.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值