hello word的前生后世 | C++基础

标准输出函数说明

头文件:stdio.h

原型:int printf(const char *format,…);

format : 格式控制字符串

…: 可变参数列表

返回值:输出字符的数量

printf("%d\n",printf("%d",n));//输出一个n和n字符的数量
标准输入函数说明

头文件:stdio.h

原型:int printf (const char *format,…);

format : 格式控制字符串

…:可变参数列表

返回值:成功读入的参数个数

&n:传出参数

合法性:返回值 >= 0

scanf("hello");//返回值为0
(根据非法)循环读入
while(scanf() != EOF);//EOF为end of file,在这里为-1
取反循环读入
while(~scanf("%d", &n));
带空格输入字符串:
scanf("%[^\n]s", str);//[^\n]为除了'\n',整句为除了换行都输入

弊端:没有处理掉‘\n’,在输入完毕按回车时输入一个换行,换行一直存在,会导致一个死循环,就是一直换行输入换行之前输入的字符串,但是只有换行之前输入是有效的,scanf返回值为换行之前成功输入的参数个数

处理:吐掉换行

getchar();

这个函数可以吐掉上一个字符

sprintf 、fprintf

sprintf 、 sscanf -> string -> 字符串拼接【输出到字符串中去、从字符串中输入】

fprintf 、fscanf -> file -> 中文件操作【输出到文件中去、从文件中输入】

#include<stdio.h>

int main(){
    int n;
    char str[100] = {0};
    int arr[4] = {0};
    //scanf("%d", &n);
    //printf("%d\n", n);
    sprintf(str, "%d.%d.%d.%d", 192, 168, 0, 1);//拼接字符串到str
    printf("str = %s\n", str);//打印字符串str
    sscanf(str, "%d.%d.%d.%d", &arr[0], &arr[1], &arr[2], &arr[3]);//从str字符串中输入
    for(int i = 0; i< 4; i++){
        printf("%d\n", arr[i]);//标准输出
    }
    FILE *fp = fopen("./output","a+");//打开文件output,“a+”为追加性写入
    fprintf(fp, "str = %s\n", str);//从fp指向的文件output中输出str
    fclose(fp);//关闭fp指向的文件output
    char ans[100] = {0}, temp;
    int offset = 0;
    FILE *fin = fopen("./output", "r");//打开文件output,“r”为可读性
    while(fscanf(fin, "%c", &temp) != EOF){//从fin指向的文件中输入到temp中
        offset += sprintf(ans + offset, "%c",temp);//一个temp拼接到ans + offset,offset为中间变量,比如ans + 1为数组位置,最终保存文件全部内容到ans中,offset += sprintf()返回值,每次加一
    }
    fclose(fin);//关闭fin指向的文件
    printf("%s\n", ans);//标准输出ans
    return 0;
}

位运算(二进制)

位权:比如二进制的位权就是pow(2,n-1),十进制的位权就是pow(10,n-1),n为位数

& :有0则0

判断奇偶:

n & 1 == 1 为奇数

| :有1则1
^ :(逆运算)同为0,异为1

【必须是整型值】

作用:

1、交换

aba=b

a ^=b;
b ^=a;
a ^=b;

a’ = a ^ b;

b’ = b ^ a’ = b ^ a ^ b = a;

a’’ = a’ ^ b’ = a ^ b ^ a = b;

~ :取反

​ 作用:

1、循环读入
while(~scanf("%d", &n));

-1

原码: 0000 0000 0000 0000 0000 0000 0000 0001

取反:1111 1111 1111 1111 1111 1111 1111 1110

加1: 1111 1111 111 1111 1111 1111 1111 1111

~(-1):0000 0000 0000 0000 0000 0000 0000 0000

(~scanf(“%d”, &n)):在scanf返回值前取反,当成功读入参数个数大于或等于0时,即为真值,就可进行循环;当成功读入参数为-1时,即为0时,即为假值时,结束读入循环。

2、竖式计算

-2= -1 - 1

​ 1111 1111 111 1111 1111 1111 1111 1111

— 0000 0000 0000 0000 0000 0000 0000 0001


​ 1111 1111 111 1111 1111 1111 1111 1110

<<,>>:左右移,左移乘(*)2倍,空位补0。右移除(/)2倍,空位补符号位

数学函数库

