C--深度剖析--关键字(6)

条件判断对于我们来说,已经是非常信手拈来的事情了,这里我总结一些小小的细节,让我们更好的更深度的理解条件判断。

循环语法的深入理解

三种循环结构理解

三种循环:
while
do while
for

首先我们了解一下循环的三要素:1、循环条件初始化 2、循环判定 3、 循环条件的更新

我们先来看看while循环
在这里插入图片描述
这张图标示了循环的要素和循环的执行顺序。
基本是一个顺序的结构,while()if()其实他们两个判定逻辑是一样的,先计算得到逻辑,再去判断逻辑,最后执行。只不过while一遍后会回到二处再次判定。


for循环
for(int i= 0;i <10 ;i++)
最大的优点是语法结构紧凑,你不用担心程序太大,导致少了循环条件更新等小操作,从而导致程序bug难寻。
在这里插入图片描述


do while循环
程序一定会进入一次,怎么验证呢?我们把while后的判断赋成假,发现循环体还会执行一次才退出。
再很多游戏场景中我们会用到它。
在这里插入图片描述
我们推荐这样的写法,while写到花括号后面,并且是有 分号 的哦,不要忘记了。

死循环写法

while(1)
{ }
这里不需要多解释了,当然括号里只要是非零都可以,但是1会规范点,你如果写个8,看代码的人可能会突然愣一下。

for( ; ;)
for这样用也是可以的,以前我都没怎么用过,以后要多试试

do{
}while(1)
这里和while一样了

getchar函数和相关深剖

我们首先知道,在c语言程序运行时,编译器会自动帮我们打开三个文件:
标准输入 stdin FILE* stdin (键盘)
标准输出 stdout FILE* stdout (显示器)
标准输入 stderr FILE* stderr (显示器)
他们叫标准输入输出流

他们是一种文件指针类型的文件,我们也知道
FILE * open这个函数是用来打开文件的,上面三个函数和open是相同的类型。
为什么要用FILE * 这样的类型定义他们呢?
这是因为这样就可以用操作文件的方法,操作一切。可以控制键盘显示器硬盘等等。

我们使用C语言的时候为什么没有打开过文件呢?
我们都是直接printf(); scanf();这样直接用。
而且为什么内容会被打印到显示器上呢?
这就是因为编译器自动打开了上面三个标准输入输出流。

因为我们程序员要调试代码,要组织代码,都需要输入输出等直观可视化的内容。不然如果不打开这三个文件,我们怎么输入,怎么看输出。还得我们自己打开,编译器一看,这活它干了。

我们回到我们getchar这个函数上,它的功能是从键盘上获取字符。
在这里插入图片描述
这里可没有那么简单,我们可以看到这个getchar字符的返回值怎么是int ,按照我们的常规思维,不应该返回char吗?

我们知道char的范围是 [ 0 ,255] ,其中他们的每一位都在ascll表中有对应的意义。那如果我们 char getchar()失败应该返回什么呢?
一共8个比特位, 从 0000 0000 -> 1111 1111
哪一个都不能代表失败的意思,这256个字符都有其各自的意思。那1 0000 0000它呢?这不是被截断了吗又是0.
所以我们无法表示错误。
这就用了int 来返回了。

第二点:

我们还需要知道的一点是,当我们getchar一个字符,如果我们用回车结束,那getchar会多打印一行回车,getchar本来带一位回车。这样会打印两行回车,再去输出你输入的字符。所以一般getchar时 我们不用回车,空格就好了。

第三个关键点是:
我们从键盘上输入的所有内容 ,显示器上打印的所有内容全部都是字符 !!!

我们经常写的代码
printf ( “ %d” ,1234);
这个时候显示在显示器上的,其实都是字符,并不是数字
那我凭什么这么说?
我们拿一下printf的返回值,在打印这个返回值我们可以得到如下结果。
在这里插入图片描述
很明显时5个字符。
不仅仅printf打印出的是字符,我们从键盘输入到显示器的也是字符。不过是通过scanf的格式控制,转换了格式,把字符转换成你需要的格式并放在变量空间中。

所以我们可以更深刻的理解什么是格式化输入输出。
printf和scanf ,它们格式的是什么?
其实就是把字符格式化成对应的格式。
所以,linux中说一切皆文件,所以,我们把键盘和显示器,叫做字符设备

break和continue

我们先来看看第一个代码,这个很好理解是吧。遇到#就截止了。直接跳出我们的循环。
在这里插入图片描述
再来看看第二个代码,continue ,我们发现它仅仅跳过了#,其他的都打印出来了。
在这里插入图片描述
那么这里提出一个问题,continue到底跳转到代码的那里了?
这里很明显,我们的while 和 do while()都是跳转到了条件判断的地方。
那for循环呢,它很与众不同。
在这里插入图片描述
我们通过结果可以看到,我们应该是跳转到循环变量更新的地方,否则都会形成死循环。所以这里只有一个5了。

我们写循环的时候,有几个注意事项:
建议一:
在这里插入图片描述
解释:两层循环来回跳转,会导致cpu的缓存非常的多,影响效率。当然还要考虑局部性原理。

