The C Programming Language 第二章类型、运算符与表达式 读书笔记

来源:互联网 发布:linux修改系统时间指令 编辑:程序博客网 时间:2024/06/08 08:41

变量和常量是程序处理的两种基本数据对象。

声明语句说明变量的名字及类型,也可以指定变量的初值。

运算符指定将要进行的操作。

表达式把变量与常量组合起来生成新的值。

对象的类型决定该对象可取值的集合以及可以对该对象进行的操作。

所有整型包括signed和unsigned两种形式,且可以表示无符号常量与十六进制字符常量。

浮点预算可以以单精度进行,可以使用更高精读的long double类型运算。

字符串常量可以在编译时连接。

对象可以声明const类型,表示其值不能修改。


2.1变量名

名字是由字母和数字组成的序列,但其第一个字符必须为字母。

下划线‘_'被看做是字母,通常用于命名较长的变量名,提高其可读性。

由于库例程的名字通常以下划线开头,因此变量名不要以下划线开头。

大写字母与小写字母是有区别的。

在传统C语言用法中,变量名使用小写字母,符号常量名全部使用大写字母。

类似于if、else、int等关键字是保留给语言本身使用的,不能把它们用做变量名,关键字中的字符必须小写。

局部变量一般使用较短的变量名(尤其循环控制变量),外部变量使用较长的名字。


2.2数据类型及长度

char 字符型,占用一个字节,可以存放本地字符集中的一个字符

int 整型,通常反映了所用机器中整数的最自然长度

float 单精度浮点型

double 双精度浮点型

short,long两个限定符用于限定整型:short int sh;  long int counter;   在上述类型声明中关键字int可以省略。

类型限定符signed与unsigned用于限定char类型或任何整型。

long double表示高精度的浮点数。


2.3常量

类似于1234的整数常量属于int类型。

long类型的常量以字母l或L结尾,如123456789L,一个整数太大无法用int类型表示时也被当做long类型处理。

无符号常量以字母u或U结尾。

后缀为ul或UL表明是unsigned long类型。

浮点数常量中包含一个小数点(如123.4)或一个指数(如1e-2),或两者都有。

没有后缀的浮点数常量为double类型。

后缀f或F表示float类型,后缀l或L表示long double类型。

带前缀0的整型常量表示它为八进制形式;前缀为0x或0X表示它为16进制形式。

一个字符常量是一个整数,书写时将一个字符括在单引号中,如'x'。

字符在机器字符集中的数值就是字符常量的值。在ASCII字符集中,’0‘值为48,与数值0没有关系,用’0‘代表48增强程序的易读性。

某些字符可以通过转义字符序列表示为字符和字符串常量。

转义字符序列只表示一个字符。

我们可以用’\ooo'表示任意的字节大小的位模式,其实ooo代表1~3个八进制数字。

这种位模式还可以用‘\xhh’表示,其中hh是一个或多个十六进制数字。

字符常量‘\0'表示值为0的字符,也就是空字符。

常量表达式是只包含常量的表达式,在编译时求值而不在运行时求值。

字符串常量也叫字符串字面值,是用双引号括起来的0个或多个字符组成的字符序列。

双引号不是字符串的一部分,它只用于限定字符串。

编译时可以将多个字符串常量连接起来,例如,"hello,""world"等价于“hello,world"。

字符串的内部表示使用一个空字符‘\0'作串的结尾,存储字符串的物理存储单元数比括在双引号中的字符数多一个。

标准库函数strlen(s)可以返回字符串参数s的长度,但长度不包括末尾的'\0'。

’x'与"x"是不同的,前者是一个整数,其值是字母x在机器字符集中对应的数值,后者是一个包含一个字符以及一个结束符‘\0’的字符数组。

枚举常量是另外一种类型的常量。枚举是一个常量整型值的列表,例如enum boolean{NO,YES};

没有显示说明的情况下,enum类型中第一个枚举名的值为0,第二个为1。如果只指定了部分枚举名的值,那么未指定值的枚举名的值将依着最后一个指定值向后递增。

不同枚举中的名字必须互不相同。同一枚举中不同的名字可以具有相同的值。

相对于#define语句,枚举的优势在于常量值自动生成,并检查存储的值是否为该枚举的有效值,所以枚举比#define更具优势。


2.4声明

所有变量必须先声明后使用,某些变量可以通过上下文隐式声明。一个声明指定一种变量类型,后面所带的变量表可以包含一个或多个该类型的变量。

一个声明语句中的多个变量可以拆开在多个声明语句中声明。这样需要占用较多的空间,但便于向各声明语句中添加注释,也便于以后修改。

还可以在声明的同时对变量进行初始化。在声明中,如果变量名的后面紧跟一个等号以及一个表达式,该表达式就充当对变量进行初始化的初始化表达式。

如果变量不是自动变量(局部变量),则只能进行一次初始化操作,应该在程序开始执行之前进行,并且初始化表达式必须为常量表达式。

每次进入函数或程序块,显式初始化的自动变量都将被初始化一次,其初始化表达式可以是任何表达式。

默认情况下,外部变量与静态变量将被初始化为0。未经显式初始化的自动变量的值为未定义值(即无效值)。

任何变量的声明都可以用const限定符限定。该限定符指定变量的值不能被修改。对数组而言,const限定符指定数组所有元素的值都不能被修改。

const限定符也可配合数组参数使用,表明函数不能修改数组元素的值。


2.5算术运算符

二元算术运算符包括:+、-、*、/、%。

整数除法会截断结果中的小数部分。

取模运算符%不能应用于float或double类型。