pow 函数 :指数函数

​ 头文件:math.h

​ 原型:double pow(double a,double b);

​ a:底数

​ b:指数

​ 返回值:返回a的b次方

sqrt 函数 :开平方函数

​ 头文件:math.h

​ 原型:double sqrt(double x);

​ x :被开方数

​ 返回值:返回根号x

ceil 函数 :上取整函数

​ 头文件:math.h

​ 原型:double ceil(double x);

​ x :某个实数

​ 返回值:返回[x] 例子: ceil(4.1) = 5

floor 函数 :下取整函数

​ 头文件:math.h

​ 原型:double floor(double x);

​ x :某个实数

​ 返回值:返回[x] 例子:floor(4.9) = 4

/*abs 函数 :整数绝对值函数

​ 头文件:stdlib.h

​ 原型:int abs(int x);

​ x :某个整数

​ 返回值:返回|x| 例子:abs(-4) = 4 */

fabs 函数 :实数绝对值函数

​ 头文件:math.h

​ 原型:double fabs(double x);

​ x :某个实数

​ 返回值:返回|x| 例子:abs(-4.5) = 4.5

log 函数 :以e为底对数函数

​ 头文件:math.h

​ 原型:double log(double x);

​ x :某个实数

​ 返回值:返回logeX 例子:log(9) = 2.1972…

log10 函数 :以10为底对数函数

​ 头文件:math.h

​ 原型:double log10(double x);

​ x :某个实数

​ 返回值:返回log10X 例子:log10(100) = 3

注意:其他底数可以用换底公式来转换

acos 函数 :acos函数

​ 头文件:math.h

​ 原型:double scos(double x);

​ x :角度的弧度值

​ 返回值:返回arccos(x) 例子:acos(-1) = 3.1415926…

比较运算符

代表假值:0、NULL、‘\0’

‘==’: 如果a == b,则返回值为真值,反则为假值

‘!=’ : 如果a!=b,则返回值为真值,反则为假值

‘<=(=<) 、 =>(>=)’

‘!’:注意 ‘!!(x)’ 为逻辑归一化,把真值归为1,把假值归为0.如!(3) = 0,!!(3) = 1;

分支结构

一条语句:空语句、单语句(分号结束前面的单行语句) 、复合语句(花括号{}中间的语句)

if 语句

if成立 作用一条语句

switch 语句
CPU的分支预测

一个指令整个操作(每一步需要一个时钟周期):

F:取指

D1:指令与解析

D2:数据与解析

EX:执行

WB:返回

时钟周期:上面每一个部分为一个时钟周期

串行执行:执行完一整个操作(整个操作包括一系列指令)再进行下一个操作,也就是一个指令执行完得等整个操作执行完才再开始执行。比如执行一个指令要五个时钟周期,执行五个指令要二十五个时钟周期

并行执行:如下图,五个指令执行完需要九个时钟周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FDzgfdP3-1678493644813)(C:\Users\86166\AppData\Roaming\Typora\typora-user-images\image-20210529195914588.png)]

CPU就是并行执行if语句,也就是if和else同时执行,但是只能执行if或者else,所以CPU有个分支预测,根据以前的习惯来预测执行,所以就存在分支预测失败,如果有过多的if语句分支预测失败可能性提高,但是当预测失败,CPU有套容错的机制,会自我检查的机制,出错时CPU会将中间运行的指令全部推掉,重新再来,并且改为串行执行方式来执行,这样执行的时间就会变得较长。

通过利用宏来提高分支预测的成功率:

Unix中的两条宏:

#define likely(x) //likely 代表x经常成立

#define unlikely(x) //unlikeil 代表x不经常成立

__builtin_expect(!!(x),1)

__builltin_expect(!!(x),0)

这里的 builtin_expect(!!(x), 1) 就是告诉CPU x为1经常成立,提高分支预测成功的可能性,同样builltin_expect(!!(x),0) 就是告诉CPU x为负不经常成立

附录:

__builtin_expect (long exp, long c):用来引导gcc进行条件分支预测

__builtin_ffs(x):返回x最后一个为1的位是从后向前的第几位

__builtin_popcount(x):x中1的个数

__builtin_ctz(x):x末尾0的个数。x=0时结果未定义

__builtin_clz(x);x前导0的个数。x=0时结果未定义

