快速入门c语言

1.什么是C语言

1.C语言是一门面向过程的语言。不同于C++等其他面向对象的语言。简单来说:面向对象就是高度实物抽象化。面向过程就是自上向下的编程,把每一步都想好。

2.C语言擅长底层软件开发。
操作系统及以下的内容都属于底层开发。
如:linux是用C开发的。
在这里插入图片描述

1.1语言发展历史

1.机器语言时代,计算机语言都是由二进制数字组成的。代码都形如01010101000001111…这让计算机语言难学难懂,很少人会使用

2.汇编语言时代,后来有人把某一些特定的二进制编码序列进行编号。这些编号叫做助记符。例如:
在这里插入图片描述
3.B语言。比汇编又方便了一些了。
4.C语言。C语言的出现让很多人都可以开始写程序了。但是由于越来越多人的使用,导致C语言在不同地方的标准不统一。出现了在我这里写的代码可以跑,在你那就报错的情况。因此C语言国际标准就由此诞生。
5.ANSI C–C语言国际标准。
包含C89,C90,C99.最常用的是C89和C90。

1.2 IDE和编译器

1.IDE是集成开发环境(Integrated Development Environment)
里面包含了编译器。例如vscode等等

2.常用的编译器是MSVCGCC

2.第一个程序

int main()
{
	printf("Hello world");
	return 0;
}

1.一个程序的入口就是main函数。不管mian函数前面有多少代码,程序也会首先运行main函数里面的代码。

2.一个工程里面只能有一个main函数。
注意:是工程而不是文件。
在这里插入图片描述
如果在test里面创建了main函数,在test6.13也不能再写main函数了。因为它们在同一个工程里面。

3.main函数的名字不能改。一定就是main,其他写法都不行。

2.1 main函数的几种写法

第一种

int main()
{
	return 0;
}

这是最常用的写法。
第二种

void main()
{
}

这种写法很少,过时了。
第三种

int main(int argc, char* argv[])
{
	return 0;
}

argc(argument count)和argv(argument vector)是main函数的形参。它们是程序的“命令行参数”。
argv本质是一个指针数组,里面的每一个元素(指针)指向命令行中的一个字符串的首字符。
在这里插入图片描述

3.数据类型

数据类型大小(byte)
char1
short2
int4
long4
long long8
float4
double8

注:long的大小不一定是4.C语言规定long的大小大于等于(>=)int就可以。

4.变量

变量分为局部变量和全局变量。

int g_val = 100;//全局变量
int main()
{
	int a = 0;//局部变量
	return 0;
}

从作用域和生命周期两个角度来区分变量

作用域

  1. 全局变量的作用域是整个工程。(注意是工程,上面main函数那里已经强调过了)。但在工程内的其他文件使用时要声明外部变量。

在test6.13里面写一个全局变量。
在这里插入图片描述
在test里面若要使用该全局变量,就要使用关键字extern(这个关键字是用来声明外部变量的)如果不声明,虽然全局变量的作用域是整个工程,但是在test文件里面不认识它。
在这里插入图片描述
如果不申明:
在这里插入图片描述

  1. 局部变量的作用域是变量所在的局部范围。(就是离得最近的大括号里面)

生命周期

  1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。(进最近的大括号开始,出最近的大括号开始)
  2. 全局变量的生命周期是:整个程序的生命周期。(因为作用域是整个工程)

4.1 变量在内存中的体现

int main()
{
	int a = 0;
	return 0;
}

在这里插入图片描述
在作用域内变量对这段内存有使用权限。当出了作用域之后,就要归还对这段内存的使用权限。

5.常量

5.1字面常量

很简单,举个例子。

int main()
{
	3.14;//字面常量
	0;//字面常量
	int a = 0;//字面常量的用法
	return 0;
}

5.2const修饰的常变量

重点!!

  1. 什么叫常变量?—具有常属性的变量。本质还是变量。
  2. 什么是常属性?—不能修改的属性叫做常属性

举例子说明:
例子1:

int main()
{
	const int a = 100;
	a = 200;
	return 0;
}

这样合法吗?
显然是不合法的。const修饰的常变量是不可以修改的。
报错:
在这里插入图片描述
例子2

int main()
{
	const int a = 10;
	int arr[a];
	return 0;
}

