第一章 “C“浒传——初识C语言(更适合初学者体质哦!)
第二章 【初始C语言2】详细认识分支语句和循环语句以及他们的易错点,应用(猜大小游戏)
目录
系列文章目录
前言:
一、什么是语句?
1.1 表达式语句
1.2 函数调用语句
1.3 控制语句
1.4 复合语句
1.5 空语句
二、分支语句(选择结构)
2.1 if语句
2.2 switch语句
三、分支语句(选择结构)易错点:
3.1 if和else的对应关系(悬空else):
3.2 if语句的一些优化:
3.3 switch语句中的break:
3.4 switch语句中的default子句:
四、循环语句
4.1 while循环
4.2 for循环
4.2.1 语法
4.2.2 for语句的循环控制变量
4.3 do......while()循环
4.3.1 do语句的语法
4.3.2 do语句的特点
4.4 利用循环简答清理缓冲区(应用)
前言:
4.4.1 多组输入
4.4.1.1 scanf函数的一些见解
4.4.1.2 多组输入的习题
4.4.2 清理缓冲区
4.4.2.1 什么是缓冲区(buffer)
4.4.2.2 为什么要引入缓冲区这个概念?
4.4.2.3 介绍一个新函数——getchar()
4.4.2.4 模拟环境进行缓冲区的清理
五、循环语句的易错点:
5.1 while循环中的continue:
5.2 while循环中的break:
5.3 for循环中的continue:
5.4 for循环的变种:
六、goto语句
6.1 goto语句的作用
6.2 goto语句的使用场景
6.3 goto语句的例子
七、 分支语句和循环语句的应用(猜数字),了解随机数(rand())和时间函数(time(NULL))
7.1 生成随机数
7.1.1 伪随机数字
7.1.2 种子
7.2 用C语言来实现rand()函数和srand()函数
7.3 time函数
7.4 猜数字游戏的实现(含代码)
7.4.1 猜数字游戏的主体
7.4.1.1 猜数字函数的主体
7.4.1.2 猜数字游戏的菜单
7.4.1.3 猜数字游戏的选择部分
总结:
7.4.2 猜数字的游戏函数实现
7.4.3 猜数字游戏的所有代码
总结:
在上一章内,小编我带领大家进行进行了基础C语言的梳理和导航,希望大家要将第一章的内容好好利用起来!小编在这里谢谢大家了!
在这一章内,小编我会详细地为大家介绍分支语句与循环语句的,希望大家在看完之后,点个赞,支持一下博主,谢谢大家了!进行完分支语句和循环语句的学习后,小编自认为学的比较不错,但是在做题的过程中,我还是发现有一些容易错的地方,下面跟随小编的步伐进行学习吧!
另外,还有大家最关心的事情——学了这一章内容,到底应该怎么利用所学知识运用到生活中呢?请看这一章最后的内容!
因为这里是C语言的详细讲解,所以我们要细细品味每一个名词、知识点。要学习分支语句和循环语句,就要先知道什么是语句?小编认为C语言中的语句就是我们平常说的话一样,用句号进行分割。而C语言类似,在大部分情况下,我们用分号进行分割。
在C语言中,语句可以分为以下五类:1)表达式语句; 2)函数调用语句; 3)控制语句;4)复合语句;5)空语句。
下面进行每种语句的举例,来帮助你更好地了解他们:
顾名思义,就是表达式加上分号。下面进行代码解释:
3 + 5; //这就是表达式语句
函数调用语句,就是将函数进行使用时调用的语句。下面进行代码解释:
printf("%d\n", ans); //进行调用库函数
ADD(3, 5); //进行调用自定义函数
控制语句是用于控制程序的执行流程,以实现程序的各种结构方式(C语言是结构化的程序设计语言),他们由特定的语句定义符组成,C语言有九种控制语句。今天讲的分支语句与循环语句就是控制语句。
可分为以下三类:
1)条件判断语句(分支语句):if语句,switch语句;
2)循环执行语句:do while语句,while语句,for语句;
3)转向语句:break语句,goto语句,continue语句,return语句。
别被他这个名字吓一跳,小编我刚开始也认为复合语句很难,其实,复合语句就是多条语句用大括号进行包围起来。下面进行代码解释:
{
int a = 0;
int b = 0;
printf("%d\n", a + b);
return 0;
}
空语句虽然很简单,但是其用途很大:有时候需要一条语句,但这条语句什么都不需要做。下面进行代码解释:
while(*dest++ = *src++)
{
;
}
进行完这几种语句的举例,那么我们接下来进行这篇博客的重点:分支语句。
在学习分支语句之前,我们需要知道一件事情:在C语言中,0为假,非0为真!(负数也是真)
分支语句分为两类:if语句,switch语句。
下面我们来看分支语句的流程图:
那么if语句的语法结构是怎么样的?下面进行代码解释:
if(表达式)
语句;
//单分支语句
if(表达式)
语句1;
else
语句2;
//多分支语句
if(表达式1)
语句1;
else if(表达式2)
语句2;
else
语句3;
当然,这些语句仅限于在单语句中进行,那么何为单语句呢?就是只有一个语句。
如果条件成立,要执行多条语句,应该使用代码块。那么何为代码块呢?就是用大括号包围起来的语句。下面用代码进行解释:
#include
int main()
{
if(表达式)
{
语句列表1;
}
else
{
语句列表2;
}
return 0;
}
switch语句也是一种分支语句,常常用于多分支情况!小编认为每一种分支语句的形式都是为了在不同情况中实现而生的。
比如,输入1,输出星期一; 输入2,输出星期二;输入3,输出星期三;输入4,输出星期四;输入5,输出星期五;输入6,输出星期六;输入7,输出星期七。
如果写成if...else if...else if...else的情况就很复杂,那我们需要有不一样的语法形式。
这就是switch语句(支持嵌套使用):
switch(整形表达式)
{
语句项;
}
当大家看到语句项的时候,可能会小懵一手,那么语句项是什么呢?
语句项就是一些case语句,如下:
case 整形常量表达式:
语句;
看下面的这个代码:
//要有良好的代码风格
int main()
{
int a = 0;
int b = 2;
if (1 == a)
if (2 == b)
printf("hehe\n");
else
printf("haha\n");
return 0;
}
这样写代码是不正确的,要有良好的代码风格,不然会被喷成狗的。(小编建议看一下《高质量 C++/C 编程指南》这本书来养成良好的代码风格)所以适当的使用{}可以是代码的逻辑更加清楚。
易错点:else的匹配: else是和它里的最近的if匹配。
看下面的图片:
在if语句中,如果写成了赋值,程序是不会报错的,而只是会有警告的,对以后的调试带来不好的结果。所以我们可以进行下面的操作:
这种操作如果你少写了一个‘=’,程序会进行报错,不会出现上述情况。如果if括号里的是表达式而不是变量,则不需要进行这种操作。因为表达式不会被赋值。
#include
int main()
{
int num = 1;
if (5 == num)
printf("hehe");
return 0;
}
在switch语句中,我们要时刻关心break语句,使得case与break配合使用;在switch语句中所有分支下都没有增加break语句,因此会从上往下顺序执行,最后执行default中语句返回。break语句的作用是:break实现了switch语句跳出分支的效果。
在这里小编提一个编程好习惯:
在最后一个case语句的后面加上一条break语句。
(之所以这么写是可以避免出现在以前的最后一个case语句后面忘了添加break语句)。
如果表达的值与所有的case标签的值都不匹配怎么办?其实也没什么,结构就是所有的语句都被跳过而已!程序并不会终止,也不会报错,因为这种情况在C中并不认为是个错误。
但是,如果你并不想忽略不匹配所有标签的表达式的值时该怎么办呢?你可以在语句列表中添加一条default语句。
default语句:
这条语句可以写在任何一个case标签出现的位置。当switch表达式的值并不匹配所有case标签的值时,这个default子句后面的语句就会执行。所以,每一个switch语句中只会出现一条default子句。但是他可以出现在语句列表的任何位置,而且语句流会像执行一个case标签一样执行default语句。
在这里小编再提一个编程好习惯:
在每一个switch语句中都放入一条default语句是一个好习惯,甚至可以在后面加一个break。
循环语句分为三类:while循环,for循环,do......while循环。
在前面,我们已经掌握了if语句:
if语句:当条件满足的情况下,if语句后的语句执行,否则不执行。但是这条语句只会执行一次。
由于我们发现生活中很多实际的例子是:同一件事情我们需要完成很多次。所以C语言中给我们引入了:while语句,可以实现循环。
那么while语句的语法结构是怎么样的?下面进行代码解释:
while(表达式)
循环语句;
while循环的执行流程:
在我的认知里,for循环将是你用的最频繁的循环了,所以for循环算是一个重点。
当然,先来看一下for语句的语法结构是怎么样的?下面进行代码解释:
for(表达式1; 表达式2; 表达式3)
循环语句;
表达式1:表达式1为初始化部分,用于初始化循环变量的;
表达式2:表达式2为条件判断部分,用于判断循环时候终止;
表达式3:表达式3为调整部分,用于循环条件的调整。
for循环的执行流程:
现在,我们学习完了while循环和for循环后,让我们进行对比一下这两个循环:
int i = 0;
//实现相同的功能,使用while
i = 1; //初始化部分
while(i <= 10) //判断部分
{
printf("hehe\n");
i = i + 1; //调整部分
}
//实现相同的功能,使用for
for(i = 1; i <= 10; i++)
{
printf("hehe\n");
}
通过上面的代码,可以发现在while循环中依然存在循环的三个必须条件,但是由于风格问题使得三个部分很可能偏离较远,这样查找修改不够集中和方便。
在这一部分,小编有一些建议:
1)不可在for循环体内修改循环变量,防止for循环失去控制;
2)建议for语句的循环控制变量的取值采用“前闭后开区间”写法。
在小编看来,这个循环用的也是比较少的。
来跟随小编的脚步看一看do......while()语句的语法结构是怎么样的?下面进行代码解释:
do
{
循环语句;
}while(表达式);
do......while()循环的执行流程:
循环至少执行一次,使用的场景有限,所以不是经常使用。
在学习循环语句时,有几个例子:1.多组输入;2.清理缓冲区。希望能够将while循环与实际问题进行结合。下面我们就来进行一一展示:
在我们进行OJ题目的训练时,常常会看到以下的题目要求!这时,初学者会一脸懵逼!不要怕,下面我们就来消灭他:
在进行多组输入的讲解前,我们需要进行介绍scanf函数,在下面的链接上有详细的介绍(要学会使用cplusplus) ——scanf函数介绍,下面是小编我自己的介绍:
1.第一个用法,有人可能是一脸懵的,小编刚学的时候也是不相信的,输入函数居然有返回值,大家还是要欣然接受,毕竟大千世界无奇不有。scanf函数的返回值是int类型的,返回的是读取数据的个数,下面用代码进行证明:
2.这是scanf函数与gets函数的区别,在一些OJ题中,有时需要输入有空格的字符串,而scanf函数在读取字符串时,遇到空格就不在读取了 ;这时我们需要使用gets函数来接收。
总结:scanf函数是从缓冲区中的数据读取的,读取成功后,返回读取数据的个数;读取失败后,返回EOF(-1);其次在读取字符串时,遇到空格就不在读取了。
- scanf函数的返回值是int类型的,返回的是读取数据的个数;
- scanf函数在读取字符串时,遇到空格就不在读取了 。
下面进行一个简单的题目:
在这一部分,我们需要先了解什么是缓冲区,为什么要引入缓冲区,其次要学习一个新函数,最后模拟实现循环清理缓冲区。
缓冲区是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。
什么是输出缓冲区?
在C语言中,很多输出函数(如printf,putchar)存在输出缓存,在windows系统中,使用printf()函数后,数据被写入输出缓冲区,随后立即刷新缓冲区,所有我们在使用printf()函数时,往往会很快就在控制台中打印出来(Linux操作系统略有不同,等小编学完Linux后,在来讲解)。
什么是输入缓冲区?
同理得,输入函数(如scanf,getchar)也存在输入缓存,并且这些输入函数属于阻塞函数,当缓冲区没有内容时,程序将阻塞在输入函数中,等待用户从键盘输入内容,并按下回车键(即换行‘\n’)确认,之后,输入的字符将进入缓冲区,输入函数便从缓冲区获取字符,并且删除缓冲区中已经获得的字符,并解除阻塞状态继续执行代码。
下面举例一个十分经典的C语言代码来展示输入缓冲的存在:
char str[10]; int i; for(i=0;i<10;i++) scanf("%c",&str[i]); for(i=0;i<10;i++) printf("%c",str[i]);
第一种情况:如果我们正常地输入10个字符,然后就会正常的输出10个字符,打印正常。
第二种情况:如果我们输入a,然后回车;输入b,然后回车……结果只能输入5个字符便结束了程序,这也是我们要清理缓冲区的原因,在多组输入字符中,回车也是会被系统当成字符的,这样利用上面对整数的多组输入就不能使用,所以我们要清理缓冲区中的回车。
在以前的时期,我们要用磁盘进行储存信息,我们可以先将数据放在缓冲区,等缓冲区的数据读取完后,再去磁盘中进行读取。这样减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。
顾名思义,getchar()函数的功能是获取一个字符,而putchar()函数的功能是输出一个字符。
下面,进行具体的getchar()函数的功能介绍:在下面的链接上有详细的介绍getchar函数。getchar()函数,读取成功后,返回读取到字符的ASCII值(为int);读取失败后或遇到文件末尾时,返回EOF(-1)。
在下面的环境中——输入密码请确认是否正确,如果正确输出正确;如果错误输出失败。在这个过程中会出现一些问题:我们在输入完密码后,会敲一个回车,然后再输入(Y/N),但是在我们敲完回车后,程序直接结束了。
因为缓冲区中会有回车这个字符,getchar()会接收回车而不是(Y/N),这个程序看着没有太大的问题,但我们需要利用循环进行缓冲区的清理,这样如果有特殊情况,我们也可以进行清空缓冲区。
char arr[20];
printf("请输入密码:>");
scanf("%s", arr); //scanf函数在读取字符串时,遇到空格就不再读取
//在这里插入清理缓冲区的代码
printf("请确认(Y/N):>");
int ch = getchar();
if ('Y' == ch)
printf("确认成功\n");
else
printf("确认失败\n");
解决方法:
while ((ch = getchar()) != '\n')
; //在这里,我们需要循环但不需要循环体,用空语句充当循环体,空语句的用法
while循环中,continue的作用是:跳过本次循环后面的代码,直接去判断部分,看是否进行下一次判断。
下面来看一下这道题:
这个代码主要是让我们注意一下边界,以免出现漏项。
break在循环中不是很难,也不是很有诱惑性。读者们只需记住其在对应循环中的作用即可。
break在while循环中的作用:
其实在循环中只要遇到break,就会停止后期的所有循环,直接终止循环。所以:while中的break是用于永久终止循环的。
在for循环中,continue的作用是:跳过本次循环后面的代码,直接去循环的调整部分。
在for循环中,初始化部分,判断部分,调整部分是可以省略的,但是不建议初学时省略,容易导致问题。看下面两个代码:
#include
int main()
{
int i = 0;
int j = 0;
for (i = 0; i < 10; i++)
{
for (j = 0; j < 10; j++)
{
printf("hehe");
}
}
return 0;
}
//打印出100个hehe
#include
int main()
{
int i = 0;
int j = 0;
for (; i < 10; i++)
{
for (; j < 10; j++) //因为初始化部分省略,没有给j赋初值
{
printf("hehe");
}
}
return 0;
}
//打印出10个hehe
在小编看来,学校是不会讲goto语句的,因为如果goto语句用的不好,会导致程序跳来跳去的。但是这篇博客是分支语句和循环语句全详解,所以小编还是要讲一讲。
C语言中提供了可以随意滥用的goto语句和标记跳转的标号。从理论上goto语句时没有必要的,实践中没有goto语句也可以很容易的写出代码。但是某些场合下goto语句还是用的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。
例如,一次跳出两层或多层循环。
多层循环这种情况使用break是达不到目的的,他只能从最内层循环退出到上一层的循环。
在上面,小编为读者解释了goto语句的作用,那么下面小编将为读者们写下goto语句的代码:
for(...)
for(...)
{
for(...)
{
if(disaster)
goto error:
}
}
...
error:
if(disaster)
//处理错误情况
这个是一个关机程序的例子,也是一个恶作剧,等读者学会后,读者可以去恶搞你的室友。
#include
#include
#include
int main()
{
char input[10] = {0};
system("shutdown -s -t 60");
again:
printf("电脑将在1分钟内关机,如果输入:我是猪,就取消关机!\n请输入:>");
scanf("%s", input);
if(0 == strcmp(input, "我是猪“)
{
printf("shutdown -a");
}
else
{
goto again:
}
return 0;
}
Hello,各位!今天来通过一个小游戏引进一个知识点:生成随机数。下面进行介绍的所有概念都有对应的链接进行匹配,详细内容请点击链接进行观看。
先来介绍一下随机函数rand():rand函数的介绍。返回值为0到RAND_MAX(32767)的一个伪随机数。在使用rand函数之前,要先使用srand函数,设置随机数的生成起点。(这句话可能有些小伙伴们不懂,但往下继续看。)
在来介绍一下srand()函数:srand函数的介绍。函数的参数为:伪随机数字的种子生成。上述两个函数都有提到:伪随机数字,那么伪随机数字究竟是什么?下面来跟着小编来一起探索。
在计算机中不可能产生出完全随机的数,产生的是一个伪随机数。就比如,我们现在写一个程序要产生随机数,但理论上我们每一次去运行程序产生的随机数是一样的。代码如下:
int i = 0;
while (i < 3)
{
int ret = rand();
printf("%d\n", ret);
i++;
}
return 0;
所以光用一个rand()函数不能产生一个随机数的,为了每一次进行调用的时候,返回值都不一样,所以就有了种子的概念。
(种子,不是bt的种子。)在前面的时候,已经介绍过了srand函数的参数是种子,作用是:使每次调用函数后,参数不同,从而使返回值都不一样。
下面来进行手撕代码:(我们要习惯于学习和适应手撕一些库函数,以至于我们能更好的地使用它们)
先来看rand()函数:这个next的数据可以随便进行乘除,我感觉无所谓。
static unsigned long int next = 1; //将数据放在静态区中
unsigned int randX()
{
next = next * 1103515245 + 12345;
return (unsigned int)(next / 65536) % 32768;
}
再来看srand()函数:
void srandX(unsigned int seed)
{
next = seed;
}
讲完上述两个函数,接下来,进行讲述如何在电脑上真正地打印出随机数。在前面,我们每一次进行更换srand()函数的种子时,我们会发现生成的随机数再不断发生变化。而我们知道,一个变化的srand值可以对应不同的随机数值,而在电脑中,时间就是那个一直在变化的值。对于每个变化的时间,我们都有唯一的数字可以表示它,这个数字叫做时间戳(时间戳)。
简单介绍一下这个函数,详细内容在:time函数的介绍。该函数可以返回一个时间戳(当前机器的时间与计算机起始时间的一个差值)。
time函数的参数是一个指针,如果你不想用的话,直接写成NULL即可。其返回类型为:time_t,所以在使用time函数时需要进行强制类型转换。
srand((unsigned int)time(NULL))
time_t 是什么类型呢?
在学完上面如何生成随机数后,接下来,我们要将今日所学的所有内容串起来,那么就请跟随我的脚步进行学习吧!在下面的教程中,我会采用分模块的方式进行每一步的讲解,想要代码的不用担心,我会在最后将代码放上去的。由于这个程序过于简单,我们就不分多文件进行编写。
首先,这个游戏——猜数字,不会只进行一遍,我们需要猜好几个数字,不然的话会很没意思,这里就需要我们今天学习的循环语句进行编写。循环语句有三个,我们需要选择哪一个语句进行编写呢?我们玩游戏肯定是需要先玩一下了,管他那么多干什么,所以我们用do……while语句进行编写。
一个游戏他需要有菜单,菜单上有几个选择,根据选择不同的选项来进行功能的使用。这是不是很像今天我们学习的分支语句,像这种选择几,就进行哪一项功能,用switch()语句就好不过了,那么经过分析以后,我们来动手编写游戏的主体吧!
int main()
{
do
{
//……
//菜单和选择功能的实现
}while();
return 0;
}
为了使整个程序看起来不那么乱,我们需要进行函数的编写——自定义一个函数(详细地介绍函数)。需要我们在主函数中声明一下,因为玩家每猜对一个数字都可以自行选择继续游戏还是退出游戏,所以要将菜单放入循环体,以便玩家进行自由选择。
void menu()
{
printf("*****************************\n");
printf("********* 1. play **********\n");
printf("********* 0. exit **********\n");
printf("*****************************\n");
}
在这一部分中,input的取值是关键,放在while中,如果想要退出,则需要条件为假,这种设计退出程序,我们要使input为0,刚好在while中表示假,一举两得。
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请开始你的表演\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择:>");
break;
}
} while (input);
这一部分要好好了解一下,因为这一结构是简单游戏设计的大致思路,在之后的游戏中,小编也会使用到这个结构的,请好好消化一下!通用代码如下:
void menu()
{
printf("*****************************\n");
printf("********* 1. play **********\n");
printf("********* 0. exit **********\n");
printf("*****************************\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请开始你的表演\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择:>");
break;
}
} while (input);
return 0;
}
猜数字怎么实现呢?猜数字的实质是比大小,所以有三种情况(使用分支语句if):情况一——两者相等;情况二——前者比后者大,需要我们重新输入;情况三——前者比后者小,需要我们重新输入。所以在游戏函数主体需要死循环(只能使用while循环),只有猜对之后,才会跳出循环。
void game()
{
//猜数字游戏的关键是获得一个随机数,用rand()函数进行获得
//但是如果光用一个rand()函数来获取一个随机数的话,每次运行程序获得的数字是一样的
//所以将srand()和rand()混合使用
int ret = rand() % 100 + 1;//为了获取1~100的随机数
int secret = 0;
while (1)
{
printf("请输入数字:>");
scanf("%d", &secret);
if (ret == secret)
{
printf("恭喜你猜对了!\n");
break;
}
else if (ret > secret)
printf("猜小了,请继续!\n");
else if(ret
在完成这个游戏后,我们可以将这个游戏的难度进行上升,就只能猜一定的次数,我们需要进阶函数代码。进阶代码如下:
void game()
{
int count = 0;
int ret = rand() % 100 + 1;
int secret = 0;
while (1)
{
printf("请输入数字:>");
scanf("%d", &secret);
if(count > 5)
{
printf("抱歉,次数已用完,请重新玩游戏!\n");
count = 0;
}
if (ret == secret && count <= 5)
{
printf("恭喜你猜对了!\n");
break;
}
else if (ret > secret)
{
count++;
printf("猜小了,请继续!\n");
}
else if(ret
#include
#Include
#include
void menu()
{
printf("*****************************\n");
printf("********* 1. play **********\n");
printf("********* 0. exit **********\n");
printf("*****************************\n");
}
void game()
{
//猜数字游戏的关键是获得一个随机数,用rand()函数进行//获得
//但是如果光用一个rand()函数来获取一个随机数的话,每//次运行程序获得的数字是一样的
//所以将srand()和rand()混合使用
int ret = rand() % 100 + 1;
int secret = 0;
while (1)
{
printf("请输入数字:>");
scanf("%d", &secret);
if (ret == secret)
{
printf("恭喜你猜对了!\n");
break;
}
else if (ret > secret)
printf("猜小了,请继续!\n");
else if(ret ");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请开始你的表演\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择:>");
break;
}
} while (input);
return 0;
}
本次小编详细地介绍了分支语句和循环语句以及分支语句和循环语句的易错点,但分支语句和循环语句的易错点应该不是很完善,有详细的写出了猜数字游戏的代码,愿各位大佬进行批评和指正,请受下小弟一拜。