__builtin_prefetch (const void *addr,…):对数据手工预取的办法

__builtin_types_compatible_p(type1,type2):判断type1和type2是否相同的数据类型

__builtin_constant_p (exp): 判断exp是否在编译时就可以确定其为常量

__builtin_parity(x):x中1的奇偶性

__builtin_return_address(n):当前函数的底n级调用者的地址

循环结构

while(表达式){},表达式为真则进入循环

do{}while(表达式), 一定循环一次

for(初始化;循环条件;执行后操作){};

逻辑运算符

&&短路原则为遇到假就不再运算后面的表达式

int a = 0, b = 0;
if((a++) && (b++)){}else{}
//到这a为1,b为0;

&&用于空格控制(最后一个元素后面没有空格):

普通的一个情况:

if(i != a[0]) printf(" ");//第一个元素前不加空格
printf("%_",a[i]);//其他元素前输出都带一个空格

利用&&短路原则:

i && printf(" ");//如果i不为0,就输出一个空格,如果为0则不输出
printf("%_",a[i]);
前后置运算

后置加加/减减:a++/a-- ,先返回a的值再加加/减减

前置加加/减减:++a/–a ,先加加/减减再返回a的值

随机数

rand()得到的随机数为伪随机数,即已经规定好的

srand(x) x为一个变量作为随机种子

#include<time.h>
srand(time(0));//time(0)为一个随机种子
函数定义声明

未声明 :错误暴露编译期(是否存在语法层面错误)

未定义:错误暴露链接期

源文件—>预编译(编译期)—>对象文件.o/.obj—>链接(a.out)/.exe(链接期)

编译头文件:g++/gcc -I./ -c xx.cc/xx.cpp

查看对象文件声明:ld xx.o

删除所有对象文件:rm *.o

链接多个对象文件:g++ xx.o xxx.o xxxx.o…

头文件源文件

源文件:xxx.c(c)、xxx.cpp/xxx.cc(c++)

头文件:xxx.h

包含:“ ” ,<>从系统库中

条件式编译:
#ifndef _HEAD3_H//如果没有定义_HEAD3_H
#define _HEAD3_H//就定义_HEAD3_H,_HEAD3_H部分可以自己命名
#endif

条件式编译有效地解决对于 一个(多个不行)源文件中编译链接所产生的重复包含问题。

包含多个头文件到一个头文件
#ifndef _HEAD3_H//如果没有定义_HEAD3_H
#define _HEAD3_H//就定义_HEAD3_H,_HEAD3_H部分可以自己命名
#include<head1.h>
#include<head2.h>
#include<head3.h>
       .
       .
       .    
#endif
工程开发规范:

头文件只能放声明,源文件只能放定义,

工程开发规范有效地解决对于 多个源文件中编译链接所产生的重复包含问题。

递归程序【系统栈】

程序调用自身的编程技巧叫做递归

递归程序的组成部分:

*(语义信息)

1、边界条件处理【出口】“需要提前设置”

2、针对于问题的处理过程和递归过程

【递推过程】(回溯):分为向下递归和向上递归,先向下再向上。可以根据数学归纳法对递推函数进行了解过程

3、结果返回【传出参数】

【系统栈】(FILo){最大为8MB,也就是200万个整型数据,大于200万则爆栈}:先进后出

函数指针(变量)
//下面是一个分段函数
int g(int (*f1)(int), int (*f2)(int), int (*f3)(int), int x);
//int (*f1)(int)中的int为f1的返回值类型,(*f1)【f1为函数指针变量名】为传进来f1的地址,(int)为传进来的参数列表
变参函数

如scanf()函数和printf()函数等变参函数

int max_int (int a, …);

va_list类型变量可以获得a往后的参数列表,也就是上面函数的( … )

va_start函数可以定位a往后第一个参数得位置

va_arg函数可以获取下一个可变参数列表中的参数

va_end函数结束整个获取可变参数列表的动作

#include<stdio.h>
#include<inttypes.h>
#include<stdarg.h>
int max_int(int n, ...){
    int ans =  INT32_MIN;//定义一个整型变量为最小值
    va_list arg; //arg为参数列表
    va_start(arg, n);// 获取n往后的第一个参数
    while(n--){
        int temp = va_arg(arg, int);//获取参数列表中的下一个参数
        if(temp > ans) ans = temp;
    }
    va_end(arg);
    return ans;
}

 int main(){
    printf("%d\n", max_int(3, 12, 0, -2));
     
    printf("%d\n", max_int(3, 22, 44, -2));
    printf("%d\n", max_int(3, 12, 0, -2));
     return 0;
 }