合法吗?
可能合法可能不合法。

在C99里面新定义了一个概念叫变长数组。允许arr[a]里面的a是变量。在这个例子当中a确实是变量,这么写在C99标准下是没有问题的
但是在C89和C90里面,arr[a]里面的a必须是常量表达式。这么写就会报错。
考虑到程序的可移植性,我们还是不推荐这种写法。

5.3#define定义的标识符常量

很简单,举个例子:

#define MAX 100//define定义的标识符常量
int main()
{
	int arr[MAX] = { 0 };
	return 0;
}

#define的本质是替换。相当于数学上的换元。把MAX换成100.
注:#define后面不加分号。

5.4枚举常量

枚举常量是枚举类型里面的可能取值。
例子1
下面代码输出什么?

enum destination
	{
		BEIJING,
		SHANGHAI,
		GUANGZHOU,
		SHENZHENG
	};
	printf("%d",GUANGZHOU);//输出多少?

答案:2.
enum destination相当于一种类型,叫枚举类型。里面的元素是有对应的值的。
若像此题没有赋予初值的话。默认是从0,1,2,3…一直增长。若有赋初值,后一个元素的值是前一个值+1.

例子2

enum destination
	{
		BEIJING=10,
		SHANGHAI,
		GUANGZHOU,
		SHENZHENG
	};
	printf("%d", SHANGHAI);

答案:11.
例子3
这个例子合法吗?

int main()
{
	enum destination
	{
		BEIJING=10,
		SHANGHAI,
		GUANGZHOU,
		SHENZHENG
	};
	enum destination a = BEIJING;
	BEIJING = 11;
}

不合法。枚举常量是常量,具有常属性,不可以修改。
在这里插入图片描述

6.字符串

6.1c语言怎么写字符串

C语言里面没有字符串。因此要用字符数组来表示字符串。

int main()
{
	char arr[] = "hello world";
	printf("%s", arr);
}

上面那段代码的原理是printf函数从字符串第一个字母开始往后找,直到找到**\0**这个字符之后就停止运动。(\0我们是看不见的,但是计算机可以看见。)
在这里插入图片描述
arr[11]就是\0。

6.2字符串结束标志

关于结束标志有一些例子
例子1
下面代码输出什么

int main()
{
	char arr[] = "hello world";
	char arr2[] = { 'h','e','l','l','o' };
	printf("%d", strlen(arr));//输出多少?
	printf("%d", strlen(arr2));//输出多少?
}

答案:11,随机值。
11的原因就是\0前面有11个字符。那随机值是怎么来的呢?
我们说过,字符串查找是查找到\0才会结束。
在这里插入图片描述
在arr2里面并没有\0。因此查找并不会按预期的想象停下来,他会一直往后面找,直到找到\0才会停止。

内存视角
在这里插入图片描述

7.转义字符

7.1转义字符简介

不怎么重要的
在这里插入图片描述
重要的

\dddddd表示8进制数字转换成十进制数字对应的ASCII码对应的字符
\xddxdd表示16进制数字转换成十进制数字对应的ASCII码对应的字符

这两句话很重要

7.2重点转义字符和习题

注:转义字符都算1个字符。(例如:\t虽然是4个空格,但也是一个字符。)
例子1
输出什么?

int main()
{
	printf("%c", '\065');
}
  • 答案:字符5. \065是5×80+6×81+0×82=5+48+0=53 ASCII码53对应的字符就是5

例子2
输出什么?

int main()
{
	printf("%c", '\x65');
}
  • 答案:e \x65是5×80+6×161=5+96=101 ASCII码101对应的字符就是e

例子3
输出什么?

printf("%d"strlen("c:\test\328\test.c"));
  • 答案:14.先找出转义字符。\t算一个。
  • 问题来了,\328是不是几个转义字符?算两个。\ddd里面的每一位数都要求是8进制,8进制最大就是7,所以这里是\32和8分开来算。
  • 所以总和是14.

8.选择语句

8.1if语句

int main()
{
	//输出较大值
	int a = 0, b = 0;
	scanf("%d%d", &a, &b);
	if (a >= b)
		printf("a");
	else
		printf("b");
}

8.2 switch语句