有负操作数的情况下,整数除法截取方向以及取模运算结果的符号取决于具体机器的实现。

二元运算符+和-具有相同的优先级,优先级比*和/和%低,而*、/、%的优先级又比一元运算符+和-优先级低。

算术运算符采用从左到右的结合规则。


2.6关系运算符与逻辑运算符

关系运算符:>、>=、<、<=,具有相同的优先级。优先级仅次于它们的是相等性运算符:==、!=。

关系运算符的优先级比算术运算符低。

逻辑运算符&&,||,由&&或||连接的表达式按从左到右的顺序进行求值,在知道结果值为真或假后立即停止计算。

运算符&&的优先级比||高,但两者都比关系运算符和相等性运算符的优先级低。

在关系表达式或逻辑表达式中,如果关系为真,表达式结果值为数值1,如果为假,结果值为0。

逻辑非运算符!的作用是将非0操作数转换为0,将操作数0转换为1。

一般采用if(!valid)的形式而不是if(valid==0),类似于!valid的用法读起来更直观。


2.7类型转换

自动转换是指把”比较窄的“操作数转换为"比较宽的”操作数,并且不丢失信息的转换。

针对可能导致信息丢失的表达式,编译器可能会给出警告信息,但这些表达式并不非法。

将字符类型转换为整型时,因为C语言没有指定char类型的变量是无符号变量还是带符号变量,所以当一个char类型的值转换为int类型的值时,其结果是否为负整数取决于机器。

C语言中很多情况下会进行隐式的算术类型转换,如果二元运算符的两个操作数具有不同的类型,那么在进行运算前会把“较低”的类型提升为“较高”的类型。运算结果为较高的类型。

表达式中float类型的操作数不会自动转换为double类型。使用float类型主要是为了使用较大数组时节省存储空间,有时也为节省机器执行时间。

赋值时也要进行类型转换。赋值运算符右边的值需要转换为左边变量的类型,左边变量的类型即赋值表达式结果的类型。

字符型变量都将被转换为整型变量。

当把较长的整数转换为较短的整数或char类型时,超出的高位部分将被丢弃。

函数调用的参数是表达式,在把参数传递给函数时也可能进行类型转换。

在任何表达式中可以使用强制类型转换的一元运算符强制进行显示转换。(类型名)表达式


2.8自增运算符与自减运算符

自增运算符++使其操作数递增1,自减运算符--使其操作数递减1。

前缀运算符如++n,先将n递增1,再使用变量n的值,而后缀运算符如n++,则是先使用变量n的值,再将n的值递增1。

自增与自减运算符只能作用于变量,类似于表达式(i+j)++是非法的。


2.9按位运算符

C语言提供了6个按位操作运算符,只能作用于整形操作数,&,|,^,<<,>>,~。

按位与运算符&经常用于屏蔽某些二进制位。

按位或运算符|常用于将某些二进制位置为1。

按位异或运算符^当两个操作数的对应位不相同时将该位设置为1,否则设置为0。

移位运算符<<和>>分别用于将运算的左操作数左移与右移,移动的位数则由右操作数指定(右操作数的值必须是非负值),表达式x<<2将x的值左移2位,右边空出的两位用0填补,该表达式等价于对左操作数乘以4。对unsigned类型的无符号值进行右移位时,左边空出的部分用0填补。对signed类型的带符号值进行右移时,某些机器将对左边空出的部分用符号位填补(即算术移位),另一些机器则对左边空出的部分用0填补(即逻辑移位)。

一元运算符~用于求整数的二进制反码,即分别将操作数各二进制位上的1变为0,0变为1。


2.10赋值运算符与表达式

+=称为赋值运算符,大多数二元运算符都有一个相应的赋值运算符。

赋值运算符简洁,表示方式与人们的思维习惯比较接近,使程序代码更易于理解,有助于编译器产生高效代码。

赋值表达式的类型时它左操作数的类型,其值是赋值操作完成后的值。


2.11条件表达式

条件表示式 expr1 ? expr2 : expr3 首先计算expr1,其值为真,则计算expr2,并以该值作为条件表达式的值,否则计算expr3的值,并以该值作为条件表达式的值。expr2与expr3只能有一个表达式被计算。如果expr2和expr3的类型不同,结果的类型将由本章前面讨论的转换规则决定,如f为float类型,n为int类型,则表达式(n>0)? f:n是float类型,与n是否为正值无关。

条件运算符的优先级非常低,仅高于赋值运算符,但我们还是建议使用圆括号,使表达式的条件部分更易于阅读。

采用条件表达式可以编写出简洁的代码,比等价的if-else结构要紧凑一些。


2.12运算符优先级与求值次序

C语言没有指定同一运算符中多个操作数的计算顺序,例如x=f()+g(),f()可以在g()之前计算,也可以在g()之后计算。

C语言没有指定函数各参数的求值顺序。

函数调用、嵌套赋值语句、自增与自减运算符都可能在对表达式求值的同时修改了某些变量的值。

代码的执行结果与求值顺序相关是不好的程序设计风格,最好不要尝试运用特殊的实现方式。


感想

这本K&R的The C Programming Language真不愧C语言中的圣经,讲解十分简洁清爽毫不繁琐但又没有遗漏,不经意间就向我们介绍了标准库中一些函数的类似实现,如strlen函数、atoi函数、lower函数、rand函数、srand函数等等,让我了解了类似功能的实现并从中了解了相关知识,课后的习题也非常有趣,对我这个接触C快一年的大一学生来讲做起来还是有一些难度,但仔细思索花一些时间还是可以完成的。让我对C语言的一些基本知识比如位操作等了解得更深刻。

0 0
原创粉丝点击