数组

相同类型变量的集合

数组清空:int a[1000] = {0};

a[1000]中的数组名a为该数组的首地址

函数是压缩的数组,数组是展开的函数,因为两者都满足映射关系

大小:n*sizeof(types)

随机访问:a[0] + i,a + i

传参:(根据表现形式一致)一维数组–>传地址,也就是数组首地址

高维数组–>也是传首地址,但函数定义形参时地址最多可以省略一个维度,如a[] [m],(*p)[m]

字符串

空格也为一个字符

任何一个字符都对应着一个整数值

字符串必须初始化,是为了防止丢掉/0

初始化字符数组:char str[] = “zhangyangsong” / char str[size] = {‘z’, ‘h’, ‘a’, ‘n’, ‘g’};

字符串相关操作:

头文件:string.h

strlen(str) 计算字符串长度,以\0作为结束符

strcmp(str1,str2); 字符串比较整型值和字典序

strcpy(dest, src) ;   字符串拷贝

因为以上两种以\0为结束符号,\0可能被覆盖丢失,容易照成数组的越界问题

strncmp(str1,str2,n); 安全的字符串比较

strncpy(str1,str2,n); 安全的字符串拷贝

memcpy(str1,str2,n); 内存拷贝

memcmp(str1,str2,n); 内存比较

memset(str1, c, n); 内存设置,初始化数组str为c值,n为内存大小,c值需要为内存内统一值;如整型1为10000000则不是,-1为11111111则是,0为00000000则是

结构体

struct P{

​ char name[20];

​ int age;

};

直接引用:P · name

间接引用:P —>name

内存大小:【申请空间的对齐方式】以其中内存最大数据类型内存为其中最小内存的整数倍,如结构体P中name申请sizeof(int) * 20,age申请四个字节。注意,相同的类型的成员相连定义可一起计算内存

如:

struct node1 {
    char a;
    char b;
    int c;
};//8字节;char a和char b一共占两字节,又对齐方式得4字节
struct node2 {
    char a;
    int c;
    char b;
};//12字节

因此可以根据同类型定义来减少空间申请

共用体

共同利用同一片存储空间

union register{
    struct {
        unsigned char a;
        unsigned char b;
        unsigned char c;
    } bytes;
    unsigned int d;
}

上面的共用体中int占4个字节,所以struct也占4个字节,而且int和struct共占一片内存空间,根据访问类型所占字节访问成员,如:

union node{
    double a;
    char b;
    int c;
}

上面共用体一共占8字节,如果访问内存中第一个字节则访问b;如果访问内存中前四个字节则访问c,以此类推。

大小端

小端:数字低端存在数据段低地址位

大端:数字高端存在数据段高地址位

判断大小端方式:

int is_little(){
    int num = 1;//如果是小端在地址中存的是1000,如果是大段存的的是0001
    return ((char*)(&num))[0];//强制转换为char指针类型。返回第一个地址,小端为1,大端为0
}

字节序:

主机/本地字节序

网络字节序

指针

变量:类型,存值,空间大小,地址

指针变量:

类型:可以是int,char…

存值:地址

空间大小:64位操作系统有8字节(8gb),32位有4字节(4gb)

地址:64位可以给2^62个字节编址,每个字节都有对应的地址,根据操作系统位数决定指针变量地址数量,指针指向的地址为全部数量地址中最小的地址,地址类型由指针变量类型决定

指向指针的指针:

指向指针的指针,存储指针的地址

p+n:

往后移n*sizeof(types)长度

等价形式转换:

*p <=> a(原始变量)

p + 1 <=> &p[1]

p->filed <=> (*p).filed <=> a.filed

函数指针:

返回值 (*函数名)(形式参数…)

(*函数名)为什么要加括号:

如int (*add)(int, int);

不加括号:int *add(int, int);这时可以理解返回值类型为int *,也可以理解为int

typedef的用法:

内建类型的重命名:如

typedef long long lint;

typedef char * pchar;