int main()
{
	char grade = 0;
	scanf("%c", &grade);
	switch (grade)
	{
	case 'A':printf("优秀"); break;
	case 'B':printf("良"); break;
	case 'C':printf("及格"); break;
	}
}

9.循环语句

9.1 for循环

int main()
{
	for (int i = 0; i < 5; i++)
	{
		printf("hello world");
	}
	return 0;
}

9.2 while循环

int main()
{
	int i = 0;
	while (i < 5) {
		printf("hello world");
		i++;
	}
	return 0}

9.3 do…while循环

while是先判断后do
do…while是先do再判断

int main()
{
	int i = 0;
	do
	{
		printf("hello world");
		i++;
	} 
	while (i < 5);
	return 0;
}

10.函数

int main()
{
	void FindGrade(int);//由于程序从上到下执行,程序不认识FindGrade这个函数,所以要进行函数声明
	char grade = 0;
	scanf("%c", &grade);
	FindGrade(grade);//调用函数
}
void FindGrade(int grade)//grade是函数的参数
{
	switch (grade)
	{
	case 'A':printf("优秀"); break;
	case 'B':printf("良"); break;
	case 'C':printf("及格"); break;
	}
}

注:

  1. 由于程序从上到下执行,程序不认识FindGrade这个函数,所以要进行函数声明
  2. void表示函数返回参数的类型。void表示不返回参数,int表示返回整型,以此类推

11.数组

C语言中给了数组的定义:一组相同类型元素的集合

1.数组专属操作符—[]

int main()
{
	char arr[20] = "hello world";
	return 0;
}

[20]表示创建一个有20个char类型大小的空间,最多存放20个char类型元素。

2.数组遍历

int main()
{
 int i = 0;
 int arr[10] = {1,2,3,4,5,6,7,8,9,10};
 for(i=0; i<10; i++)
 {
       printf("%d ", arr[i]);
 }
 printf("\n");
    return 0;
}

由于数组是顺序表,所以在遍历的时候可以用i++这种方式来往后遍历。
内存体现
在这里插入图片描述
计算机内部是这样子的
在这里插入图片描述
最左侧的是每一个元素的地址。每个地址之间都相差1个字节,刚好是char类型大小。证明是连续的。

12.操作符

操作符有下面那么多

优先级运算符名称或含义使用形式结合方向说明
1[]数组下标数组名[常量表达式]左到右
()圆括号(表达式) 函数名(形参表)
.成员选择(对象)对象.成员名
->成员选择(指针)对象指针->成员名
2-负号运算符-表达式右到左单目运算符
(类型)强制类型转换(数据类型)表达式
++自增运算符++变量名 变量名++单目运算符
自减运算符–变量名 变量名–单目运算符
*取值运算符*指针变量单目运算符
&取地址运算符&变量名单目运算符
!逻辑非运算符!表达式单目运算符
~按位取反运算符~表达式单目运算符
sizeof长度运算符sizeof(表达式)
3/表达式 / 表达式左到右双目运算符
*表达式*表达式双目运算符
%余数(取模)整型表达式%整型表达式双目运算符
4+表达式+表达式左到右双目运算符
-表达式-表达式双目运算符
5<<左移变量<<表达式左到右双目运算符
>>右移变量>>表达式双目运算符
6>大于表达式>表达式左到右双目运算符
>=大于等于表达式>=表达式双目运算符
<小于表达式<表达式双目运算符
<=小于等于表达式<=表达式双目运算符
7==等于表达式==表达式左到右双目运算符
!=不等于表达式!= 表达式双目运算符
8&按位与表达式&表达式左到右双目运算符
9^按位异或表达式^表达式左到右双目运算符
10|按位或表达式|表达式左到右双目运算符
11&&逻辑与表达式&&表达式左到右双目运算符
12||逻辑或表达式||表达式左到右双目运算符
13?:条件运算符表达式1? 表达式2: 表达式3右到左三目运算符
14=赋值运算符变量=表达式右到左
/=除后赋值变量/=表达式
*=乘后赋值变量*=表达式
%=取模后赋值变量%=表达式
+=加后赋值变量+=表达式
-=减后赋值变量-=表达式
<<=左移后赋值变量<<=表达式
>>=右移后赋值变量>>=表达式
&=按位与后赋值变量&=表达式
^=按位异或后赋值变量^=表达式
|=按位或后赋值变量|=表达式
15,逗号运算符表达式,表达式,…左到右