建议二:
在这里插入图片描述
在这里插入图片描述
解释:1、循环的次数更加直观 2、便于用下标计算个数

建议三:
在这里插入图片描述
浮点数的存储会有很大的精度损失,在循环中会产生很多问题。

goto-真的很有用

我们先来看看goto的语法结构。
在这里插入图片描述
当然除了向下跳,我们还能向上跳。但很容易就导致死循环了。
在这里插入图片描述
既然我们讲的循环,那我们如何用goto实现循环功能呢?
在这里插入图片描述

goto只能在代码块里面使用哦,不能跨函数哦!

这里有一个建议:就是禁止使用goto语句
在这里插入图片描述
当然,这只是针对新手来说的,你如果有能力使用,它会产生起效。
告诉大家一个小秘密,linux内核源码代码中 ,有几十万行的goto语句的使用。
所以要锻炼自己,不要用goto把自己搞晕了,因为goto确实很破坏代码的结构。
在这里插入图片描述

void 的理解

void定义变量

void是什么,他在c语言中是一个种类型,但是它不能用来定义变量。
为什么呢?
在这里插入图片描述
在这里插入图片描述
我们可以看到,viod这个类型在vs中的字节是 0 , 那定义变量就需要根据类型的大小开辟空间,void可没法开空间。
在gcc下,我们可以看到它的字节数是1,当然 我们把这个1当作占位符来理解。

我们了解了这些,现在来看看到底原因是什么:
我们要开辟的大小是不知道的,并且它本身就被编译器解释为空类型,强制不允许你来定义变量。

viod 作为返回值

我们上文看到,void是不能定义变量的。但是viod 是可以作为函数的返回值的。
在这里插入图片描述
但是做返回值也是有条件的,我们不能够去接收返回值的结果。
在这里插入图片描述
当然还有一种情况,c语言可以完全不写返回值,就像c++构造函数那样。
在这里插入图片描述
这个时候再去用一个整形接收,发现突然就可以接收了,这可真是有点复杂啊。
我们来稍微做一下总结吧:
c语言函数可以不带返回值,默认返回值是int, 但是这样很容易引起误解?
你的同事看到代码,就会问,你这到底是忘了写返回值,还是默认用的int呢?
所以我们一般会主动的带上 void ,来说明这个函数没有返回值,也就是起了占位符的作用。

第二点:如果又人想通过函数的返回值,保存你的值进行修改。你加上void,别人就无法进行接收这个返回值了。

void作为函数参数

在这里插入图片描述
我们看上面这两段代码,两个函数,一个有void参数,一个没有参数。
我问一下大家:这个参数能传进去吗?函数会报错吗?
当我们传给无参函数的时候,发现完全没问题。但是当我们传给test2时,虽然编译过了,但是有一个小小的警告。在这里插入图片描述
所以void作为参数的作用就是:告知编译器,这个函数不需要参数,如果你要传参数,编译器会自动给你一个警报,并自动进行优化。
在这里void同样起到的时占位符的作用,告知程序员们,这里不需要参数。

以上时在vs中的实验结果,那如果在gcc中呢?
在这里插入图片描述
我们发现test1依旧没什么问题,但是在test2上,无法编译通过,直接在语法上报错了。

void与指针

void 既然不能定义变量,那void * 可以定义变量吗?
答案是可以的,因为我们void 不知道要开多少空间存变量的值,但是指针不一样啊,
指针类型在编译器下的类型和大小,明确是4或者8个字节。
在这里插入图片描述
这样写毫无问题!
void* 可以被任何类型的指针接收,也可以接收任何类型的指针。
在这里插入图片描述
在这里插入图片描述
正是因为这样的特性,我们在很多地方都可以做成通用类型的接口进行调用。
比如在库和系统接口的设计上,就是采用void*,你又没有模板、没有重载,这真是c唯一的杀器了
在这里插入图片描述
既然谈到指针,指针都是可以+±-操作的
在这里插入图片描述
一般就是移动指针类型大小的字节数,进行指针的操作。
那void可以吗?
在这里插入图片描述
这种情况是不行的,我们+±-就是为了向前向后移动指针类型的步长,那void
要怎么移动呢?
它指向的类型是void ,大小是 0 . 我们无法移动,编译器也不答应。
那你vs是0,那我gcc下可是1 啊,那我 void* +±- 可以吗? 答案是可以的,你成功的说服了编译器给你移动void*。
每个平台的特性都是不一样的。

不同编译器下的C语言特性

我们上文看了那么多有关gcc和vs下的对于C语言的不同
那么gcc和vs下的c语言编译器表现出的的不同特性,到底是为什么呢?为什么不把他们统一起来呢?
这样不是更加便于大家学习使用吗?
linux中c语言是对标准的一种扩展,不仅仅满足c语言的标准,还有更多新的标准,也就是GUN计划。
在这里插入图片描述

最后一个问题,void*可以解引用吗?
答案是不可以的,解引用后是void类型的变量,问题回到了上文,void是不能定义变量的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值