Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,关注+收藏,欢迎欢迎~~
💥个人主页:小羊在奋斗
💥所属专栏:C语言
本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为同样是初学者的学友展示一些我的学习过程及心得。文笔、排版拙劣,望见谅。
5、逗号表达式
6、结构体成员访问操作符
6.1结构体
6.2结构体变量的初始化
6.3结构体成员访问操作符
7、表达式求值
7.1整型提升
7.2算数转换
7.3问题表达式
5、逗号表达式
逗号表达式,就是用逗号隔开的多个表达式。逗号表达式从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
注意:千万不要想当然的以为整个表达式的结果是最后一个表达式的结果就直接去算最后一个表达式,一定要从左到右每个表达式都执行。
另外,逗号表达式还有一个神奇的用法,来看示例:
这两个代码的效果是一样的,第二种运用了逗号表达式从左向右依次执行的特点,使代码更简单一些。
6、结构体成员访问操作符
6.1结构体
C语言已经提供了内置类型,如:char、int、float、double、short等,但只是这些内置类型还是不够的。如果我们想描述一个复杂的个体,比如一个人、一本书,这时单一的内置类型是不行的。因为对于人而言,人有名字,有体重,有身高,有年龄;对于书而言,书有名字,有作者,有出版社,有定价等。那为了解决这个问题,C语言增加了结构体这种自定义的数据类型,让我们可以自己创建合适的类型。
结构体是一些值的集合,这些值称为结构体成员变量。结构体的每个成员可以是不同类型的变量,如:标量、数组、指针、其他结构体。
定义结构体:
比如我们定义一个学生类型:
对于结构体类型我们一定要保持头脑清醒,不然很容易云里雾里。我们首先定义了一个学生类型(struct student),在主函数中,我们用定义的学生类型分别创建了一个结构体变量 s1 和 s2 ,还用 int 类型创建了一个整型变量 a,struct student 和 int 都是数据类型,它们的本质是一样的。
定义一个结构体类型,就像工程师在建造房子之前先要画图纸一样,画好了图纸,就可以根据这个图纸来建造相应的房子,虽然我们最终建造的房子颜色、风格、房间布局不尽相同,但是房子的框架是一样的。同样的,我们可以使用自定义的结构体类型(图纸)来创建变量(房子),所创建的变量内部的值是不尽相同的(房屋风格)。
还有,我们定义的结构体类型里面是不能存放数据的,它只是一个模板,就像工程师画好的图纸还不能住人一样。造房子的前提是你得先画好图纸,你想造什么样的房子就画什么样的图纸,画好之后你就可以根据图纸造不同风格的房子。
我们同样可以用结构体类型创建局部变量和全局变量:
可以看到,我们有3个地方创建结构体变量。
6.2结构体变量的初始化
我们一层一层的给我们定义的结构体类型内的成员变量赋值就行。当然,结构体也是可以嵌套的:
6.3结构体成员访问操作符
在给结构体变量初始化后,也可以把它拿出来,这就用到了结构体成员访问操作符 “ . ”。
用法为:结构体变量.结构体成员名
还有一个结构体成员访问操作符 “—>”,这个是依赖指针的,后面再探讨。
7、表达式求值
7.1整型提升
C语言中整型算术运算总是至少以缺省(默认)整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换就称为整型提升。
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般都是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU中执行时也要转换为CPU内整型操作数的标准长度。
通用CPU是难以直接实现两个8比特字节直接相加运算的,所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行。
如何进行整型提升?
(1)有符号整数提升是按照变量的数据类型的符号位来提升的;
(2)无符号整数提升,高位补0。
来看下面几个示例:
当我们整型与整型相加的时候,不需要整型提升。
在上面的代码中,就需要整型提升。具体过程比较绕,还请耐心理解。
上面就是打印结果是44的原因。
事实上,我们知道char类型也被归为整形家族,也分有符号的char和无符号的char。int默认是signed int,那char是不是默认是signed char呢?其实不然,这个是取决于编译器的,只是在VS上char默认是signed char。之前的文章中说过signed char的取值范围是:-128~127,所以它根本就存不了100和200相加的值,来看下面的图:
就像上图表达的意思一样,数范围的变化是轮回的,对于300来说它轮回了一圈半,最终的值就是44。上面的内容都是计算机内部悄悄发生的,表面看不到,我们看到的只是结果。
7.2算数转换
算数转换讨论的是类型大于等于整型的类型的类型。如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则无法进行。下面的层次体系称为寻常算术转换:
1 long double
2 double
3 float
4 unsigned long int
5 long int
6 unsigned int
7 int
如果某个操作数的类型在上面这个列表中排名靠后,则首先要转化为另一个操作数的类型后执行运算。
7.3问题表达式
何为问题表达式?即使有了操作符的优先级和结合性,我们写出的代码(表面没有任何问题的代码)也不能确定唯一的计算路径,也就得不到唯一的值,那这个代码就是存在风险的,我们应该避免写成这样的代码。
我们来看几个例子:
虽然我们知道 “ * ” 的优先级高于 “ + ” 的优先级,但我们并不能确定在计算完前两个 “ * ” 后到底是先计算第一个 “ + ” ,还是计算第三个 “ * ”,同样编译器也确定不了,在不同的编译器中得到的结果是不同的。
类似例子1,在这个代码中虽然我们能确定 “ * ” 和 “ + ” 哪个先执行,但也不能确定是先执行完三个函数调用,还是执行完后两个函数调用后先计算 “ * ”,同样在不同的编译器中得到的结果也是不一样的。
这个例子还是一样的道理,我们确定不了是先执行三个自增表达式,还是执行完前两个自增表达式后相加,在不同的编译器中也会得到不同的结果。
像这样的例子还有很多,我们应该避免写出这样复杂且愚蠢的代码,否则就是害人害己。
点击跳转主页—> 💥个人主页:小羊在奋斗