Linux系统操作
[]表示里面可以不写
① 打开终端Ctrl + alt + t 或 Ctrl + Shift + n (在已经打开一个终端的前提下)
② 关闭终端 Ctrl + d 或 exit 或 alt + F4 或 ctrl + shift + q
③ 打开标签 ctrl + shift + t
④ 关闭标签 ctrl + shift + w
⑤ 切换到对应的标签
Alt + 数字
Shift + Ctrl + PgUp/PgDn 左移右移标签页
Ctrl + PgUp/PgDn 切换标签页
⑥ 调整终端
放大:ctrl+shift+"+"
缩小:ctrl+"-"
man加语法:查询语法用途
pwd 显示用户在文件系统中的当前位置
ls 浏览目录 ls[options][files_or_dirs]
ls ..\:显示上一级文件
cd 切换目录
cat 查看文件内容 cat-s:空行合并 cat-b:加行号显示
mkdir 创建指定名称目录
要求用户在当前目录下具有写权限,并且创建的目录不能与已有目录重名。
mkdir 目录名:创建一个空目录 --- mkdir test1
mkdir -p 子目录1/子目录2:先创建子目录1再在子目录1下创建子目录2 --- mkdir test1/test2
mkdir -v 目录名:创建目录后显示信息 --- mkdir -v test3
mkdir -m 权限码 目录名:创建一个权限为(权限码)的空目录 --- mkdir -m 777 test4
touch:创建文件
如果文件不存在,创建文件,如果文件存在,则修改该文件的时间戳为当前时间
touch -t 时间 文件名:修改文件的时间戳为指定时间。
touch -t所需要的时间格式:[[CC]YY]MMDDhhmm[.SS],如201410112233.44
touch day2.txt
touch main.c main.cpp main.java main.py main.js
rm:删除文件或目录
rmdir:删除空目录
mv:移动文件 或重命名文件 (重命名第二个标题不存在即可)
cp:复制文件或目录
man:查看帮助文档
sudo:临时获得管理员权限
用户切换:
普通用户----超级用户
sudo su
// su root
超级用户---普通用户
exit
su + username
临时获取超级用户权限:
sudo + 命令
sudo apt install 软件名
cat:查看文件内容
cat 文件名
查看ip地址
windows:打开终端 输入 ipconfig
Linux:打开终端,在终端中输入 ifconfig
注意:
ubuntu 18.04 中使用ifconfig 会报错,需要安装网络工具 sudo apt install net-tools
vi 编程序
新增(append,简写为a)
a:从光标所在位置后面开始新增
A:从光标所在行最后的地方开始新增
插入(insert,简写为i)
i:从光标所在位置前面开始插入
I:从光标行所在的第一个非空白字符前面开始插入
开始(open,简写为o)
o:在光标所在行的下一行新增一行并开始插入
O:在光标所在行的上一行新增一行并开始插入
进入底行模式
按 " : " 键可以进入底行模式
返回命令模式
按ESC键
复制剪切粘贴操作
按行复制/剪切命令
光标移动到文本文件的某一行,输入yy/dd,表示按行复制/剪切;
h:向左移动
j:向下移动
k:向上移动
l:向右移动
b:移动到当前单词开始
e:移动到当前单词结尾
w:移动到下一个单词
行首:0
行尾:$
文件头:gg
文件最后一行:G, 如果要到文件尾用G$
对光标位置到该行的结尾进行复制/剪切
命令y$/d$,表示从当前光标复制/剪切到当前光标结尾
多行复制命令
我们可以将光标移动到某行,我们输入命令nyy/ndd
粘贴操作
命令p/P表示粘贴,如果需要将复制的内容多次粘贴,则多次按p键就可以了。
错误撤销恢复
命令u表示撤销上一步操作,如果需要多次撤销,则多次按u键就可以了
如果我们上一次的撤销错了,取消撤销,可以按ctrl+r恢复
保存
如果使用vim打开现有文件的话,可以使用命令**:w**直接保存到原始文件中
w 路径和文件名,即可以指定名称保存到指定路径。
wq表示写入退出命令
q!表示不保存退出命令
查找
/ <需要查找的字符> 向下查找
?<需要查找的字符> 向上查找
设置高亮显示:set hlsearch
取消高亮显示: set nohlsearch 或 :nohl
如果文本中含有多个匹配字符,则可以按n来自动查找下一个匹配的字符,按N键就可以查找上个匹配的字符。这样就能对查找到的内容进行上下移动。
程序的编译和调试
gcc -o hello hello.c
-o输出可执行任务
-c 只要求编译器输出目标代码(.o文件),而不必输出可执行文件
-g 用于调试
./hello 查看输出结果
gcc 编程格式
gcc编译步骤:
gcc -E [].c -o [].i
gcc -S [].i -o [].s
gcc -c [].s -o [].o
gcc [].o -o []
注释三种方法:
数据的表示
基数,权
十进制:0 1 2 3 4 5 6 7 8 9(基数十,权为10**0往上)
Eg:123=1*10**2+2*10**1+3*10**0
二进制:0 1
Eg:1010=1*2**3+0*2**2+1*2**1+0*2**0=10
十六(0x前缀):0 1 2 3 4 5 6 7 8 9 a b c d e f
Eg:0x1010=1*16**3+...=1*4096+0*256+1*16+0*1=5012
八(0前缀):0 1 2 3 4 5 6 7
Eg:25转二进制:11001(算完反着输入)
二进制:原码,反码,补码
正数,三码一样
101 101 101
负数(符号位不变) 原 反码 补码(反码加1)
0-正,1-负)10000101 11111010 11111011
基本数据类型
整型
int(整型) %d (读取一个整数值)
long int(长型) %ld
short int 短型
字符型
char %c (字符)
char %s (从输入中读取一个字符串)
浮点型(实型)
float(单精度) %f
double(双精度) %lf
long double
其他类型
枚举型
enum
结构体
struct
共用体
union
空类型
void
数据类型
基本类型
整型 :signed short/int long
unsigned long long
字符型 : char
实型 : float double
枚举型 : enum
构造类型
数组
结构体 : struct
共用体 : union
指针类型
空类型
字符常量
关键字
[1]基本数据类型关键字
void: 声明函数无返回值或无参数,声明无类型指针,显示丢弃运算结果。
char: 字符型类型数据,属于整数数据的一种。
int: 整型数据,表示范围通常为编译器指定的内存字节长
float: 单精度浮点型数据,属于浮点数据的一种
double: 双精度浮点型数据,属于浮点数据的一种
[2]构造数据类型
数组(eg:int a[])
结构体struct
联合体(或共用体)union
枚举类型enum
[3]指针类型 (如int *p)
[4]空类型void
变量与常量
常量
[1]直接常量:直接引用的数字等;
字符常量‘A’ , ‘a’
整型常量10 100 0b1101 0664 0xaf
实型常量3.14 5.69
字符串常量 "hello world""100"
[2]符号常量:使用标识符来代替一个数字(常见的:宏定义常量 和 常变量)
宏
#define PX printf("x is %d,\n",x)
预处理 宏 替换体
eg: #define PI 3.14 //PI是3.14
sizeof
【获取某个数据类型或变量的长度可以使用操作符,以字节为单位来计数】
const 【要长用】(只读不写)
const int()
常变量
变量值不可改变的量,使用const修饰
const int a=10; //定义一个常变量
a = 9; //报错,a为const修饰不可改变
const修饰后的变量会变成只读,因此无法再次赋值。
整数的显示
显示十进制整数
%hd、 %d、 %ld 以十进制、有符号的形式输出 short、 int、 long 类型的整数
%hu、 %u、 %lu 以十进制、无符号的形式输出 short、 int、 long 类型的整数
显示八进制整数
%ho、 %o、 %lo 以八进制、不带前缀、无符号的形式输出 short、 int、 long 类型的整数
%#ho、 %#o、 %#lo 以八进制、带前缀、无符号的形式输出 short、 int、 long 类型的整数
显示十六进制整数
以十六进制、不带前缀、无符号的形式输出 short、 int、 long 类型的整数。如果 x 小写,那么输出的十六进制数字也小写;如果 X 大写,那么输出的十六进制数字也大写。
%hx、 %x、 %lx
%hX、 %X、 %lX
以十六进制、带前缀、无符号的形式输出 short、 int、 long 类型的整数。如果 x 小写,那么输出的十六进制数字和前缀都小写;如果 X 大写,那么输出的十六进制数字和前缀都大写。
%#hx、 %#x、 %#lx
%#hX、 %#X、 %#lX
整数溢出
实型
小数指数形式
aen 或aEn
eg:2.1E5 = 2.1×(10^5),其中 2.1 是尾数, 5 是指数。
输出格式
%f:输出十进制计数法的float和double数字;
%e:输出指数计数法的float和double数字;
%lf、%le:输出double类型的数字;
%Lf、%Le:输出long double类型的数字;
浮点数的溢出
字符型
字符表示
小写字母变为大写字母:-32
大写字母变为小写字母:+32
字符变量
char
转义字符
\n 回车换行
\t 水平跳到下一制表位置
\b 向后退一格
\r 回车,将当前位置移到本行开头
\f 换页,将当前位置移到下页开头
\ \ 反斜杠符
\ ' 单引号符
\ddd 1~3位八进制数所代表的字符
\xhh 1~2位十六进制数所代表的字符
数据类型转换
隐式类型转换
赋值转换
位数短的向位数长的可以转
位数长的不可以向位数短的转
浮点型与整型赋值转换
【1】将浮点型数据赋给整型变量时,舍弃浮点数的小数部分。
例:int i = 3.56; //此时i的值为3
【2】将整型数据赋给浮点型变量时,数值不变,但以浮点数形式存储到变量中
例:float f = 23; //此时f的值为23.0
double型与float型赋值转换
【1】将一个double型数据赋给float变量时,截取其前面7位有效数字,存放到float变量的存储单元(4个字节)中。但应注意数值范围不能溢出。
【2】如果将一个float型数据赋给double变量时,数值不变,存储方式与有效位数与double类型保持一致。
字符型与整型赋值转换
【1】将一个整型数据赋给一个char型变量时,只将其低8位原封不动地送到char型变量(即截断)
【2】字符型数据赋给整型变量时,将字符数据放到整型变量存储单元的低8位中。
① 对于无符号字符类型,则将字符的8位放到整型变量低8位,高24位补零;
② 对于有符号字符类型,若字符最高位为0,则整型变量高24位补0;若字符最高位1,则高24位全补1
int类型与long类型赋值转换
只考虑int型与long类型长度不一致情况
【1】将long类型赋值给int类型时,直接截断数据,将低位原封不动存储在int型中。
【2】将int类型赋值给long类型时,分两种情况:
① 无符号int类型(即unsigned int型),数据存储在long类型低位,剩下位补0
② 有符号int类型,数据存储在long类型低位。若int首位是0,则剩下位补0;若int首位是1,则剩下
位补1。
总结:类型升级通常不会有什么问题,但是类型降级却会带来不少问题。
例如:char ch = 1222; 1222 降级为 char,但 char 无法表示 1222。
再如:int J = 22.2; 22.2 降级为 int,小数部分被截断。
强制类型转换
隐式类型转换或赋值转换有时不会得到我们预期的结果,这时我们可以使用强制类型转换来实现我
们想要的类型转换结果。
强制类型转换:人为地将某类型转换为另一类型
强制类型转换符: ()
(类型名) 表达式;
示例:
(double) a: 将a转换成double类型
(int) (x + y): 将x+y的值转换成整型
(float)(5 % 3): 将5%3的值转换成float型
运算符和表达式
运算分类
【1】根据结合数的数目分类:
单目运算符:即操作数只有1个的运算符
双目运算符:即操作数有2个的运算符
三目运算符:即操作数有3个的运算符,只有一个( ?: )
【2】根据运算符的用途分类:
赋值运算符:如=及其扩展运算符
逻辑运算符:如&&(与)、||(或)、!(非)
算数运算符:如+ - * / %等
关系运算符:如> < >= <= == !=等
位运算符:如<< >>等
条件运算符:只有一个 ?:
逗号运算符:只有一个 , 用于分隔
运算结合方向
运算符有两种结合顺序:自左至右、自右至左
自左至右(左结合性):表示运算符的操作数是从左向右(先左再右)与运算符结合的,如加法+
例:3 + 5,即3加上5,先取3,再取+,再取5
自右至左(右结合性):表示运算符的操作数是从右向左(先右再左)与运算符结合的,如赋值=例:a = 3,即先取数3,再给a赋值
运算符优先级
算数运算符
四则运算符和求模运算符
符号及含义:+(加) -(减)*(乘)/(除) %(取余)
数目:双目运算符
结合性:自左至右
优先级:+和-:4级。*和/和%:3级
使用方法:表达式 运算符 表达式。如:3+5 a-b等
注意:
① C语言中,若相除2个数都是整数,则计算/时只取商,余数部分被舍去。
② %的操作数必须是整数
正运算符和负运算符
符号及含义:+(正数) -(负数)
数目:单目运算符
结合性:自右至左
优先级:2级
使用方法:+ 表达式 或 - 表达式。
自增运算符和自减运算符
符号及含义:**++(自增1) --**(自减1)
数目:单目运算符
结合性:自左至右 或 自右至左(取决于运算符位置)
int a = 3;
printf("%d\n",-a); // 对a取负数,会输出-3优先级:2级
使用方法:
自增;变量++ 或 ++变量。如a++ 或 ++a
自减:变量-- 或 --变量。如b-- 或 --b
注意:
① 自增或自减运算符仅用于变量,不能用于常量或表达式
② 注意++/--运算符与+/-(正数/负数运算符)是同等优先级。当这两个运算符一起使用时,是右结合
性。即--a++ <---等价于---> --(a++);
③ 自增或自减运算符可用在操作数之前,也可以放在其后,这两种用法稍有区别:
运算符在操作数前时:
C语言在引用操作数之前那就先执行加1或减1
例如:j = ++i;其执行过程是,先将变量i+1,再将计算结果赋给j。
运算符在操作数后时:
C语言先引用操作数的值,然后再进行加1或减1,
例如:j= i--;其执行过程是,先将变量i的值赋值给j;再执行将变量i-1。
关系运算符
符号及含义:>(大于) <(小于) >=(大于等于) <=(小于等于) ==(判等) !=(不等)
数目:双目运算符
结合性:自左至右
优先级:> < >= <=:6级。==和!=:7级
使用方法:表达式 运算符 表达式。如3<5,a==7等
注意:
① 关系运算符的操作数可以是变量、常量和表达式
② 关系表达式的的值是一个逻辑值:关系成立,即为真,结果为1;关系不成立,即为假,结果为0
③ 注意区分判断两个表达式相等的运算符是==,与=(赋值运算符)
逻辑真值和逻辑假值在c里是如何表达的?
0表示逻辑假,如0、0.0、\0、NULL
非0表示逻辑真,而且非零不一定是整数,可以是任何类型
逻辑运算符
符号及含义:&& (逻辑与) ||(逻辑或) !(逻辑非)
数目:!为单目运算符,&& 和 || 为双目运算符
结合性:!为自右至左,&&和 || 为自左至右
优先级:!:2级、&&:11级、||:12级
使用方法:
&&和||:表达式 运算符 表达式。如:a && b、a || b
!:!表达式。如 !a
注意:
① 逻辑与:当且仅当两个表达式都为真时,则计算结果为真。否则为假
if ((a>10) && (a<20))② 逻辑或:当且仅当两个表达式都为假时,则计算结果为假。否则为真
③ 逻辑非:当原表达式为真时,计算结果为假;当原表达式为假时,计算结果为真
④ 使用逻辑运算符的表达式结果为真或假;
逻辑与(&&)运算符短路
表达式1 && 表达式2 && 表达式3
当表达式1是真时,才会去判断表达式2的真/假。否则,如果表达式1是假,则之后的都不会进行运算。
当表达式2是真时,才会去判断表达式3的真/假。否则,如果表达式2是假,则之后的都不会进行运算。
逻辑或(||)运算符短路
表达式1 || 表达式2 ||表达式3
当表达式1是真时,跳过判断表达式2和表达式3,直接返回真;
当表达式1是假时,才去判断表达式2的真/假
当表达式2是真时,跳过判断表达式3,直接返回真;
当表达式2是假时,才去判断表达式3的真/假
注意:
这里要特别注意&&的运算优先级比||高。运算优先级高并不代表会先运算,而是代表先与操作数
结合。而整个算式还是按照自左至右顺序计算。
条件运算符
符号及含义: ?: (判断?前表达式是否成立,若成立取:前表达式,否则取:后表达式)
数目:三目运算符(
C语言中唯一的三目运算符)
结合性:自右至左
优先级:13级
使用方法:表达式1 ?表达式2 :表达式3。
先判断表达式1是否成立,若成立取表达式2,否则取表达式3。
条件运算符相当于小型的if-else表达式
长度运算符
符号及含义:sizeof()(计算括号内数据类型或表达式的大小)
数目:无
结合性:无
优先级:2级
使用方法:sizeof(表达式) 或 sizeof(类型名)
sizeof()用于计算某类型或某表达式所占内存的大小,经常与结构体/数组等连同使用
逗号运算符
符号及含义: ,(连接多个表达式组成一个新的表达式,并将最后一个表达式的值作为整个逗号表达式的
值)
数目:未知
结合性:自左至右
优先级:15级(最低)
使用方法:表达式1,表达式2, …,表达式n
y = ((x=a+b),(b+c));
y 等于整个逗号表达式的值,就是表达式2的值,x是第一个表达式的值。
注意:
并不是所有出现逗号的地方都组成逗号表达式,如变量说明中,函数参数表中的逗号只是用作各变
量之间的间隔符。例如:float x = 10.5, y = 1.8, z = 0;
算符
描述
按位与( x &y )
如果两个操作数的相应位均为 1,则该位的结果值为 1
按位或( x |y )
如果两个操作数的相应位有一个为 1,则该位的结果值为 1
按位取反(~x )
将操作数按位取反(0 到 1 和 1 到 0)
按位异或(x^y )
如果参加运算的两个操作数的相应位同号,则结果为 0,异号则为 1
左移( x<<2 )
左端(高位)移出部分舍弃,右端(低位)补0
右移( x>>2 )
右端(低位)移出部分舍弃,左端(高位)根据符号位补0或者1,无符号或正数
补0,负数补1
位运算符
注意:
① 位运算符中除~以外,均为二目(元)运算符,即要求两侧各有一个运算量。
② 运算量只能是整型或字符型的数据,不能为实型数据。
③ 位运算符将数字视为二进制值,并按位进行相应运算,运算完成后再重新转换为数字
按位与(&)
&的运算规则:如果两个相应的二进制位都为1,则该位的结果值为1;否则为0。
按位或(|)
| 的运算规则:两个相应的二进制位中只要有一个为1,该位的结果值为1
按位异或(^)
^ 的运算规则:若参加运算的两个二进制位同号则结果为0(假)异号则结果为1(真)
按位取反(~)
~ 的运算规则:1-->0 0-->1(若是1则变成0,若是0则变成1)
移位运算符
【1】左移运算符(<<)
左移运算符是用来将一个数的各二进制位全部左移若干位。 高位左移后溢出舍弃,右边低位补0。
使用方法:表达式1 << 表达式2。如a<<3
结论:当某个整数左移时被溢出舍弃的高位中不包含1时。左移一位相当于乘2;
【2】右移运算符(>>)
右移运算符是将一个数的各二进制位全部右移若干位,移到右端的低位被舍弃,对无符号数,高位补0。
对于有符号的值,如果原来符号位为0(该数为正),则左边也是移入0。如果符号位原来为1(即负数),则左边移入0还是1,要取决于所用的计算机系统。有的系统移入0,有的系统移入1。移入0的称为“逻辑右移”,即简单右移;移入1的称为算术右移。
赋值运算符及复合赋值运算
符号及含义:=(赋值)+=(加后赋值) -=(减后赋值)=(乘后赋值) /=(除后赋值) %=(取余后赋值)<<=(左移后赋值) >>=(右移后赋值) &=\(按位与后赋值) ^=(按位异或后赋值)|=(按位或后赋值)
数目:双目运算符(一次赋值)
结合性:自右至左
优先级:14级
c语言程序结构
1.if-else结构
单分支结构
表达式是要判断的条件,如果条件为真则执行跟在后面的是一个或一组语句,如果条件为假则跳过不执行;
在if后的语句不止一个,应用大括号{}将他们组织起来。如果只有一个语句,大括号{}可以省略,但不建议。
双重分支结构
如果 if 表达式的值为true(非0),将执行 if 语句(一个或一组)后的语句块。如果 if 表达式的值为false(0),那么控制权将交给else 表达式后面的语句。else语句是可选的。 仅当 if 表达式的值为false时,才会执行else后的语句或语句序列
多重分支结构
首先判断条件1是否为真,若为真,则执行语句1并跳出,若为假则继续判断条件2是否为真,若条件2为真则执行语句2并跳出,否则继续判断条件3。以此类推。
if语句嵌套使用
在if语句中又包含一个或多个if语句称为if语句嵌套,其形式一般如下:
需要注意的是if和else的配对问题,一个匹配原则:在嵌套if语句中,else总与它上面最近的if配对
2.switch结构
if-else语句只能判断2个分支,若要判断多个分支则需要if-else的多次使用或嵌套使用,程序会变得很复杂,可读性差。switch是多分支选择语句。通过switch()的多分支判断可以简便地实现多分支选择结构。
说明:
1)switch(表达式)表达式的值应是一个整数(包括字符数据)
2)switch()下的{}是一段语句块,这段语句包含若干个以case开头的语句块和至多一个以default开头的语句块
3)case后需要一个常量(或常量表达式)。首先判断switch(表达式)的表达式的值,之后与各个case之后的值进行比对,如果某个case后的值与表达式的值相同,则跳转到此case语句;如果所有的case都不匹配,则跳转到default后的语句
4)可以没有default语句。若没有default语句,则如果没有匹配的case,则程序不执行任何语句
5)每个case语句后的常量值必须各不相同,否则会发生互相矛盾现象
3.循环结构
while循环
while循环在执行循环前检查条件,条件表达式一般为关系表达式或者逻辑表达式。只要表达式为真循环就会迭代,否则退出循环。循环体可以是空语句、一个简单的语句或语句块,如果while循环中包含一组语句,必须用{}括起来
do-while循环
先执行一次指定的循环体语句,然后判别表达式,当表达式的值为非零(“真”) 时,返回重新执行循环体语句,如此反复,直到表达式的值等于0为止,此时循环结束;while后面的分号不能省略:do {} while();
for 循环
表达式1:循环的初始条件,只执行一次。可以为0个、1个或多个变量设置初值
表达式2:判断循环结束的条件。在每次执行循环体前判断此表达式,若表达式为真则进入循环,否则不执行循环
表达式3:作为循环的调整(即改变循环状态),在执行完循环体之后执行
注意:
[1]for()括号内的3个表达式的分隔符是分号 ;不是逗号 ,
[2] for()括号内的3个表达式都可以同时省略,但是不能省略分号 ;,当省略表达式2时,程序将陷入死循环。
循环嵌套
如果一个循环出现在另一个循环中,则称它为嵌套循环。三种循环都可以相互嵌套,自由组合。
三个循环的区别和总结
三种循环可以处理同一问题,一般情况可以互相代替。但在实际应用中,我们要根据具体情况来选用不同的循环语句。选用的一般原则如下:
如果循环次数在执行循环体之前就已确定,一般用for语句;如果循环次数是根据循环体的执行情况确定的,一般用while语句或者do-while语句。
当循环体至少执行一次时,用do-while语句;反之,如果循环体可能一次也不执行时,用while语句。
其他控制
break
目录
break语句的用途:
用于在 switch 语句中终止case。
用来从循环体内跳出循环体,即提前结束循环,接着执行循环下面的语句。
注意
break语句不能用于循环语句和switch语句之外的任何其他语句中。
多层循环中,break只向外跳一层
continue
continue语句的作用:
结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定.
注意:
在while循环和do…while循环中,程序控制权传递给条件测试语句;
在for循环中,continue影响循环的增量部分,然后执行条件测试;
return
说明:
结束当前函数,并将返回值返回给函数调用的位置。
用法:
return 返回值;
其中返回值由函数类型决定。如main()函数是int类型,则需要返回一个整数。如果函数是void类型则无需写返回值。
*注意:*
表达式是可选的。一个函数中可以使用多个return语句,但是遇到第一个return语句时返回
goto
说明:
goto语句为无条件转向语句;
用法:
goto 标签;
当执行到goto语句时,程序会跳转到同一函数内goto语句所指向的标号处,例如下图,goto语句执行后,程序会自动跳转到label_1标签处。标签的命名规则与C语言标识符的命名规则相同
注意:
用不用goto一直是一个著名的争议话题,滥用goto语句会使程序无规律、可读性差。goto语句违背了C语言的模块化编程的基本思想,因此goto语句不推荐使用。
Linux内核源代码中对goto的应用非常广泛,但是一般只限于错误处理中。(最好不用)