结构体类型的重命名:如

typedef struct _node{

} Node, *PNode;

函数指针命名:

typedef int (*func)(int);把函数指针变量提升为函数指针类型

main函数参数

操作系统调用main函数

int main();

int main(int argc, char*argv[]);

argc:接受命令行参数个数,argv:具体命令行参数,其中有若干行字符串,为二维数组

int main(int argc, char *argc[], char ** env);

env:环境变量,也为二维数组

int main(int argc, char *argv[],char **env){
    printf("argc = %d\n", argc);
    for(int i = 0; i < argc; i++){
        printf("argv[%d] = %s\n", i, argv[i]);
    }
    for(int i = 0; env[i]; i++){
        printf("env[%d] = %s\n", i, env[i]);
    }
    return 0;
}

预处理命令
预处理命令-宏定义

以#号开头为预处理命令

#define

宏只进行一个符号替换不做运算

宏只支持单行

定义符号常量:

#define PI 3.1415

#define MAX_N 10000

定义傻瓜表达式:

#define MAX_N(a, b) (a) > (b) ? (a) : (b)

#define S(a, b) a * b 如S(2+3, 2+3) 2+3*2+3

定义代码段:

#define P(a) {\

​ printf(“%d\n”, a);\

}

:反斜杠为连接符

预处理命令-预定义的宏

__DATE _ 日期:

__TIME _ 时间:

__LINE _ 行号

__FILE _ 文件名

__func _ 函数名/非标准

__FUNC _ 函数名/非标准

__PRETTY _ FUNCTION _ 更详细的函数信息/非标准

预处理命令-条件式编译

#ifdef DEBUG 是否定义了DEBUG宏

#ifndef DEBUG 是否没定义DEBUG宏

#if MAX_N == 5 宏MAX_N是否等于5

#elif MAX_N == 4 否则宏MAX_N是否等于4

#else

#endif

宏定义DEBUG
#include<stdio.h>

#define p(func){\
    printf("%s = %d\n", #func, func);\        
}
#define MAX(A, B) {\
    __typeof(A) _A = (A);\
    __typeof(B) _B = (B);\
    _A > _B ? _A : _B;\
}

int main(){
     int a = 7;
     p(MAX(2, 3));
     p(5 + MAX(2, 3));
     p(MAX(2, MAX(3, 4)));
     p(MAX(2, 3 > 4 ? 3 : 4));
     p(MAX(a++, 6));
     p(a);
     return 0;
}

打印LOG宏和条件式编译

编译条件:gcc -DDEBUG LOG.c

#include<stdio.h>
#define BEBUG
#ifdef DEBUG
#define log(frm, args...){\
    printf("[%s : %s : %d] ", __FILE__, __func__, __LINE__);\
    printf(frm, ##args);\
    printf("\n");\
}
#else
#define log(frm, args...)
#endif

#define contact(a, b) a##b

int main(){
    int a = 123, b = 345, abcdef = 0;
    //printf("[%s : %s : %d] %d\n", __FILE__, __func__, __LINE__, a);
    log("%d", a);
    log("%d", b);
   // printf("hello world\n");
    contact(abc, def) = 112233;
    log("%d", abcdef);
    return 0;
}

工程项目相关目录创建

linux创建目录命令:mkdir

主目录:

project

下属目录:

include:存放所有头文件【必须】

src:存放所有源文件【必须】

//编译主程序temp.cpp
①g++ -c temp.cpp //错误。没有包含head头文件
②g++ -I./include -c temp.cpp// -I./include头文件包含到系统库中,g++编译temp.cpp
//②中生成temp.o文件
g++ ./src/head  //链接src中的head
g++ -I./include -c ./src/head1.cc  // ./src/head1.cc为编译源文件head1.cc
g++ -I./include -c ./src/head2.cc
g++ -I./include -c ./src/head3.cc
//生成一系列对象文件.o
//使temp.o这个对象文件和src下所有的对象文件链接生成可执行程序
g++ *.o
//生成a.out这个可执行文件

bin:存放最终整个多文件编译链接生产的唯一的可执行程序

lib:存放链接库文件

makefile

(非常依赖环境)

linux创建makefile命令:touch

作用:将多个文件操作写出一个脚本,便于多文件编译

一个简版makefile:

①~④为编译源文件成对象文件

