- do while for 关键字
- break&&continue区别
- 循环语句的注意点
- goto关键字
- void 关键字
- void a
- 为何void不能定义变量呢?
- void修饰函数返回值和参数
- void指针
- void*用来设计通用接口
- 定义的指针变量可以进行运算操作吗?
- void*可以直接解引用吗?
三种循环的各自写法
//for
for(条件初始化; 条件判断; 条件更新){
//业务代码
}
//while
条件初始化
while(条件判断){
//业务代码
条件更新
}
//do while
条件初始化
do
{
//业务代码
条件更新
}while(条件判断);
for循环的执行逻辑就是()里的条件初始化先(只)执行一次,然后条件判断,业务代码,条件更新,条件判断,业务代码……
while循环的条件初始化在外面,也就是先(只)执行一次,然后是条件判断,业务代码,条件更新,条件判断,业务代码……
do while循环的条件初始化和上面一样,但是唯一不同的是该循环至少执行一次业务代码,然后才是条件更新与判断……
其实这个循环的条件初始化全部都是只执行一次,而for循环则是把条件初始化写在()里了。
while循环的三个点是较为分散的,分别在代码块外,括号内,代码块内,而for循环则是把这三者集成到了一个()中,在使得用户编写代码时一般能有更好的体验。
而对于while、do while循环,它们的条件更新和业务代码逻辑随便颠倒,但只要保证条件是更新一次,判断一次即可。
三种循环的死循环写法
for(;;){
...
}
while(1){
...
}
do
{
...
}while(1);
其实只要保证条件判断一直是真就可以。
break&&continue区别break是终止本层循环,而continue是终止本次(一次)循环。
在循环中,执行到break时,会(永久)跳出循环,去执行循环之外的代码。而执行到continue时,会跳转到循环开始时的条件判断(在for循环中是先跳转到条件更新再条件判断)处,若条件判断为真,则继续进行循环。
注意:
continue不能够在switch case语句中使用!
循环语句的注意点在多重循环中,如果有可能,应当将最长的循环(循环次数最大)放在最内层,最短的循环(循环次数最小)放在最外层,以减少CPU跨切循环层的次数。
像第二个效率就会比第一个高一些,但是差别不会特别大。一般推荐。
强烈建议for语句的循环控制变量的取值采用“半开半闭区间”写法。
第一种写法比第二种好太多了,因为这样写可以达到两个目的:循环次数明确、便于进行个数计算
同样的循环,第一种写法一看就是循环10次,计算过程10 - 0 = 10,而第二种写法看起来不直观,无法达到一眼就明确循环次数,计算过程9 - 0 + 1 = 10。而且在leetcode上刷题时,第一种写法会使昨天更轻松。
不能在for循环体内修改循环变量,防止循环失控。
在for循环体内修改变量,很有可能会陷入死循环,不推荐这样做。
循环要尽可能短,要使代码清晰,一目了然。
作为一个程序员,肯定是要使得代码在逻辑清晰,可用的情况下使代码更短的,不过代码量问题是要结合场景来决定的。
把循环嵌套控制在3层以内。
循环层数太多,非常不利于用户的阅读与调试,而且三层以上的循环嵌套在实际工作中也基本很少遇到。
for语句的控制表达式不能包含任何浮点类型的对象。
for循环一般情况下都是跟循环次数有关的,而循环次数一般都是用整型来算的。况且,浮点数在内存中是有精度损失的,综上不建议for语句控制表达式包含浮点数。
goto关键字基本使用
goto语句有两部分,一个是goto另一个是标签,标签顶格写加一个:,然后在使用goto时,直接goto 标签;即可,所以,goto的自由度是极高的,想跳到哪里就跳到哪里(在同一函数内),标签不影响其它代码,就相当于是在某一行做了个记号而已。
对于对goto语句不熟悉或者是掌握一般的用户来说, 一般不建议使用goto语句。
自从提倡结构化设计以来,goto就成了有争议的语句。首先,由于goto语句可以灵活跳转,如果不加限制,它的确会破坏结构化设计风格;其次,goto语句经常带来错误或隐患,它可能跳过了变量的初始化、重要的计算等语句。如果编译器不能发觉此类错误,那么每用一次goto语句都可能留下隐患。
很多公司确实是禁止使用goto的,但是goto在解决很多问题时是有奇效的,而且goto只是使用场景较少,一般不使用,但是也有不少使用goto的用户,像linux内核中就用到了几十万行的goto。
所以不建议一般用户使用goto语句,除非你对它特别熟悉。
void 关键字 void avoid是否可以定义变量呢?
可以看到,在linux和vs2019环境下都不可以定义变量。
为何void不能定义变量呢?定义变量的本质:开辟空间。
而void作为空类型,理论上是不应该开辟空间的,即使开了空间,也仅仅作为一个占位符看待
所以,既然无法开辟空间,那么也就无法作为正常变量使用,既然无法使用,编译器干脆不让它定义变量。
在linux和vs2019环境中分别测试出void的内存大小为1bit和0bit,这里的1bit可以看作是用来作为占位符的,而0bit解释成:开辟0内存空间。既然是这样那么编译器直接就禁止void开辟空间。
void修饰函数返回值和参数函数返回值
可以看到,test()函数即使没有加返回参数类型,也没有任何的报错警告,并且可以正常编译,这说明了函数的默认返回参数类型是int.
而加了当函数返回参数类型加上void之后,有警告,但可以编译,但是在用一个变量接收这个返回值时却报错无法编译。
这说明了,当函数返回参数类型是void时,该函数无法接收并且保存返回值。
还有一点,当函数不需要返回参数时,一定要加上void,而不要忽略进而不写返回参数类型,因为这时,用户无法确定该函数是忘记写返回参数类型了还是使用的默认返回参数类型(int)。
参数
test()函数是不需要参数的,但是给它传参,依旧不会有任何警告报错,并且可以运行。
而当test()函数的参数列表写上void后,再给函数传参,依旧可以运行(说明传参成功),但是出现了警告。
在linux
在linux中,对加了void的函数传参会报错无法编译。
综上说明了,当函数不需要参数时,也是可以进行传参的,但是当不需要参数时,加上void会警告用户,该函数不需要参数。
void指针上面说到了void不能定义变量,那么void*是否可以呢?
很完美的运行了,所以void*是可以定义变量的。那么为什么呢?
void*是指针,而只要是指针,空间大小就是确定的,在32位平台4个bit,在64位平台8个bit。
可以看到,无论是void*接收其它类型的指针,还是其它类型的指针接收void*,都不会产生警告报错。
结论:void*的作用是用来接收任意类型的指针的(最常用)。
void*用来设计通用接口比如说memset函数
该函数的作用就是将ptr所指向的内存块的第num个字节设置为value
参数设置成void*可以操纵任意类型的内存块。
定义的指针变量可以进行运算操作吗?可以看到,除了void*以外的指针是可以进行运算的,而void*进行运算时,出现了两个错误,导致不能编译成功。
在linux环境下测试
void*是可以进行运算的,这是为什么呢?根本原因是因为使用的C标准拓展的问题。
GNU计划,又称革奴计划,是由Richard Stallman(理查德 · 斯托曼)在1983年9月27日公开发起的。它的目标是创建一套完全自由的操作系统。它在编写Linux的时候自己制作了一个标准称为GNU C标准。ANSI 美国国家标准协会,它对C做的标准ANSI C标准后来被国际标准协会接收成为标准C,所以,ANSI C和标准 C是一个概念,总体来说现在Linux也支持标准C,以后标准C可以跨平台,而GNU C 一般只在Linux C 下应用。 - - - 来自百度
Linux上可用的C 编译器是GNU C 编译器,它建立在自由软件基金会的编程许可证的基础上,因此可以自由发布。GNU C 对标准 C 进行一系列拓展,以增强标准 C 的功能。 - - - 来自百度
总结:大部分编译器是标准 C ,而Linux下是拓展 C,Linux平台也能保证标准 C 的运行。
void*可以直接解引用吗?换成Linux下再试试
原因:解引用指针时,是在访问指针所指向的空间,而void是空类型,void既然都无法定义变量,那又如何访问呢?