12.1移位操作符

<< 和 >>

12.1.1 左移操作符

例子
b等于多少?

int main()
{
	int a = 4;
	int b = a << 1;
	printf("%d", b);
}

分析:整型在计算机内以二进制的方式存储。左移操作符就是把二进制序列往左移动一位。高位丢弃,低位补0.
在这里插入图片描述

12.1.2 右移操作符

右移操作符有不同的操作规则。要对源码,反码,补码有一定认识。

12.1.2.1 源码,反码,补码

一个整数的二进制表示方式有3种。分别是源码,反码和补码。

  • 源码是数字本身的二进制序列。例如4的源码就是0100.

  • 反码是对源码的除符号位外(序列的第一位是符号位,0表示整数,1表示负数的每一个二进制位进行按位取反。(0变成1,1变成0)

  • 补码是对反码的二进制序列+1

  • 由于正数的符号位是0,所以这里有一个结论。正数的源码,反码,补码相同

例子1
写出4的源码,反码和补码。

分析:由于4是正数,所以4的源码反码和补码相同。4的源码就是它的二进制序列。如下图在这里插入图片描述

例子2
写出-1的源码,反码和补码

分析:-1不是正数,不能用上面的结论了。

由于-1是负数,所以高位符号位是1。因此源码如图。
反码是源码除符号位外的每一位按位取反,所以反码如图。
补码是反码的二进制序列+1,所以补码如图。
在这里插入图片描述

12.1.2.2 右移操作符练习

右移操作符注意事项:

  1. 右移时高位补符号位,低位舍弃
  2. 右移操作符是对整数的补码进行操作的。因此在做题时要先把二进制序列转换成补码,在进行右移操作。最后输出的时候要重新对新序列转换成源码。(输入输出都是源码,存储时才是补码)

例子1:
b等于多少?

int main()
{
	int a = 4;
	int b = a >> 1;
	printf("%d", b);
}

答案:2.
4是正数,原反补相同。直接可以移位。移位后变成2.由于2也是正数,所以原反补相同。输出2.
在这里插入图片描述

例子2
b等于多少?

int main()
{
	int a = -1;
	int b = a >> 1;
	printf("%d", b);
}

答案:-1.
在这里插入图片描述

12.2位操作符

位指的是二进制位。字面意思就是对二进制位进行操作
&(按位与)
|(按位或)
^(按位异或)

12.2.1按位与

按位与的操作是对两段不同的二进制序列的每一位进行与操作。
只要其中一段二进制序列对应位有0,则结果是0.只有两端二进制序列的对应位都是1,结果才是1
例子1
输出什么?

printf("%d", 3&5);

答案:1
在这里插入图片描述

12.2.2按位或

按位与的操作是对两段不同的二进制序列的每一位进行或操作。
只要其中一段二进制序列对应位有1,则结果是1.只有两端二进制序列的对应位都是0,结果才是0
例子1
输出什么?

printf("%d",3|5);

答案:7
在这里插入图片描述

12.2.3按位异或

按位与的操作是对两段不同的二进制序列的每一位进行异或操作。
二进制序列对应位相同为0,相异为1.
例子1:

printf("%d",3^5);

答案:6
在这里插入图片描述

12.3赋值操作符

= += -= *= /= >>= <<= &= ^= |=
注:a+=10等效于a=a+10。可以简化代码。其余类推

12.4单目操作符

!逻辑反操作(true变false,false变true)
& 取地址
sizeof 计算大小
~ 按位取反
++ 自增

重点讲按位取反和自增。

12.4.1 按位取反

和上面所说的源码变成反码的操作类似,就是对补码的二进制序列进行操作。0变1,1变0.
注:凡是位操作符都是对补码进行操作,然后以源码的形式输出。
例子1
输出什么?

int a = 0;
printf("%d",~a);

答案:-1
分析:由于0不是负数,所以源码反码和补码相同。直接可以对它的二进制序列进行按位取反。得到~0的补码,再转换回源码即可。(补码-1等于反码,反码除高位符号位不变,其余全部按位取反得到源码)
在这里插入图片描述

12.4.2 前置++和后置++

区分a++和++a的区别
a++是先加再使用
++a是先使用再加
例子1
b等于多少?

int main()
{
	int a = 0;
	int b = a++;
	printf("%d", b);
}

答案:0
分析:先使用再加。a先把0赋值给了b。然后自己再加一。所以现在b是0,a是1.
例子2
b是多少?

int main()
{
	int a = 0;
	int b = ++a;
	printf("%d", b);
}

答案:1.
分析:a先自增1,所以a等于1.然后再赋值给b,所以b是1.
例子3
b等于多少?

int a = 1;
b = (++a)++(++a)+(++a)

答案:ub(undefined behavior)
分析:以后遇到这种题统一回答ub。因为本质这就是错的。在不同的编译器上跑的结果都是不一样的。

12.5关系操作符

>= < <= != ==等比较符
注:判断两个值是否相等是用两个等号,而不是一个等号

12.5.1 注意事项

如果表示x大于1且小于5,怎么表示?
这样对吗?

1<x<5//可以吗

答案是否定的。
应该这么写,这是C语言规定的。

(x>1)&&(x<5)

12.6逻辑操作符

&& ||

12.7条件操作符(三目操作符)

exp1?exp2:exp3
它的意思是当满足exp1的条件时,执行exp2的语句,否则执行exp3的语句。

例子

int max(int x, int y)
{
	return x >= y ? x : y;
}

分析:如果x>=y就返回x,否则返回y

12.8逗号表达式

逗号表达式从左向右一次计算。整个逗号表达式的结果是最后一个表达式的结果。(用的比较少,了解就好)
例子
输出什么?

int main()
{
	int a = 1, b = 2, c = 3, d = 4, e = 5;
	int f = (a = b - 5, b = a + c, c = a + b, c -= -5);
	printf("%d", f);
}

答案:2.
一直算下去就可以了

12.9下标引用、函数调用和结构成员

[]使用数组的时候用,
()使用函数的时候用,
. 访问结构体成员变量的时候用 ,
-> 访问结构体指针指向的成员的时候用

13.常见关键字

auto break case char const continue
default do double else enum extern
float for goto if int long
register return short signed sizeof static
struct switch typedef union unsigned void
volatile while

这里挑几个
auto是自动变量的意思。自动的意思是自动创建自动销毁的意思。和上面讲的作用域有关,当程序出了这个变量的作用域时,这个变量就会自动销毁

extern是用来声明外部变量的。在前面讲全局变量的声明时说过。

unsigned 无符号数
signed 有符号数

13.1重点关键字介绍

13.1.1typedef

typedef是用来重命名的。相当于给名字起了个小名。可以在未来写的时候简化代码,增加代码可读性。
注:起了小名之后原来的名字一样可以用
例子

typedef unsigned int uint;//把无符号数名起了个别名叫uint
typedef queue q;//把队列起了个别名叫q

13.1.2 register

register是(建议)寄存器变量。讲这个关键字要讲一点关于计算机组成的知识。
在这里插入图片描述
在这里插入图片描述
早期CPU读写速度不快,与内存差不多。所以没有寄存器也没什么关系,而且内存造价还便宜。
但随着技术发展,cpu读写速度越来越快,内存已经跟不上cpu的处理速度了。因此有了寄存器,cache等的储存空间的出现,目的就是为了跟上cpu的处理速度
在这里插入图片描述

寄存器是储存空间,一般是集成在cpu上的,和内存是不同的独立的储存空间。它的读写速度也是最快的。如果程序员想让某一个变量的读写速度要快,就可以用register来定义变量。

注:&是无法取在寄存器里的变量地址的。因此&无法作用与register。

13.1.3 static

static是静态的意思。作用对象都是生命周期和作用域。有三种用法,每种用法都有点区别。

1.修饰局部变量。延长了变量的生命周期(与程序的生命周期一致),但作用域没有变
例子
输出什么?

void test()
{
	static int a = 0;
	a++;
	printf("%d ", a);
}
int main()
{
	for (int i = 0; i < 5; i++)
	{
		test();
	}
	return 0;
}

答案:1 2 3 4 5
分析:本来a的生命周期在进入test函数开始,出test函数结束。现在static让a的生命周期延长了。出去test的时候也不会销毁。因此a的值每次都被保留了下来。
2.修饰全局变量。作用域从原来的整个工程减小到本文件。生命周期不变
例子
在文件1内创建全局变量g
在这里插入图片描述
在文件2内声明外部变量
在这里插入图片描述
报错:
在这里插入图片描述
3.修饰函数。作用域从原来的整个工程减小到本文件。生命周期不变
例子和2相同。原理和2也一样,加入static后函数就只能在创造函数的文件内使用

13.1.4 define定义宏

#define可以定义宏和常量,定义常量在上面已经讲过。这里讲定义宏。
宏在程序预处理阶段就会被更换。
宏可以理解成数学中的换元。
例子

#define MAX(X,Y) X>Y?X:Y
int main()
{
	int x = 1, y = 2;
	int c = MAX(x, y);//在编译器眼里是int c = x>y?x:y;
}

分析:MAX(x,y)在编译器眼里是x>y?x:y;

14.指针

14.1指针的由来

电脑的内存大多都是4G/8G/16G,不会太大。那电脑是怎么使用和管理这些内存的呢?和生活中一样,电脑给每一块内存单元编了个号。内存单元的编号叫做地址

首先地址是怎么产生的,也就是说电脑是怎么给内存单元编号的?电脑里面有32根/64根电线(分别对应着32位电脑和64位电脑)。正电被称为1,负电被称为0.这32根电线就排列组合成了32位的编号。这一个32位的编号就是地址。所以说地址的产生是由电信号决定的。

那每一个内存单元可以管理多大呢?1字节?1bit?1kb?科学家们就发现,如果每个内存单元可以管理1个bit。232个编号可以管理4294,967,296bit,即0.5G。0.5G的内存对于日常生活来讲有点太小了。而且这还面临着一个问题:如果我们向系统申请一个char类型(8bit),我们就要用八个地址编号去管理一个char类型。这效率就太低了。(用力过度了,没有必要)

如果每个内存单元可以管理1个bit。232个编号可以管理4G的内存对于日常生活来讲比较合适。而且上面的问题也解决了,不会让太多的地址编号被浪费掉。

如果每个内存单元可以管理1个kb。232个编号可以管理更大的内存空间。但是我们却连char类型都无法管理。一个char类型1字节。我们一个内存单元1kb。无法管理,也不合适。

总结:所以比较合适的是一个内存单元可以管理1字节的大小。这些内存单元的编号就是地址。而地址就是指针。这就是指针的由来

14.2指针表示方法

指针是一个存放起始地址的变量。我们用一个*表示这个变量是指针变量。
例子

int * pa;

分析:星号表示pa是一个指针,int说明pa指向的对象是int类型的

下面的写法都是可以的,没有区别。

int* pa;
int *pa;
int * pa;

14.3指针的大小

它们的大小都是多少?

int main()
{
	printf("%d", sizeof(char*));
	printf("%d", sizeof(double*));
	printf("%d", sizeof(int*));
	return 0;
}

答案:都是4
分析:所有的指针大小都是4。上面说过,指针就是地址,地址就是内存单元的编号。由32位数字构成。每一位数字是1bit,所以32位数字是4字节。所以不管类型是什么,它们大小都是4.

14.4与指针有关的操作符

*解引用符。可以访问地址指向的内存单元的内容。
输出什么?

int main()
{
	int a = 10;
	int* pa = &a;
	*pa = 20;
	printf("%d", a);
}

答案:20
分析:pa指向a所在的空间,*pa访问到了a的内容并把它修改成了20.

15结构体

结构体是一种特殊的类型,结构体使得C语言有能力描述复杂类型。

struct Stu
{
    char name[20];//名字
    int age;      //年龄
    char sex[5];  //性别
    char id[15]//学号
};

15.1 结构体访问成员的操作符

. 操作符 和 ->操作符
.是结构体访问成员的操作符。
->是结构体指针访问成员的操作符,两者不能搞混了

struct student s = {"张三"20"男""20180101"};
printf("name = %s age = %d sex = %s id = %s\n", s.name, s.age, s.sex, s.id);
struct Stu *ps = &s;
printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps-
>id);

总结
复习的时候可以当笔记看

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值