




已阅读5页,还剩105页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第3章 数据类型、运算符与表达式,3.1 C的数据类型 3.2 常量与变量 3.3 整型数据 3.4 实型数据 3.5 字符型数据 3.6 变量赋初值,3.7 各类数值型数据间的混合运算 3.8 算术运算符和算术表达式 3.9 赋值运算符和赋值表达式 3.10 逗号运算符和逗号表达式,3.1 C的数据类型,数据结构+算法=程序 其中, (1)对操作的描述。即操作步骤,也就是算法(algorithm)。 (2)对数据的描述。在程序中要指定数据的类型和数据的组织形式,即数据结构(data structure)。 处理同一类问题,如果数据结构不同,算法也会不同。因此,在考虑算法时,必须注意数据结构。,C语言的数据结构是以数据类型形式出现的。 C的数据类型如下:,由以上这些数据类型还可以构成更复杂的数据结构。 例如利用指针和结构体类型可以构成表、树、栈等复杂的数据结构。,3.2 常量与变量,3.2.1 常量和符号常量 常量: 在程序运行过程中,其值不能被改变的量。 常量区分为不同的类型,如12,0,-3为整型常量,4.6、-1.23为实型常量,a,d为字符常量。 常量一般从其字面形式即可判别,这种常量称为字面常量或直接常量。,用一个标识符代表一个常量,称为符号常量。 例3.1符号常量的使用。 #define PRICE 30 #include main ( ) int num, total; num=10; total=num * PRICE ; printf(“total=%d“,total); 本文件中出现的PRICE都代表30,可以像常量 一样进行运算.,请注意符号常量不同于变量,它的值在其作用域(在本例中为主函数)内不能改变,也不能再被赋值。如再用以下赋值语句给PRICE赋值是错误的。 PRICE =40; 习惯上,符号常量名用大写,变量用小写,以示区别。 使用符号常量的好处是: (1) 含义清楚。如上面的程序中,看程序时从PRICE就可知道它代表价格。因此定义符号常量名时应考虑“见名知意”。 (2) 在需要改变一个常量时能做到“一改全改”。,3.2.2 变量 变量:其值在程序运行期间可以改变的量。 一个变量应该有一个名字,在内存中占据一定的存储单元。在该存储单元中存放变量的值。 请注意区分变量名和变量值这两个不同的概念,见图3.1。 变量名实际上是一个符号地址,在对程序编译连接时由系统给每一个变量名分配一个内存地址。 在程序中从变量中取值,实际上是通过变量名找到相应的内存地址,从其存储单元中读取数据。,图3.1,用来标识变量名、符号常量名、函数名、数组名、类型名、文件名的有效字符序列称为标识符(identifier)。 C语言规定标识符只能由字母、数字和下划线三种字符组成,且第一个字符必须为字母或下划线。 下面列出的哪些是合法的标识符,哪些不是合法的变量名: sum,average, _total, day, student_name,lotus_1_2_3, (li-ling,M.d.John,33,3d64,ab是错误的),注意,大写字母和小写字母被认为是两个不同的字符,即“大小写敏感”。因此,sum和SUM是两个不同的变量名。 ANSI C标准没有规定标识符的长度,但各个c编译系统都有自己的规定。 有的系统取8个字符,假如程序中出现的变量名长度大于8个字符,则只有前面8个字符有效,后面的不被识别。例如,有两个变量:student_name和student_number,由于二者的前8个字符相同,系统认为这两个变量是一回事而不加区别。可以将它们改为stud_name和stud_num,以使之区别。,为了程序的可移植性(即在甲机器上运行的程序可以基本上不加修改,就能移到乙机器上运行)以及阅读程序的方便,建议变量名的长度不要超过8个字符。 在选择变量名和其他标识符时,应注意做到“见名知意”,如count、name、day、month、total、country等;,共性规则,标识符最好采用英文单词 或其组合,便于记忆和阅读。切忌使用汉语拼音来命名。 程序中的英文单词用词应当准确。例如不要把CurrentValue写成NowValue。 几十年前老ANSI C规定名字不准超过6个字符,现今的C+/C不再有此限制。一般来说,长名字能更好地表达含义,所以函数名、变量名、类名长达十几个字符不足为怪。 那么名字是否越长越好?不见得! 单字符的名字也是有用的,常见的如i,j,k,m,n,x,y,z等,它们通常可用作函数内的局部变量。,命名规则尽量与所采用的操作系统或开发工具的风格保持一致。 例如Windows应用程序的标识符(主要是函数名)通常采用“大小写”混排的方式,如AddChild。 而Unix应用程序的标识符通常采用“小写加下划线”的方式,如add_child。别把这两类风格混在一起用。 程序中不要出现仅靠大小写区分的相似的标识符。例如: int x, X; / 变量x 与 X 容易混淆 void foo(int x); / 函数foo 与FOO容易混淆 void FOO(float x);,在c语言中,所有变量“先定义,后使用” ,因为: (1) 凡未被事先定义的,不作为变量名,这就能保证程序中变量名使用得正确。例如,如果在定义部分写了 int student; 而在执行语句中错写成stadent。如: stadent=30; 在编译时检查出statent未经定义,不作为变量名。因此输出“变量statent未经声明”的信息。,(2) 每一个变量被指定为一确定类型,在编译时就能为其分配相应的存储单元。如指定a、b为int型,turbo c编译系统为a和b各分配两个字节,并按整数方式存储数据。 (3) 指定每一变量属于一个类型,这就便于在编译时,据此检查该变量所进行的运算是否合法。例如,整型变量a和b,可以进行求余运算:a%b 但如果将a、b指定为实型变量,则不允许进行“求余”运算,在编译时会给出有关“出错信息”。,3.3 整型数据,3.3.1 整型常量的表示方法 整型常量即整常数。C整常数可用以下三种形式表示: (1) 十进制整数。如123, -456, 0。 (2) 八进制整数。以0开头的数是八进制数。如0123表示八进制数123,即(123)8。-011表示八进制数-11,即十进制数-9。 (3) 十六进制整数。以0x开头的数是十六进制数。如0x123,代表十六进制数123。-0x12等于十进制数-18。,3.3.2 整型变量,1. 整型数据在内存中是以二进制形式存放的。 如: int i; /* 定义为整型变量 */ i=10; /* 给i赋以整数10 */ 十进制数10的二进制形式为1010 TC系统为每一个整型变量在内存中分配2个字节,而VC6.0分配4个字节。,图3.2(a)是数据存放的示意图。图3.2(b)是数据在内存中实际存放的情况。 实际上,数值是以补码(complement) 表示的。 一个正数的补码和其原码的形式相同。如图3.2(b) 。 求负数的补码的方法是:将该数的绝对值的二进制形式,按位取反再加1。 例如求-10的补码: 取-10的绝对值10; 10的绝对值的二进制形式为1010; 对1010取反得1111111111110101(一个整数占16位); 再加1得1111111111110110,见图3.3。,图3.3 可知整数的16位中,最左面的一位是符号位,该位为0,表示数值为正;为1则数值为负。,2. 整型变量的分类,整型变量的基本类型符为int。 根据数值的范围在int 之前可以根据需要分别加上修饰符:short(短型)或long(长型)。从而分为以下三种整型变量: (1) 基本整型,以int表示。 (2) 短整型,以short int表示,或以short表示。 (3) 长整型,以long int表示,或以long表示。,在turbo c中一个int型的变量的值范围为-215(215-1) ,即-3276832767。 在实际应用中,变量的值常常是正的(如学号、库存量、年龄、存款额等)。为了充分利用变量的表数范围,此时可以将变量定义为“无符号”类型。 对以上三种都可以加上修饰符unsigned,以指定是“无符号数” 。 如果加上修饰符signed,则指定是“有符号数”。 如果既不指定为signed,也不指定为unsigned,则隐含为有符号(signed)。实际上signed一般不写。,归纳起来,可以用以下6种整型变量。即: 有符号基本整型 signed int 无符号基本整型 unsigned int 有符号短整型 signed short int 无符号短整型 unsigned short int 有符号长整型 signed long int 无符号长整型 unsigned long int 方括弧内的部分是可以省略的. 如果指定unsigned,为无符号型,存储单元中全部二进位(bit)用作存放数本身,而不包括符号。无符号型变量只能存放不带符号的整数,如123、4687等,而不能存放负数,如-123、-3。,一个无符号整型变量中可以存放的正数的范围比一般整型变量中正数的范围扩大一倍。 如果在程序中定义a和b两个变量: int a; unsigned int b; 则变量a的数值范围为-3276832767。而变量b的数值范围为065535。,表示有符号整型变量a的最大值(32767)。 (b) 表示无符号整型变量b的最大值(65535)。,C标准没有具体规定以上各类数据所占内存字节数,只要求long型数据长度不短于int型,short型不长于int型。 具体如何实现,由各计算机系统的字长决定: long在16和32位操作系统中都是32位。 short在16和32位操作系统中都是16位。 16位操作系统(DOS, Windows 3.x)int是16位的. 32位操作系统(Windows 9x/NT/2000/XP)int是32位的(范围达21亿).,一个整数(以13为例)在存储单元中的存储情况,见图3.5所示。,图3.5,/求某数据类型能表示的最大数 #include void main() int i; double max=1; for(i=sizeof(int)*8; i0;i-) max *=2; max-; printf(“%fn“,max); ,3. 整型变量的定义,前面已提到,c规定在程序中所有用到的变量都必须在程序中“先定义,后使用” ,即“强制类型定义”。例如: int a,b;(指定变量a、b为整型) unsigned short c,d;(指定变量c、d为无符号短整型) long e,f; (指定变量e、f为长整型) 对变量的定义,一般是放在一个函数的开头部分的声明部分。,例3.2整型变量的定义与使用。,void main() int a,b,c,d; /定义a、b、c、d为整型变量 unsigned u; /定义u为无符号整型变量 a=12;b=-24;u=10; c=a+u;d=b+u; printf(“a+u=%d,b+u=%dn“,c,d); 运行结果为: a+u=22,b+u=-14 可以看到不同种类的整型数据可以进行算术运算。,4. 整型数据的溢出,假如,在VC中一个int型变量的最大允许值为2147483647 (0x7fffffff),如果再加1,会出现什么情况? 例3.3整型数据的溢出。 void main() int a=2147483647, b; b=a+1; printf(“%d,%dn“,a,b); 运行结果为: 2147483647,- 2147483648,请注意:遇此情况就发生“溢出”, 但运行时并不报错。 将变量b改成范围更大的数据类型。,图3.6,3.3.3 整型常量的类型,我们已知整型变量可分为int、short int、long int和unsigned int、unsigned short、unsigned long等类别。那么常量是否也有这些类别?在将一个整型常量赋值给上述几种类别的整型变量时如何做到类型匹配?请注意以下几点: (1) 一个整数,如果其值在-2147483648+2147483647范围内,认为它是int型,它可以赋值给int型和long int型变量。,(2) 一个int型的常量也同时是一个long int型常量,可以赋给int型或long int型变量。 (3) 一个整常量后面加一个字母u,认为是unsigned int型,如12345u,在内存中按unsigned int规定的方式存放(存储单元中最高位不作为符号位,而用来存储数据。 (4) 在一个整常量后面加一个字母l或L,则认为是long int型常量。例如123l、432L、0L等,这往往用于函数调用中。如果函数的形参为long int型,则要求实参也为long int型。,3.4 实型数据,3.4.1 实型常量的表示方法 实数(real number)又称浮点数(floating-point number)。实数有两种表示形式: (1) 十进制小数形式。它由数字和小数点组成(注意必须有小数点)。0.123、 123.、 123.0、 0.0都是十进制小数形式。 (2) 指数形式。如123e3或123E3都代表123103。但注意字母e(或E)之前必须有数字,且e后面的指数必须为整数,如e3、2.1e3.5、e3、 e等都不是合法的指数形式。,1. 实型数据在内存中的存放形式 在常用的微机系统中,一个实型数据在内存中占4个字节(32位)。 与整型数据的图3.7存储方式不同,实型数据是按照指数形式存储的。系统把一个实型数据分成小数部分和指数部分,分别存放。指数部分采用规范化的指数形式。实数 3.14159 在内存中的存放形式可以用图3.7示意。,3.4.2 实型变量,图3.7,图中是用十进制数来示意的,实际上在计算机中是用二进制数来表示小数部分以及用2的幂次来表示指数部分的。 在4个字节(32位)中,究竟用多少位来表示小数部分,多少位来表示指数部分,标准C并无具体规定,由各C编译系统自定。 小数部分占的位(bit)数愈多,数的有效数字愈多,精度愈高。指数部分占的位数愈多,则能表示的数值范围愈大。,2. 实型变量的分类,C实型变量分为单精度(float型)、双精度(double型)和长双精度型(long double)三类。 ANSI C 并未具体规定每种类型数据的长度、精度和数值范围。 有的系统将double型(8字节)所增加的32位全用于存放小数部分,这样可以增加数值的有效位数,减少舍入误差。 有的系统则将所增加的位(bit)用于存放指数部分,这样可以扩大数值的范围。表3.2列出的是微机上常用的c编译系统(如turbo c, Ms c, borland c )的情况。应当了解,不同的系统会有差异。,对每一个实型变量都应在使用前加以定义。如: float x,y,(指定x、y为单精度实数) double z; (指定z为双精度实数) long double t; (指定t为长双精度实数,少用),3. 实型数据的舍入误差,由于实型变量是由有限的存储单元组成的,因此能提供的有效数字总是有限的,在有效位以外的数字将被舍去。由此可能会产生一些误差。例如,(a20) 应该比a大? 例3.4 实型数据的舍入误差。,void main() float a,b; a = 123456.789e5; b = a + 20 ; printf(“%f“,b); “%f” 是输出一个实数时的格式符。 程序运行时,输出b的值与a相等。原因是:a的值比20大很多,a+20的理论值应是12345678920,而一个实型变量只能保证的有效数字是7位有效数字,后面的数字是无意义的,并不准确地表示该数。,运行程序得到的a和b的值是12345678868.000000,可以看到,前7位是准确的,后几位是不准确的(随机),把20加在后几位上,是无意义的。 应当避免将一个很大的数和一个很小的数直接相加或相减,否则就会“丢失”小的数。与此类似,用程序计算1.0/3*3的结果可能不等于1。,3.4.3 实型常量的类型,C编译系统将实型常量作为双精度来处理。例如已定义一个实型变量f,有如下语句: f = 2.45678 * 4523.65 这样做可以保证计算结果更精确,但是运算速度降低了。可以在数的后面加字母f或F(如1.65f, 654.87F),这样编译系统就会按单精度(32位)处理。,一个实型常量可以赋给一个float型、double型或long double变量。赋值时根据变量的类型截取实型常量中相应的有效位数字。假如a已指定为单精度实型变量: float a; a=111111.111; 由于float型变量只能接收7位有效数字,因此最后两位小数可能不起作用。如果a改为double型,则能全部接收上述9位数字并存储在变量a中。,3.5 字符型数据,3.5.1 字符常量 C的字符常量是用单引号(即撇号)括起来的一个字符。如a,x,d,?,等都是字符常量。注意,a和A是不同的字符常量。 除了以上形式的字符常量外,C还允许用一种特殊形式的字符常量,就是以一个“”开头的转义字符。例如,n,它代表一个“换行”符。这是一种“控制字符”,在屏幕上是不能显示的。 常用转义字符,见P48 表33,例3.5转义字符的使用。 void main() printf(“ ab ct derftgn“); printf(“htibbj k“); 其中,“t”的作用是“跳格”,即跳到下一个“制表位置”,一个“制表区”占8列,“下一个制表位置”从第9列开始 。 “r”,它代表“回车”(不换行) “n”,作用是“使当前位置移到下一行的开头” “b”,作用是“退一格”,程序运行时在打印机上得到以下结果: fab c gde h jik 注意在显示屏上的结果: f gde h j k 结果不同的原因:“r”使当前位置回到本行开头,自此输出的字符(包括空格和跳格所经过的位置)将取代原来屏幕上该位置上显示的字符。而在打印机输出时,不像显示屏那样会“抹掉”原字符,留下了不可磨灭的痕迹,它能真正反映输出的过程和结果。,3.5.2 字符变量,字符型变量用来存放字符常量,请注意只能放一个字符。字符变量的定义形式如下: char c1,c2; c1=a; c2=b; 在所有的编译系统中都规定以一个字节来存放一个字符,或者说一个字符变量在内存中占一个字节。,3.5.3 字符数据在内存中的存储形式及其使用方法,将一个字符常量放到一个字符变量中,实际上并不是把该字符本身放到内存单元中去,而是将该字符的相应的ASCII代码放到存储单元中。例如字符a的ASCII代码为97,b为98,在内存中变量c1、c2的值如图3.8(a)所示。实际上是以二进制形式存放的,如图3.8(b)所示。,图3.8,既然在内存中,字符数据以ASCII码存储,它的存储形式就与整数的存储形式类似。这样,字符型数据和整型数据之间就可以互相转换。 一个字符数据既可以以字符形式(%c)输出,也可以以整数形式(%d)输出。 以字符形式输出时,需要先将存储单元中的ASCII码转换成相应字符,然后输出。 以整数形式输出时,直接将ASCII码作为整数输出。 也可以对字符数据进行算术运算,相当于对它们的ASCII码进行算术运算。,例3.6向字符变量赋以整数。,void main() char c1,c2; c1=97; c2=98; printf(“%c %cn“,c1,c2);/*以字符形式输出*/ printf(“%d %dn“,c1,c2);/*转换为整数形式输出*/ c1=97; c2=98; 作用相当于以下两个赋值语句: c1=a;c2=b;,c1=97; c2=98; 把97和98两个整数直接存放到c1和c2的内存单元中。 而c1=a和c2=b则是先将字符a和b化成ascii码97和98,然后放到内存单元中。 二者的作用和结果是相同的。,图3.9,程序运行时输出如下: a b 97 98 可以看到:字符型数据和整型数据是通用的。它们既可以用字符形式输出(用%c),也可以用整数形式输出(用%d),见图3.9。 但是应注意字符数据只占一个字节,它只能存放0255 范围内的整数。,例3.7大小写字母的转换。,void main() char c1,c2; c1=a; c2=b; c1=c1-32; c2=c2-32; printf(“%c %cn“,c1,c2); 运行结果为: A B 从ascii代码表中可以看到每一个小写字母比它相应的大写字母的ascii码大32。c语言允许字符数据与整数直接进行算术运算,即A+32会得到整数97,a-32会得到整数65。,字符数据与整型数据可以互相赋值。如: int i; char c; i=a; c=97; 是合法的。 如果在上面语句之后执行以下语句: printf(“%c,%dn“,c,c); printf(“%c,%dn“,i,i); 输出: a,97 a,97,说明:有些系统(如pdp,Vax-11,turbo c)将字符变量中的最高位作为符号位,也就是将字符处理成带符号的整数,即signed char型。它的取值范围是-128127。 如果使用ascii码为0127间的字符,由于字节中最高位为0,因此用%d输出时,输出一个正整数。 如果使用ascii码为128255间的字符,由于在字节中最高位为1,用%d格式符输出时,就会得到一个负整数。,例如: char c=130; printf(“%d”, c); 得到-126。 如果不想按有符号处理,可以将字符变量定义为unsigned char类型, 这时其取值范围是0255。,3.5.4 字符串常量,字符串常量是一对双引号括起来的字符序列。如: “how do you do.”, “CHINA“,“a“,”$123.45“ 都是字符串常量。可以输出一个字符串,如: printf(“how do you do.“); 不要将字符常量与字符串常量混淆。a是字符常量,“a”是字符串常量,二者不同。,假设c被指定为字符变量: char c; c=a; 是正确的。而c=“a“;是错误的。c=“CHINA“ 也是错误的。不能把一个字符串赋给一个字符变量。 原因:c规定:在每一个字符串的结尾加一个“字符串结束标志”,以便系统据此判断字符串是否结束。C规定以字符0作为字符串结束标志。 0是一个ASCII码为0的字符,从ascii代码表中可以看到ascii码为0的字符是“空操作字符”,即它不引起任何控制动作,也不是一个可显示的字符。,如果字符串“CHINA”,实际上在内存中是: C H I N A 0 它的长度不是5个字符,而是6个字符,最后一个字符为0。 字符串“a”,实际上包含2个字符:a和0,因此,把它赋给只能容纳一个字符的字符变量c,即 c=“a“;显然是不行的。 但在输出时不输出0。例如在printf(“how do you do.”)中,输出时一个一个字符输出,直到遇到最后的0字符,就知道字符串结束,停止输出。,注意,在写字符串时不必加0 ,0字符是系统自动加上的。 在c语言中没有专门的字符串变量,如果想将一个字符串存放在变量中,以便保存,必须使用字符数组,即用一个字符型数组来存放一个字符串,数组中每一个元素存放一个字符。这将在第6章中介绍。,3.6 变量赋初值,C语言允许在定义变量的同时使变量初始化。如: int a=3; /* 指定a为整型变量,初值为3 */ float f=3.56;/* 指定f为实型变量,初值为3.56 */ char c=a; /* 指定c为字符变量,初值为a */ 也可以使被定义的变量的一部分赋初值。如: int a,b,c=5; 只对c初始化,c的值为5。,如果对几个变量赋予初值3,应写成 int a=3, b=3, c=3; 不能写成: int a=b=c=3; 变量的初始化不是在编译阶段完成的(只有在第7章中介绍的静态存储变量和外部变量的初始化是在编译阶段完成的),而是在程序运行时执行本函数时赋予初值的。,例如,int a=3; 相当于: int a; /*指定a为整型变量 */ a=3; /*赋值语句,将3赋给a ,运行时*/ 又如 int a,b,c=5; 相当于: int a,b,c; /*指定a、b、c为整型变量*/ c=5; /*将5赋给c ,运行时*/,3.7 各类数值型数据间的混合运算,整型、实型、字符型数据间可以混合运算。例如: 10+a-8765.1234 是合法的。 C规定:在进行运算时,不同类型的数据要先转换成同一类型,然后进行运算。 那么,到底转换为哪一数据类型? 对于不同类型的数据进行混合运算一般按占用字节数较多的类型进行计算,结果的类型也是该字节数较多的类型。,具体转换规则见右图3.10 横向向左的箭头表示必定的转换 例如:float型 double型 先转化成double型,然后再相加。 纵向的箭头表示当运算对象为不同类型时转换的方向。,图3.10,例如: int型+double型 先将int型的数据转换成double型,然后在两个同类型(double型)数据间进行运算,结果为double型。,例:假设已指定i为整型变量,f为float变量,d为double型变量,e为long型,有下面式子: 10+a+i*f-d/e 在计算机执行时从左至右扫描,运算次序为: 进行10+a的运算,先将a转换成整数97,运算结果为107。 由于“*”比“+”优先,先进行i*f的运算。先将i与f都转成double型,运算结果为double型。 整数107与i*f的积相加。先将整数107转换成双精度数(小数点后加若干个0,即10700000),结果为double型。 将变量e化成double型,d/e结果为double型。 将10+a+i*f的结果与d/e的商相减,结果为double型。 上述的类型转换是由系统自动进行的。,3.8 算术运算符和算术表达式,3.8.1 C运算符简介 语言运算符范围很宽,除控制语句和输入输出语句之外几乎所有的基本操作都作为运算符处理。 C的运算符有以下几类: 1算术运算符 (+、-、*、/、%) 2关系运算符 (、=、=、=、!=) 3逻辑运算符 (!、&、|) 4位运算符 (、 、 |、&) 5赋值运算符 (=及其扩展赋值运算符) 6条件运算符 (?:),7逗号运算符 (,) 8指针运算符 (*和&) 9求字节数运算符 (s i z e o f) 10强制类型转换运算符 ( (类型) ) 11分量运算符 (-) 12下标运算符 ( ) 13其他 (如函数调用运算符() 本章只介绍算术运算符、赋值运算符和逗号运算符,在以后各章中结合有关内容将陆续介绍其他运算符。,3.8.2 算术运算符和算术表达式,1. 基本的算术运算符 +(加法运算符,或正值运算符。如3+5、+3) -(减法运算符,或负值运算符。如5-2、-3) *(乘法运算符。如3*5) /(除法运算符。如5/3) %(模运算符,或称求余运算符,%两侧均应为整型数据,如7%4的值为3)。 需要说明,两个整数相除的结果为整数,如5/3的结果值为1,舍去小数部分。,但是,如果除数或被除数中有一个为负值,则舍入的方向是不固定的。 例如,-5/3在有的机器上得到结果-1,有的机器则给出结果-2。 多数机器采取“向零取整”的方法,即5/3=1,-5/3=-1,取整后向零靠拢。VC即采取此方法。,2. 算术表达式和运算符的优先级与结合性,用算术运算符和括号将运算对象(也称操作数)连接起来的、符合C语法规则的式子,称C算术表达式。 运算对象包括常量、变量、函数等。例如,下面是一个合法的C算术表达式: a*b/c-1.5+a,C语言规定了运算符的优先级。 在表达式求值时,先按运算符的优先级别高低次序执行。 例如先乘除后加减,如表达式a-b*c。 b的左侧为减号,右侧为乘号,而乘号优先于减号,因此,相当于a-(b*c)。 如果在一个运算对象两侧的运算符的优先级别相同,如a-b+c,则按规定的“结合方向”处理。,C规定了各种运算符的结合方向(结合性)。 算术运算符的结合方向为“自左至右”,即先左后右,因此b先与减号结合,执行a-b的运算,再执行加c的运算。“自左至右的结合方向”又称“左结合性”,即运算对象先与左面的运算符结合。 有些运算符的结合方向为“自右至左”,即右结合性(例如,赋值运算符)。,【规则】如果代码行中的运算符比较多,用括号确定表达式的操作顺序,避免使用默认的优先级。 由于将上页表熟记是比较困难的,为了防止产生歧义并提高可读性,应当用括号确定表达式的操作顺序。例如: if (a | b) & (a & c),3. 强制类型转换运算符,可以利用强制类型转换运算符将一个表达式转换成所需类型。例如: (double)a (将a转换成double类型) (int)(x+y) (将x+y的值转换成整型) (float)(5%3) (将5%3的值转换成float型) 其一般形式为(类型名)(表达式) 注意,表达式应该用括号括起来。如果写成 (int)x+y 则只将x转换成整型,然后与y相加。,需要说明的是在强制类型转换时,得到一个所需类型的中间变量,原来变量的类型未发生变化。 例如:(int)x (不要写成int(x) 如果x原指定为float型,进行强制类型运算后得到一个int型的中间变量,它的值等于x的整数部分,而x的类型不变(仍为float型)。见下例。,例3.8 强制类型转换,void main() float x; int i; x=3.6; i=(int)x; printf(“x=%f, i=%dn“,x,i); 运行结果如下: x=3.600000 , i=3 x类型仍为float型,值仍等于3.6。,从上可知,有两种类型转换: 一种是在运算时不必用户指定,系统自动进行的类型转换,如3+6.5; 第二种是强制类型转换。 当自动类型转换不能实现目的时,可以用强制类型转换。如“%”运算符要求其两侧均为整型量,若x为float型,则“x%3”不合法,必须用:“(int)x % 3”。强制类型转换运算优先于%运算,因此先进行(int)x的运算,得到一个整型的中间变量,然后再对3求模。 此外,在函数调用时,有时为了使实参与形参类型一致,可以用强制类型转换运算符得到一个所需类型的参数。,4. 自增、自减运算符,作用是使变量的值增1或减1,如: +i,-i (在使用i之前,先使i的值加(减)1) i+,i- (在使用i之后,使i的值加(减)1) 如果i的原值等于3,则执行下面的赋值语句: j=+i; i的值先变成4, 再赋给j ,j的值为4 j=i+; 先将 i的值3赋给j , j的值为3,然后i变为4,又如:i=3; printf(“%d“,+i); 输出“4”。若改为 printf(“%d“,i+); 则输出“3”。 注意: (1) 自增运算符(+)和自减运算符(-),只能用于变量,而不能用于常量或表达式,如5+或(a+b)+都是不合法的。 (a+b)+不可能实现,假如a+b的值为5,那么自增后得到的6放在什么地方呢?无变量可供存放。,(2) +和-的结合方向是“自右至左”。 如果有-i+。负号运算符和“+”运算符同优先级,而结合方向为“自右至左”(右结合性),即它相当于-(i+)。 如果i的原值等于3, 且有printf(“%d”,-i+),则先取出i的值3,输出-i的值-3,然后i增值为4。 自增(减)运算符常用于循环语句中,使循环变量自动加1,也用于指针变量,使指针指向下一个地址。这些将在以后的章节中介绍。,5. 有关表达式使用中的问题说明,注意:ANSI C并没有具体规定表达式中的子表达式的求值顺序。允许各编译系统自己安排。例如,对表达式a = f1( )+f2( )并不是所有的编译系统都先调用f1( ), 然后调用f2( )。在一般情况下,先调用f1( ) 和先调用f2( ) 的结果可能是相同的。但是在有的情况下结果可能不同。有时会出现一些令人容易搞混的问题,因此务必要小心谨慎。,如果有以下表达式: (i+)+(i+)+(i+) 设i的原值为3,那么,表达式的值是多少呢? 有的系统按照自左而右顺序求解括弧内的运算,求完笫1个括弧再求第2个括弧, 结果为3+4+5,即12。 而另一些系统(如turbo c和ms c)设i的原值为3,那么作为表达式中所有i的值, 因此3个i相加,得9。然后再实现自加3次,i的值变为6。,应该避免出现这种歧义性。如果编程者的原意是想得到12, 可以写成下列语句: i = 3; a = i+; b = i+; c = i+; d = a + b + c; 执行完上述语句后,d的值为12,i的值为6。 虽然语句多了,但不会引起歧义,无论程序移植到哪一种c编译系统运行,结果都一样。,(2) 如i+j,是理解为(i+)+j呢?还是i+(+j)呢?C编译系统在处理时尽可能多地(自左而右)将若干个字符组成一个运算符(在处理标识符、关键字时也按同一原则处理),如i+j,将解释为(i+)+j,而不是i+(+j)。 为避免误解,最好采取大家都能理解的写法,不要写成i+j的形式,而应写成(i+)+j的形式。,(3) C语言中类似上述这样的问题。例如,在调用函数时,实参数的求值顺序,C标准并无统一规定。如i的初值为3,如果有下面的函数调用: printf(“%d,%d“,i,i+) 在有的系统中,从左至右求值,输出“3,3”。 在多数系统中对函数参数的求值顺序是自右而左,先求出第2个表达式i+的值3(i未自加时的值),然后求第1个表达式的值,由于在求解第2个表达式后,执行i+, 使i加1变为4,因此printf函数中第一个参数i的值为4。所以上面printf函数输出的是“4,3”。 以上这种写法不宜提倡, 最好改写成 j = i+; printf(“%d, %d”, j,i); 总之,不要写出别人看不懂的、也不知道系统会怎样执行的程序。 使用+和-时, 常会出现一些人们“想不到”的副作用,初学者要慎用。,3.9 赋值运算符和赋值表达式,1. 赋值运算符 赋值运算符就是“=” ,它的作用是将一个数据赋给一个变量。如“a=3”, 把常量3赋给变量a。 也可以将一个表达式的值赋给一个变量。 2. 类型转换 如果赋值运算符两侧的类型不一致,但都是数值型或字符型时,在赋值时要进行类型转换。,(1) 实型数据(包括单、双精度)整型变量: 舍弃实数的小数部分。如i为整型变量,执行“i=3.56”的结果是使i的值为3, 在内存中以整数形式存储。 (2) 整型数据单、双精度变量: 数值不变,但以浮点数形式存储到变量中,如将23赋给float变量f,即f=23,先将23转换成2300000,再存储在f中。如将23赋给double型变量d,即d=23,则将23补足有效位数字为2300000000000000,然后以双精度浮点数形式存储到d中。,(3) double数据-float变量: 截取其前面7位有效数字,存放到float变量的存储单元(32位)中。但应注意数值范围不能溢出。如: float f; double d=123.456789e100; f=d; 就出现溢出的错误。 float数据double变量: 数值不变,有效位数扩展到16位,在内存中以64位(bit)存储。,(4) 字符型数据整型变量: 由于字符只占1个字节,而整型变量为2个字节,因此将字符数据(8位)放到整型变量低8位中。有两种情况:,如图3.11, 如果所用系统将字符处理为无符号的量或对unsigned char型变量赋值,则将字符的8位放到整型变量低8位,高8位补零。例如:将字符376赋给int型变量i,如图3.11(a)所示。, 如果所用系统(如turbo c)将字符处理为带符号的(即signed char),若字符最高位为0,则整型变量高8位补0;若字符最高位为1,则高8位全补1(图3.11(b)。这称为“符号扩展”,这样做的目的是使数值保持不变,如变量c(字符376)以整数形式输出为-2,i的值也是-2。 (5) int、short、long型数据char型变量时: 只将其低8位原封不动地送到char型变量(即截断)。,例如: int i=289; char c=a; c=i; 赋值情况见图3.12。c的值为33, 如果用“%c”输出c,将得到字符“!” (其ascii码为33).,图3.12,(6) 带符号的短整型数据(short int型)long型变量: 要进行符号扩展,将16位送到long型低16位中,如果short int型数据为正值(符号位为0),则long型变量的高16位补0;如果short int型变量为负值(符号位为1),则long型变量的高16位补1,以保持数值不改变。 反之,若将一个long型数据赋给一个short int型变量,只将long型数据中低16位原封不动地送到short int变量(即截断)。,图3.14,例如: short a;long b=8; a=b;赋值情况见图3.13。 如果b=65536(八进制数0200000),则赋值后a值为0。见图3.14。,图3.13,(7) 将unsigned short int型数据赋给long int型变量时,不存在符号扩展问题,只需将高位补0即可。 将一个unsigned类型数据赋给一个占字节数相同的整型变量(例如:unsigned int=int,unsigned long=long,unsigned short=short),将unsigned型变量的内容原样送到非unsigned型变量中,但如果数据范围超过相应整型的范围,则会出现数据错误。,如: unsigned short int a=65535; short int b; b=a; 将a整个送到b中(图3.15),由于b是short int型,第1位是符号位,成了负数。b的值为-1,可以用printf(“%d”,b);来验证。 (8) 将signed型数据赋给长度相同的unsigned型变量,也是原样照赋(连原有的符号位也作为数值一起传送)。如:,例3.9 有符号数据传送给无符号变量。 void main() unsigned short a; short int b=-1; a=b; printf(“%u“,a); “%u” 是输出无符号数时所用的格式符。运行结果为:65535,图3.16,以上的赋值规则看起来比较复杂,其实
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 5年级下册英语书单词表点读
- 低空空中交通应用场景
- 登山 法治宣传活动
- 4年级观察日记三则怎么写
- 超声波塑料焊接 - 副本 - 副本
- 2025年贵阳幼儿师范高等专科学校单招职业技能测试题库带答案
- 2025年云南商务职业学院单招职业倾向性测试题库一套
- 2025年重庆市绵阳市单招职业倾向性测试题库及参考答案
- 2025年天津公安警官职业学院单招职业技能测试题库1套
- 2025年晋城职业技术学院单招职业技能测试题库学生专用
- GB/T 5778-1986膨胀合金气密性试验方法
- GB/T 5455-2014纺织品燃烧性能垂直方向损毁长度、阴燃和续燃时间的测定
- GB/T 5117-2012非合金钢及细晶粒钢焊条
- GB/T 3782-2006乙炔炭黑
- 大国医魂:800年滋阴派与600年大德昌课件
- 真核生物的转录
- 《电商企业财务风险管理-以苏宁易购为例开题报告》
- 公司组织架构图(可编辑模版)
- 中小学综合实践活动课程指导纲要
- 清淤工程施工记录表
- 黄河上游历史大洪水市公开课金奖市赛课一等奖课件
评论
0/150
提交评论