⑤为链接操作

.PHONY: clean run
    //.PHONY创建了一个虚拟空间clean run
all: temp.o ./src/head1.o ./src/head2.o ./src/head3.o
	g++ temp.o ./src/head1.o ./src/head2.o ./src/head3.o -o ./bin/KKB(操作⑤)
    //链接上面所有对象文件成一般的a.out,且把a.out改名为KKB
temp.o: temp.cpp ./include/head1.h ./include/head2.h ./include/head3.h
	g++ -I./include -c temp.cpp (操作①)
    //编译temp.cpp成temp.o
./src/head1.o: ./src/head1.cc ./include/*.h
	g++ -I./include -c ./src/head1.cc -o ./src/head1.o(操作②)	
./src/head2.o: ./src/head2.cc ./include/*.h
	g++ -I./include -c ./src/head2.cc -o ./src/head2.o(操作③)
./src/head3.o: ./src/head3.cc ./include/*.h
	g++ -I./include -c ./src/head3.cc -o ./src/head3.o(操作④)
clean: 
	rm ./bin/KKB ./src/*.o temp.o
run:
	./bin/KKB

cmakean工具

链接库

将头文件和源文件打包成链接库给别人用,别人看不到源代码,保密作用,会收到include和lib两部分

静态链接库

发给别人的链接库是静态的,以后源代码更新不会影响改变已经发给别人的链接库(.a)

linux系统打包链接库命令:

链接库取名:libxxx.a

ar -r libxxx.a head1.o head2.o head3.o
    //打包对象文件成静态链接库
    //ar是gnu归档工具
mv src/libxxx.a lib/
    //把链接库移动到lib目录中

链接链接库

-L./lib -l (链接库名)

g++ -I./include main.cpp -L./lib -l xxx
    // -L./lib -l zys为链接库路径,-L指定库路径 -l指定库名称
动态链接库

放在服务器某路径下,所有人都可以使用,源代码更新也会自动更新链接库,别人也可以使用到随时更新的链接库(.so)

linux系统打包链接库命令:

链接库取名:libxxx.so.x //为版本号

g++ head.cpp -fPIC -shared -o libxxx.so
    //编译so库产生so库(libxxx.so),fpIC指编译的so库不依赖具体路径,share为生产共享格式
//g++ -fPFic -c head1.cpp head2.cpp
//g++ -share -o libxxx.so head1.o head2.o
    //这两条指令和上面的等价
mv src/libxxx.a lib/
    //把链接库移动到lib目录中

链接动态链接库:

g++ temp.o -o a.out -L. -l xxx

include -c ./src/head3.cc -o ./src/head3.o(操作④)
clean:
rm ./bin/KKB ./src/*.o temp.o
run:
./bin/KKB


cmakean工具

#### 链接库

将头文件和源文件打包成链接库给别人用,别人看不到源代码,保密作用,会收到include和lib两部分

##### 静态链接库

发给别人的链接库是静态的,以后源代码更新不会影响改变已经发给别人的链接库(.a)

linux系统打包链接库命令:

链接库取名:libxxx.a

```c
ar -r libxxx.a head1.o head2.o head3.o
    //打包对象文件成静态链接库
    //ar是gnu归档工具
mv src/libxxx.a lib/
    //把链接库移动到lib目录中

链接链接库

-L./lib -l (链接库名)

g++ -I./include main.cpp -L./lib -l xxx
    // -L./lib -l zys为链接库路径,-L指定库路径 -l指定库名称
动态链接库

放在服务器某路径下,所有人都可以使用,源代码更新也会自动更新链接库,别人也可以使用到随时更新的链接库(.so)

linux系统打包链接库命令:

链接库取名:libxxx.so.x //为版本号

g++ head.cpp -fPIC -shared -o libxxx.so
    //编译so库产生so库(libxxx.so),fpIC指编译的so库不依赖具体路径,share为生产共享格式
//g++ -fPFic -c head1.cpp head2.cpp
//g++ -share -o libxxx.so head1.o head2.o
    //这两条指令和上面的等价
mv src/libxxx.a lib/
    //把链接库移动到lib目录中

链接动态链接库:

g++ temp.o -o a.out -L. -l xxx
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

扑天鹰

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

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

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

打赏作者

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

抵扣说明:

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

余额充值