第5章 数据类型和表达式

更新时间:2024-06-07 07:42:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

第五章

数据类型和表达式

通过前面的学习,我们已经了解了C语言的基本内容,并且使用了一些数据类型编写一些简单的程序,实现对数据的处理。在用C语言编写程序时需要考虑:计算机能处理哪些数据?对这些数据能做哪些操作?通过怎样的操作步骤才能完成给定的工作?这3个问题分别对应数据表达、运算和流程控制。下面我们讨论前两个问题。

首先介绍C语言中可以使用的数据类型: 整型

基本数据类型 字符型 单精度 实型(浮点型) 双精度 数组 结构

数据类型 构造数据类型 联合 枚举

指针类型 空类型

C语言程序中所使用的每个数据都属于上述某一种类型,在编程时要正确定义和使用数据。其次,在C语言中,对数据的操作就是对数据进行运算,C语言提供了许多运算符,可以对不同类型的数据进行处理。这些运算符与数据组合后便形成了表达式。

5、1 基本数据类型

C语言的4种基本类型是:整型、字符型、单精度浮点型和双精度浮点型,见表5.1 表5. 1 基本数据类型

类 别 名 称 类型名 数据长度 取值范围 [有符号]整型 int 32位 略 [有符号]短整型 short [int] 16位 … [有符号]长整型 long[ int ] 32位 … 整 型 无符号整型 unsigned[int] 32位 …

无符号短整型 unsigned short[int] 16位 … 无符号长整型 unsigned long[int] 32位 … 字符型 字符型 char 8位 … 实 型 单精度浮点型 float 32位 … ( 浮点型 ) 双精度浮点型 double 64位 …

注 :方括号中的内容可以省略

1

1、整型

整型是指不存在小数部分的数据类型。见上表5.1的整型部分。

无符号的整型数据指不带符号的整型,即零或正整数,不包括负数。 2、字符型

每个字符型数据在内存中占用一个字节,用于存储它的ASCII码。所以C语言中的字符具有数值特征,不但可以写成字符常量的形式,还可以用相应的ASCII码表示,即可以用整数来表示字符。

例如:设 ch 是字符型变量,字符型常量 ? A ? 的ASCII码值是65,则ch = ? A ?和ch = 65等价。

既然字符变量的值可以是字符或整数,它就可以被定义成整型变量;同时整型变量的值也可以是字符型数据,它可以被定义成字符型变量。即整型变量和字符型变量的定义和值都可以互相交换。

互换整型变量和字符型变量的定义和值时,整型数据的取值范围是有效的ASCII码。 3、实型

实数类型又称为浮点型,指有小数部分的数。见上表5.1的实型部分。

单精度和双精度的区别在于数据的精度和取值范围有所不同。双精度(double)比单精度(float)的精度高,取值范围大。实型常量的类型都是双精度浮点型。

实数在计算机中只能近似表示,运算中也会产生误差。 4、数据存储

计算机处理的所有信息都以二进制形式表示(数值只能用0、1,以原码、反码、补码等方式表示)。表5.1中的数据长度32位是说32位二进制数(关于数在计算机里的表示,请参照

教材有关章节和有关书籍)。8位二进制数是一个字节,故32位二进制数是4个字节,16

位二进制是两个字节,64位二进制是8个字节。位数越多所表示的数字越大,数值越精确。

5.2 常量和变量

C语言中,数据有常量和变量之分。在程序运行过程中,其值不能改变的量称为常量;其值可以改变的量称为变量。 5.2.1 常量

常量的类型由书写格式决定。例如:-10、123L(长整型)、017(八进制)、0x1f(十六进制)是整型常量,-123.23、4.3e-3是实型常量,而?a?、?\\n?、?9?是字符型常量。 1、符号常量:可以用一个标识符来表示一个常量,称为符号常量。

例5.1 输入球的半径,计算球的表面积和体积 #include

#define PI 3.14 //定义符号常量 PI int main() {

double r,s,v;

printf(\//输入提示 scanf(\

2

}

s = 4.0*PI*r*r; //计算球的表面积 v = 4.0/3.0*PI*r*r*r; //计算球的体积 printf(\return 0;

运行结果:input r: 1.0

s = 12.56000, v = 4.186667

用 #define 命令定义符号常量PI,它代表3.14。定义后,凡在该程序中出现PI的地方,PI都代表3.14,这样符号常量PI就可以和实型常量3.14一样进行运算。

#define 命令的末尾不加分号。

定义符号常量后,就可以引用它,但不能改变它的值。 使用符号常量有助于提高程序的可读性,而且修改方便,便于移植。例如:上面的程序中多处用到PI,开始取3.14,以后为了提高计算精度,PI值取3.1415926,在这种情况下,如果直接使用常数3.14,就要对程序的多处3.14进行修改成3.1415926。而使用符号常量,只需改动一处,即改变符号常量的定义(将最上面的PI定义改成PI 3.1415926)。 符号常量名中的英文字母一般使用大写字母,如PI。 2、整型常量

只要整型常量的值不超过表6.2中列出的整型数据的取值范围,就是合法的常量。整型常量就是常说的整数。 (1)整数的表示

C语言中的整数有十进制、八进制和十六进制3种表现形式。 a、 十进制整数由正、负号和阿拉伯数字0~9组成,但首位数字不能是0。 b、八进制整数由正、负号和阿拉泊数字0~7组成,但首位数字必须是0。 c、 十六进制整数由正、负号和阿拉伯数字0~9、英文字符a~f或A~F组成,首位数 字前必须有前缀0x或0X。

例如,10,010,0x10分别为十进制、八进制、十六进制整数,它们表示着不同数值的整数。10是十进制数值,010的十进制数值是8,0x10的十进制数值是16。

又如,16,020,0X10分别为十进制、八进制和十六进制整数,它们表示着同一个数值的整数,即十进制数值16。

0386和0x1g是非法的整型常量,因为0386作为八进制整数含有非法数字8,而0x1g作为十六进制整数含有非法字符g。

任何一个整数都可以用3种形式来表示,这并不影响它的数值。例如,表示十进制数值是10的整数,可以采用10、012或0Xa,所谓十进制、八进制和十六进制只是整数数值的3种表现形式而已。

作 业:

将下面各数用八进制和十六进制数表示 1、(10)10 =( )8=( )16

1 0

十进制化八进制: 8 10 2 = 12 八进制化十六进制:12=1 * 8+ 2 * 8= 10 1

3

注意:由于16进制和十进制超过10的数无法同样表示,故将16进制的10用a表示。即 10 = a 11 = b 12 = c 13 = d 14 = e 15 = f 因此上面的十进制10用十六进制表示就是a

2、(32)10 = ( )8 = ( )16

十进制化八进制: 8 32 0 = 40 十进制化十六进制:16 32 0 = 20 4 2

3、(75)10 = ( )8 = ( )16 8 75 3 =113 十进制化十六进制:16 75 11 = 4 b 9 1 4

1 十六进制的11是b

4、(-617)10 = ( )8 = ( )16 8 6 1 7 1 617的八进制是1151

8 7 7 5 八进制1151写成机器里的二进制原码是: 8 9 1 0 0 0 0 0 0 1 0 0 1 1 0 1 0 0 1

1 符号位 1 1 5 1 整型正值符号位0 (-617) 变成负数求补码,即反码加1:

(3位一个8进制数) 1 1 1 1 1 1 0 1 1 0 0 1 0 1 1 1 负值符号位1

1 7 6 6 2 7 (4位一个16进制数) 1 1 1 1 1 1 0 1 1 0 0 1 0 1 1 1 17(8) 15(8) 11(8) 7(8) 15(10) 13(10) 9(10) 7(10) f (16) d (16) 9(16) 7(16)

故 ( -617 )10 = ( 176627 )8 = ( f d 9 7 )16 5、(-111)10 = ( )8 = ( )16 6、( 2483 )10 = ( )8 = ( )16 7、( -28654 )10 = ( )8 = ( )16 8、( 21003 )10 = ( )8 = ( )16

(2)整数的类型 a、根据整数后的字母确定它的类型。后缀l或L表示long型常量,如-12L,0123456790L;后缀u或U表示unsigned型常量,如12u,034u,0x2fdU;后缀l和u或L和U表示unsigned long型常量,如4294967295LU( 后缀LU表示无符号长整型 ) b、根据整型常量的值确定它的类型。例如,取值在-32768~32767之间的整数是short型常量等。 3、实型常量

实型常量即常说的实数 (1) 实数的表示

实数又称为浮点数,可以用十进制浮点表示法和科学计算法表示。 a、 浮点表示法: 实数由正号、负号、阿拉泊数字0~9和小数点组成,必须有小数点,并且小数点的前、后至少一边要有数字。实数的浮点表示法又称实数的小数形式。 b、科学计数法:实数由正号、负号、数字和字母 e ( 或 E )组成,e 是指数的标志,在

4

e 之前要有数据,e 之后的指数只能是整数。实数的科学计数法又称实数的指数形式。例如:3.14和6.026E-27是合法的实数,而0.2E2.3和E-5是非法的实数。 科学计数法一般用于表示很大或很小的数,如普朗克常数6.026*10-27表示为6.026E-27,也可表示为60.26e-28、602.6e-29或0.6026e-26 。 (2)实数的类型

都是双精度浮点型。 4、字符型常量

a、字符型常量和ASCII字符集

字符型常量指单个字符,用一对单引号( ? ? )及其所括起来的字符来表示。在ASCCI字符集(见教材附录)中列出了所有可以使用的字符,每个字符在内存中占用一个字节,用于存储它的ASCII码值。所以C语言中的字符具有数值特征,可以像整数一样参加运算,此时相当于对字符的ASCII码进行运算。

例如,字符?A?的ASCII码是65,则?A?+1=66,对应于字符?B?。这是因为所有大写字母的ASCII码按升序连续排列,字符?A?的ASCII码加1,就是字符?B?的ASCII。 b、转义字符

有一些字符,如回车符,退格符等控制符号,它们不能在屏幕上显示,也无法从键盘上输入,只能用转义字符来表示。转义字符由反斜杠加上一个字符或数字组成,它把反斜杠后面的字符或数字转换成别的意义。虽然转义字符形式上由多个字符组成,但它们是字符常量,只代表一个字符,它的使用方法与其他字符常量相同。见表5.2列举了常见的转义字符。

表5. 2 转义字符

字 符 含 义 ASCII代马 \\n 换行,将当前位置移到下一行开头 10 \\t 水平制表(跳到下一个tab位置) 横向跳格 9 \\b 退格,将当前位置移到前一列 8

\\r 回车,将当前位置移到本行开头 13 \\f 换页,将当前位置移到下一页开头 12 \\ \\ 反斜杠 “\\” 92

\\ ” 双引号字符 34 \\ ? 单引号(撇号)字符 39 \\ddd 1~3位八进制整数所代表的字符 \\ xhh 1~2位十六进制整数所代表的字符

表5.2中最后两行采用ASCII码(八进制、十六进制)表示一个字符。例如,\\102表示ASCII码是八进制数102的字符,即字母?B?; \\x41的表示ASCII码是十六进制数41的字符,即字母?A?。这样,ASCII字符集中所有的字符都可以用转义字符表示。 如:#include

main()

{ printf(“ ab c\\t de\\rf\\tg\\n”); printf(“h\\ti\\b\\bj k\\n”);

5

}

输出: 1 2 3 4 5 6 7 8 9 10 输出位 f g d e h j k

\\t跳格的绝对位置8个。但,如果已经有2个了,就跳6格再接着打印跟在后面的字符,如下: 1、前面有2个,如:21\\tx // 输出6个空格 则会输出:21空空空空空空x // 第9个位置上打印x 2、前面没有,如: \\tx // 输出8个空格 则会输出:空空空空空空空空x // 第9个位置上打印x 3、前面有7个,如:1234567\\t // 输出1个空格 则会输出:1234567 x // 第9个位置上打印x 4、前面有8个,如:12345678\\tX // 输出8个空格 则会输出:12345678X // 第17个位置上打印x 5、前面有9个,如:123456789\\tX // 输出7个空格 则会输出:123456789空空空空空空空X // 第17个位置上打印x

举例:

#include main()

{ printf(“21\\t3\\n”); //出现6个空格,第9位是3 printf(“\\t3\\n”); //出现8个空格,第9位是3 printf(“1234567\\tx\\n”); //出现1个空格,第9位是x

printf(“12345678\\tx\\n”); //出现8个空格,第17位是x printf(“123456789\\tx\\n”); //出现7个空格,第17位是x }

5.2.2 变量

在程序运行过程中,其值可以改变的量称为变量。C语言中遇到的所有变量都必须先定义,然后才能使用。定义变量时需要确定变量的名字和数据类型。 1、变量名

变量名应该采用一个合法的表示符,如average(平均)、price(价格)、sum(总数)等,其中的英文字母习惯用小写字母。变量名的选择应尽量遵循“见名知义”的原则,用有明确含义的英文单词(或拼音)来作为名字,这样看到变量名就知道它代表的含义,便于自己或他人阅读程序。 变量名中的英文字母习惯上用小写字母。 2、变量的类型

C语言中,常量的数据类型通常由书写格式决定,而变量的数据类型在定义时指定。用于定义变量的基本数据类型见表5.1所示。 3、变量的定义方法

变量定义的一般形式是: 类型名 变量表;

类型名必须是有效的数据类型,变量表中可以有一个变量名或由逗号间隔的多个变量名。 定义变量需要确定变量的名字和数据类型,每个变量必须有一个名字作为标识,变

6

量名代表内存中的一个存储单元,用于存放该变量的值,而该存储单元的大小由变量的类型决定。例如:字符型变量用来存放字符,需个1个字节,而整型变量用来存放整数,需4各字节。 4、变量的使用 定义变量后,就可以使用它,在程序中使用变量,就是使用该变量所代表的存储单元。 对变量的使用,包括赋值和引用。在定义变量后,首先应该对它赋值,然后就可以在该程序中引用它的值,必要时还可以改变它的值,即再次赋值。 对变量的赋值有3种方法。

(1)在定义变量时对它赋值,称为变量赋初值。例如:

int a = 5 , b = 3 ;

(2)在可执行语句中,用赋值表达式对变量赋值。例如: int a , b ; a = 5; b = 3;

(3)调用输入函数对变量赋值。例如: int a , b;

scanf(“%d%d”,&a,&b);

运行时输入: 5 3 对变量a 和 b 分别赋值5和3。

5.3 数据的输入和输出

C语言中,数据的输入和输出都是通过函数调用来实现的。

5.3.1 整型数据的输入和输出

调用函数scanf()和printf()实现整型数据的输入和输出时,应根据数据的类型和输入输出的形式,在函数调用的格式控制字符中使用相应的格式控制说明,见表5.3所示。 基本的格式控制说明有:%d ( 以十进制形式输入/输出一个整数)、%o (以八进制形式输入/输出一个整数) 、%x (以十六进制形式输入/输出一个整数),%u (以十进制形式输入/输出一个无符号整数)。

在格式控制说明中,可以加宽度限定词,指定整型数据的输出宽度。例如:输出格式控制说明为%md,指定了数据的输出宽度为m( 包括符号位 ),若数据的实际位数(含符号位)小于m,则左侧补空格,若大于m,则按实际位数输出。

表5. 3 格式控制说明 ( 整型数据 )

数据类型 输入输出形式

十进制 八进制 十六进制 int %d %o %x long %ld %lo %lx unsigned %u %o %x unsigned long %lu %lo %lx

7

例5.2 使用基本格式控制说明%d、%o、%x输入输出整型数据 #include int main()

{ printf(\ printf(\ printf(\ return 0; }

运行结果: 10,12,a

10,8,16

10,a

可以看出数据以十进制、八进制、十六进制3种形式输出一个整数;输出结果以格式控制说明为准。例如,八进制数012就可以用十进制和十六进制的形式输出。因此,不管一个整数采用哪种表现形式,它的数值是确定的。 例5.3 用%o输入整型数据示例 #include int main() { int a,b;

printf(\

scanf(\ // 输进一个8进制数和一个十进制数 printf(\ // ]指定变量b的输出宽度为5 return 0;

}

运行结果:input a,b: 17 17 // 第一个17为8进制数,第二个17是十进制数 15 17 // 8进制17,十进制是15

输入时,用格式控制说明指定的形式来读入数据,以八进制形式读入17,相当于将017(即十进制15)赋值给变量a。以]输出b的值17,左端补了3个空格。 5.3.2 实型数据的输入和输出

调用函数scanf()和printf()实现实型数据的输入和输出时,在函数调用的格式控制字符串中使用相应的格式控制说明,见表5.4所示。 表 5. 4 格式控制说明( 实型数据 )

函数 数据类型 格式 含义 printf float %f 以小数形式输出浮点数(保留6位小数)

double %e 以指数形式输出浮点数(小数点前面有且仅有一位非零的数字

%f

scanf float %e 以小数形式或指数形式输入一个单精度浮点数 %lf

double %le 以小数形式或指数形式输入一个双精度浮点数

8

输出浮点数时,单精度和双精度浮点型数据使用相同的格式控制说明%f和%e;输

入浮点数时,格式控制说明%f和%e可以通用。但是,输入double型数据时,在格式控制说明中必须加限定字符 ? l ? ( ? l ? 是long的首字母 )。

双精度double型数据的输入格式控制说明必须用%lf或%le 。

在输出格式控制说明中,可以加宽度限制,指定实数数据的输出宽度。例如,输出格式控制说明%m.nf,指定输出浮点型数据时,保留n位小数,且输出宽度是m ( 包括符号位和小数点 )。若数据的实际位数小于m,左端补空格,若大于m,按实际位数输出。

例5.4 输出数值 #include main()

{ double pi=3.1415926; printf(\

printf(\ return 0; }

运行结果:

3.141593, 3.141593e+000 3.142, 3.14, 3.14

输出pi的值3.1415926时,%5.3f输出3.142 (保留3位小数),%5.2f输出3.14(保留2位小数,左端补1个空格),%.2f输出3.14(保留2位小数,按实际位数)。

5.3.3 字符型数据的输入和输出

字符的输入输出可以调用函数getchar()、putchar()和scanf()、printf() 。 getchar()函数和putchar()函数只能处理单个字符的输入和输出。

scanf()函数和printf()函数除处理整型数据和浮点型数据的输入输出外,也可以处理字符型数据的输入和输出。此时,在函数调用格式控制字符串中相应的格式控制说明用 %c 。

例5.5 输入输出字符 #include main()

{ char ch1,ch2,ch3;

scanf(\

printf(\}

运行结果: 输入 abc 输出 a # b # c

若输入 a bc 输出 a # # b

若printf() 函数里是连续的%c%c%c,则输入多个字符时,这些字符之间不能有间隔。

9

如果使用了间隔符(如空格 ? ? )。由于它本身也是字符,该间隔符就被作为输入字符。输入字符 a 后,输入了一个空格,所以ch2的值是? ?,ch3的值是 ? b ? 。 与字符型常量在程序中的表示不同,输入/输出字符时,字符两侧没有单引号(如ch1、ch2、ch3)。

C语言中,一个字符型数据在内存中用一个字节存储它的ASCII码,它即可以按字符形式输出,也可以按整型形式输出。按字符形式输出时,可以调用函数putchar()或printf()(格式控制说明用%c),系统自动将存储的ASCII码转换为相应的字符后输出;按整数形式输出时,可以调用函数printf()(格式控制说明选用%d、%o、%x等),直接输出它的ASCII码。

同样,一个整型(在有效的ASCII码范围内)也可以按字符形式输出,此时,输出字符的ASCII码等于该数。

例5.6 已知字符 ? b ? 的ASCII码值是98 ,? A ? 的ASCII码值是65,写出下列程序的运行结果。 #include main()

{ char ch = 'b';

printf(\ printf(\ printf(\

printf(\

return 0; }

运行结果: b , 98 b , 98 a , 97 B,66

程序中包括了一些字符运算,这在实际编程中是很有用的。例如,如变量ch的值是小写字母 ? a ? ~ ? z ?,则运算ch - ? a ? + ? A ? 把小写字母转换为大写字母。又如,若变量ch的值是数字字符?0 ? ~? 9 ?,运算ch – ? 0 ? 把数字字符转换为数字;若变量val的值是数字0~9,运算val + ? 0 ? 把数字转换为数字字符。

练习1、输入一个十进制数,输出相应的八进制数和十六进制数。例如,输入31,输出37和1F。 练习2、在例5.2源程序2中,如果将程序中的 scanf ( “ %o%d “,&a,&b ); 改为:

scanf (“ %x%d “,&a,&b); 输入不变,输出是什么?

练习3、如果变量ch的值是大写字母,怎样的运算可以把它转换为小写字母?

5.4 类型转换

在C语言中,不同类型的数据可以混合运算。但这些数据首先要换成同一类,然后再作运算。数据类型的转换包括自动转换和强制转换。自动转换由C语言编译系统自动完成,强制转换则通过特定的运算完成。

10

5.4.1 自动类型转换 1、非赋值运算的类型转换

数据类型的自动转换需遵循的规则见图5.1所示。为保证运算的精度不降低,采用以下方法。

高 double float

unsigned long long

unsigned unsigned short

低 int char ,short

图5.1 数据类型自动转换规则

(1)水平方向的转换:所有的char型和short型自动转换成int型,所有的unsigned short型自动转换成unsigned型,所有的long型自动地转换成unsigned long型,所有的float型自动地转换成double型。

(2)垂直方向的转换:经过水平方向的转换,如果参加运算的数据类型仍然不相同,再将这些数据自动转换成其中级别最高的类型。

例如,设变量ac的类型是char,变量bi的类型是int,变量d的类型是double,求解表达式ac + bi – d 。运算次序是:先计算ac + bi ,将ac转换为int型后求和,结果是int型;再将ac + bi 的和转换为double型,再与d相减,结果是双精度double型。 2、赋值运算的类型转换

赋值运算时,将赋值号右侧表达式的类型自动转换成赋值号左侧变量的类型。

例如:设变量x的类型是double,计算表达式 x = 1 。运算时,先将int型常量1转换成double型常量1.0,然后赋值给 x ,结果是double型。又如,设变量a的类型是short,变量b的类型是char,变量c的类型是long,求解表达式c = a + b 。运算次序是:先计算a + b ,将a 和b转换成int型后求和,结果是int型;再将a + b的和转换成变量c的类型long,然后赋值给c,结果是long型。

利用这条规则时,如果赋值号右侧表达式的类型比赋值号左侧变量的类型级别高,运算精度会降低。

例如:,设变量ai的类型是int,计算表达式ai = 2.56 。运算时,先将double型常量2.56转换成int型常量2,然后赋值给ai,结果是int型。

在赋值运算时,赋值号两侧数据的类型最好相同,至少右侧数据的类型比左侧数据的类型级别低,或者右侧数据的值在左侧变量的取值范围内,否则会导致运算精度降低,甚至出现意想不到的结果。 5.4.2 强制类型转换

使用强制类型转换运算符,可以将一个表达式转换成给定的类型。其一般形式是: ( 类型名 ) 表达式;

例如:设i是int型变量,( double ) i将i的值转换成double型,而( int )3.8将3.8转换成int型,得到3。

11

无论是自动类型转换,还是强制类型转换,都是为了本次运算的需要,对数据的类型进行临时转换,并没有改善数据的定义。例如,表达式 ( double ) i 的类型是double,而i的类型并没有改变,仍然是int 。

强制类型转换是运算而不是函数,故 ( int ) x 不能写成int ( x )。

强制类型转换运算的优先级较高,与自增运算符 ++ 相同,它的结合性是从右到左。例如:( int ) 3.8 + 1.3等价于 (( int ) 3.8 ) + 1.3,它的值是4.3,而 ( int ) ( 3.8+1.3 ) 的值是5。

5.5 表达式

5.5.1 算术表达式 1、算术运算符

算术运算符分为单目运算符和双目运算符两类,见表6.5所示。单目运算符只需要一个操作数,而双目运算符需要两个操作数。

表 5 . 5 算术运算符

目 数 单 目 双 目

运算符 + + - - + - + - * / % 名 称 自增 自减 正值 负值 加 减 乘 除 模(求余)

2、自增运算符和自减运算符

自增运算符 ++ 和自减运算符 - - 有两个功能。 (1)使变量的值增1或减1

例如:设n是一个整型变量并已赋值,则: ++ n 和 n ++ 都相当于 n = n + 1 ; - - n 和 n - - 都相当于 n = n – 1 ; (2)取变量的值作为表达式的值。

例如:计算表达式 ++ n 和 n ++ 的值,则:

++ n 的运算顺序是:先执行 n = n + 1,再将n的值作为表达式 ++ n 的值。 n ++ 的运算顺序是:先将n的值作为表达式n + + 的值,再执行 n = n + 1 ;

自增运算符和自减运算符的运算对象只能是变量,不能是常量或表达式。如:

3 ++ 或 ++ ( i + j ) 都是非法的表达式。

3、算术运算符的优先级和结合性

在算术四则运算中,遵循“先乘除后加减”的运算规则。同样,在C语言中,计算表达式的值也需要按运算符的优先级从高到低顺序计算。例如,表达式 a + b * c相当于 a + ( b * c ) ,这是因为操作数b的两侧有运算符 + 和 * ,而 * 的优先级高于 + 。 如果操作数两侧运算符的优先级相同,则按结合性(结合方向)决定计算顺序,若结合方向为“从左到右”,则操作数先与左面的运算符结合;若结合方向为“从右到左”,则操作数先与右面的运算符结合。

C语言中算术运算符的优先级和结合性见表5.6所示,同一行实线上的运算符优先级相同,不同行的运算符的优先级按从高到低的次序排列,可以用圆括号来改变运算符的执行次序。

12

表5.6 部分运算符的优先级和结合性

运算符种类 运 算 符 结 合 方 向 优 先 级 逻辑运算符 ! 高 ++ - - + - * ( 单目 ) 从右向左(右结合) 算术运算符 * / % ( 双目 ) + - ( 双目 ) < <= > >= 关系运算符 == ! = 从左向右(左结合) && 逻辑运算符 || 条件表达式 ? : 赋值运算符 = += -= *= /= %= 从右向左(右结合) 逗号运算符 . 从左向右(左结合) 低 例如,表达式-5 + 3 % 2等价于(-5)+(3 % 2 ),结果为-4;表达式3 * 5 % 3等价于 (3*5)% 3,结果为0,这是因为5两侧运算符 * 和 % 的优先级相同,按从左到右的结合方向,5先与 * 结合。而表达式 – i ++ 等价于 – ( i ++ ),这是因为i 两侧运算符 - 和 ++ 的优先级相同,按从右到左的结合方向,i 先与 ++ 结合。 4、算术表达式

用算术运算符将运算对象连接起来的符合C语言语法规则的式子称为算术表达式,运算对象包括常量、变量和函数等表达式。算术表达式的值和类型由参加运算的运算符和运算对象决定。 5、副作用的说明

(1)C语言中,自增和自减是两个很特殊的运算符,相应的运算会得到两个结果。例如:设n = 3,表达式 n ++ 经过运算之后,其值为3,同时变量n的值增1为4。即在求解表达式时,变量的值改变了,称这种变化为副作用。在编程时,副作用的影响往往会使得运算的结果与预期的值不相符。

要慎用自增、自减运算,尤其不要用它们构造复杂的表达式。

(2)C语言中,根据运算符的优先级和结合性决定表达式的计算顺序,但对运算符两侧操作数的求值顺序并未做出明确的规定,允许编译系统采取不同的处理方式。例如,计算表达式f( ) + g( ) 时,可以先求f( )再求g( ),也可以相反。如果求值顺序的不同影响了表达式的结果,即相同的源程序在不同的编译系统下运行,结果可能不同,就给程序的移植造成了困难。所以,在实际应用中应该避免这种情况。 5.5.2 赋值表达式 1、赋值运算服

C语言将赋值作为一种运算,赋值运算符 ” =” 的左边必须是一个变量,作用是把一个表达式的值赋给一个变量。赋值运算符的优先级比算术运算符低,它的结合方向是从右向左,见表5.6所示。例如,表达式x = ( 3 * 4 ) 等价于x = 3 * 4。表达式x = y = 3等价于x = ( y = 3 )。 2、赋值表达式

13

用赋值运算符将一个变量和一个表达式连接起来的式子称为赋值表达式。赋值表达式的简单形式是: 变量 = 表达式;

赋值表达式的运算过程是:

(1)计算赋值运算符右侧表达式的值。

(2)将赋值运算符右侧表达式的值赋给赋值运算符左侧的变量。

(3)将赋值运算符左侧的变量的值作为赋值表达式的值。

在赋值运算时,如果赋值运算符两侧的数据类型不同,在上述运算过程的第(2)步,系统首先将赋值运算符右侧表达式的类型自动转换成赋值运算符左侧变量的类型,再给变量赋值,并将变量的类型作为赋值表达式的类型。

例如,设n是整型变量,计算表达式 n = 3.14 * 2的值,首先计算3.14 * 2得到6.28,将6.28转换成整型值6后赋给n,该赋值表达式的值是6,类型是整型。

又如,设x是双精度浮点型变量,计算表达式x = 10 / 4的值,首先计算10 / 4得到2,将2转换成双精度浮点型值2.0后赋给x,该赋值表达式的值是2.0,类型是双精度浮点型。

在赋值表达式中,赋值运算符右侧的表达式也可以是一个赋值表达式。如:

x = ( y = 3 ); 求解时,先计算表达式y = 3,再将该表达式的值3赋给x,结果使得x和y都赋值为3;相当于计算x = 3和y = 3两个赋值表达式。

由于赋值运算符的结合性是从右到左,因此,x = ( y = 3 )等价于x = y = 3,即多个简单赋值运算可以组合为一个连赋值的形式。 3、复合赋值运算符

赋值运算符分为简单赋值运算符和复合赋值运算符。简单赋值运算符就是” = “,复合赋值运算符又分为复合算术赋值运算符和复合位赋值运算符,在” = “前加上算术运算符就构成了复合算术赋值运算符,见表5.7所示。复合位赋值运算符在5.5.7节介绍。

所以,赋值表达式的一般形式是: 变量 赋值运算符 表达式; 表5.7 复合算术赋值运算符

运 算 符 名 称 等 价 关 系 ( exp 指表达式 ) + = 加赋值 x + = exp等价于 x = x + ( exp ) - = 减赋值 x - = exp等价于 x = x – ( exp ) * = 乘赋值 x * = exp等价于 x = x * ( exp ) / = 除赋值 x / = exp 等价于 x = x / ( exp ) % = 求余赋值 x % = exp等价于 x = x % ( exp ) 注:exp指数表达式

x * = y – 3等价于x = x * ( y – 3 ),而不是x = x * y – 3

5.5.3 关系表达式 1、关系运算符

关系运算符(见表5.8所示)是双目运算符,用于对两个操作数进行比较。 表 5.8 关系运算符

运 算 符 < < = > > = = = ! =

名 称 小于 小于或等于 大于 大于或等于 等于 不等于 优先级 高 低

14

关系运算符的优先级低于算术运算符,高于赋值运算符和逗号运算符,它的结合方向是从左向右(见表5.6)。例如,设a、b、c是整型变量,ch是字符型变量,则: (1)a > b = = c等价于 ( a > b ) = = c (2)d = a > b等价于 d = ( a > b )

(3)ch > ? a ? + 1等价于ch > ( ? a ? + 1 ) (4)d = a + b > c等价于 d = ( ( a + b ) > c ) (5)3 < = x <= 5等价于( 3 < = x ) < = 5 (6)b – 1 = = a ! = c等价于(( b – 1 ) = = a ) ! = c 2、关系表达式

用关系运算符将两个表达式连接起来的式子,称关系表达式。关系表达式的值反映了关系运算(比较)的结果,它是一个逻辑量,取值“真”或“假”。由于C语言没有逻辑型数据,就用整数1代表“真”,0代表“假”。这样,关系表达式的值就是1或0,它的类型是整型。

例5.7 关系表达式的运用 #include int main()

{ char ch = 'w'; // w 的ASCII码十进制为119 int a = 2,b = 3,c = 1,d,x = 10;

printf(\//a不大于b为假得0 ,而0是不等于c(c=1)的,所以结果是假0 printf(\//a不大于b得假0,而0 赋给d,d是0,结果是0

printf(\// 'a'是97,加1为98。ch为w值是119。119大于98,结果是真1 printf(\// a+b是5,5是大于c的,得真1,真1赋给d,结果是真1 printf(\// b-1得2,2等于a得真1,1应得c(1),但这里是!=故得假0 printf(\// 3小于10,得真1,而1小于5得真1,所以结果是真1。 return 0;

}

运行结果:0 0 1 1 0 1

程序输出了6个表达式的值,其中有两个是赋值表达式,请读者根据运算符的优先级做出判断。

关系表达式b – 1 = = a ! = c等价于关系表达式(( b – 1 ) = = a ) ! = 1,当a = 2,b = 3时,( b – 1 ) = = a的值是1,再计算1!= 1,得到0。

关系表达式3 <= x <= 5等价于关系表达式( 3 <= x ) <= 5,当 x = 10时,3 <= x的值是1,再计算1 <= 5,得到1。其实,无论x取什么值,关系表达式3 <= x的值不是1就是0,都是小于5,即3 <= x <= 5的值恒为1。由此看出,关系表达式3 <= x <= 5无法正确表示代数式3 <= x <= 5,如x = 4,3小于4,它得真是1,而1小于5得真,这不是代数式的表示,只是一种关系的运算。 5.5.4 逻辑表达式 1、逻辑运算符

15

C语言提供了3种逻辑运算符(见表5.9所示),逻辑运算对象可以是关系表达式或逻辑量,逻辑运算的结果也是一个逻辑量,与关系运算一样,用整数1代表“真”,用0代表“假”。

表5.9 逻辑运算符

目 数 单 目 双 目 运算符 ! && || 名 称 逻辑非 逻辑与 逻辑或

例如,在逻辑表达式( x >= 3 ) && ( x <= 5 )中,&&是逻辑运算符,关系表达式x >= 3和x <= 5是逻辑运算对象,逻辑运算对象的结果是1或0。

假如a和b是逻辑量,则对a和b可以进行的基本逻辑运算包括 ! a ( 或 ! b )、a && b和a || b 3种。作为逻辑量,a或b的值只能是“真”或“假”,所以,a和b可能的取值组合只有4种,即(“真”,“真”)、(“真”、“假”)、(“假”,“真”)和(“假”,“假”),与之对应的3种逻辑运算的结果也随之确定。将这些内容用一张表格表示,就是逻辑运算的“真值表”,见表5.10所示。它反映了逻辑运算的规则,其中a和b的取值见括号中的内容。

表 5.10 逻辑运算的“真值表”

a b ! a a && b a || b 非 0 (真) 非 0 (真) 0 1 1 非 0 (真) 0 (假) 0 0 1 0 (假) 非 0 (真) 1 0 1 0 (假) 0 (假) 1 0 0 表5.10说明了逻辑运算符的功能,即:

(1)! a :如果a为“真”,结果是0 ( 假 );如果a为“假”,结果是1(真)。 (2)a && b:当a和b都为“真”时,结果是1 ( 真 );否则,结果是0 ( 假 )。 (3)a || b:当a和b都为“假”时,结果是0 ( 假 );否则,结果是1( 真 )。

如何判断逻辑量(如a和b)的真、假呢?如果某个逻辑量的值为非0,就是真;如果值为0就是假(见表5.10所示)。

例如计算(x >= 3)&&(x <= 5),若x = 4,则 x >= 3和 x <= 5的值都是1(非0为真),“逻辑与”运算的结果就是1;若x = 10,则x >= 3的值是1(非0为真),而 x <= 5的值是0(假),“逻辑与”运算的结果就是0。 又如,计算 ! ( x = = 2 ),若x = 10,则x = = 2的值是0(假),“逻辑非”运算的结果是1(真);若x = 2,则 x = = 2的值是1(非0为真),“逻辑非”运算的结果是0(假)。

逻辑运算符的优先级见表5.6。例如: (1)a || b && c等价于a || ( b && c ) (2)! a && b等价于( ! a ) && b

(3)x >= 3 && x <= 5等价于( x >= 3 ) && ( x <= 5) (4)! x == 2等价于( ! x ) == 2

(5)a || 3 + 10 && 2等价于a || (( 3 + 10 ) && 2 ) 2、逻辑表达式

16

用逻辑运算符将关系表达式或逻辑量连接起来的式子,称为逻辑表达式。逻辑运算对象是值为“真”或“假”的逻辑量,它可以是任何类型的数据,如整型、浮点型、字符型等,C编译系统以非0和0判定真和假。逻辑表达式的值反映了逻辑运算的结果,也是一个逻辑量,但系统在给出逻辑运算结果时,用1代表真,0代表假。 例5.8 逻辑表达式的运用

#include int main()

{ char ch = 'w';

int a = 2,b = 0,c = 0; float x = 3.0;

printf(\ // 有一个假,则为假,结果是0

printf(\//按优先级先&&后||,则b&&c为假0,a||0有一个真为真,结果真1 printf(\// 按优先级先!后&&,则!a是假,再&&b( 0),假与假还是假0 printf(\//a||3是真,以后无论是假还是真,结果都是1,因为真1+1或0是真1 printf(\// x= =2是假,非( ! )假( 0 )是真1 printf(\// !x是假0,0 = = 2是假0

printf(\ // w 的ASCII码十进制为119为非0真1,真1或( || )假,还是真1 return 0;

}

运行结果:0 1 0 1 1 0 1

程序中字符型变量ch的值是?w?(其ASCII码值不为0),整型变量a的值是2,浮

点型变量x的值是3.0,都是非0的数,在逻辑运算时,相当于“真”,整型变量b和c的值都是0,在逻辑运算时,相当于“假”,而逻辑运算的结果只能是1或0。

!( x = = 2 )是逻辑表达式,当x = 3.0时,( x = = 2 )的值是0,再计算 ! 0,得1。而 ! x = = 2是关系表达式,等价于( ! x ) = = 2,当x = 3.0时,! x的值是0,再计算0 = = 2,得到0。其实,无论x取什么值,逻辑表达式 ! x的值不是1就是0,而不可能等于2,即 ! x = = 2的值恒为0。

与其它表达式的运算过程不同,求解用逻辑运算符&&或者 || 连接的逻辑表达式时,按从左到右的顺序计算该运算符两侧的操作数,一旦能得到表达式的结果,就停止计算。例如:

(1)求解逻辑表达式exp1 && exp2时,先计算exp1,若其值为0,则exp1 && exp2的值一定是0。此时,已经没有必要计算exp2的值。例5.8中,计算表达式 ! a && b时,先算 ! a,由于a的值是2,! a就是0,该逻辑表达式的值一定是0,不必再计算b。 (2)求解逻辑表达式exp1 || exp2时,先算exp1,若其值为非0,则exp1 || exp2的值一定是1。此时,也不必计算exp2的值。例5.8中,计算表达式a || 3 + 10 && 2时,先算a,由于a的值是2,该逻辑表达式的值一定是1,也不必再计算3 + 10 && 2。 例5.9 写出满足下列条件的C表达式 (1)x 为零 (2)x和y不同时为零 解答(1)关系表达式x = = 0或逻辑表达式 ! x

当x分别取值非0和0时,从真值表5.11可以看出,两个表达式的结果相同,故两

17

式等价。

5.11(1) 真 值 表 x x = = 0 ! x

非0 0 0 0 1 1

解答(2)逻辑表达式 ! ( x = = 0 && y = = 0 )或 x ! = 0 || y ! = 0或 x || y

从5.11(2)真值表上可以看出,3个表达式的结果相同,故3者等价。

5.11(2)真值表 x y !(x==0&&y==0) x!=0||y!=0 x||y

非0 非0 1 1 1 非0 0 1 1 1 0 非0 1 1 1 0 0 0 0 0

5.5.5 条件表达式

条件运算符是C语言中的一个三目运算符,它将3个表达式连接在一起,组成条件表达式。条件表达式的一般形式是: 表达式1?表达式2:表达式3;

条件表达式的运算过程是:先计算表达式1的值,如果它的值为非0(真),将表达式2的值作为条件表达式的值,否则,将表达式3的值作为条件表达式的值。 例如,设a、b是整型变量,将a、b的最大值赋给z,可以用if语句实现: if ( a > b ) z = a ; else

z = b ;

也可以用条件表达式求出a、b的最大值,再赋给z ; z = ( a > b ) ? a : b ;

如果条件表达式中表达式2和表达式3的类型不同,根据5.4.1节中讨论的类型自动转换规则确定条件表达式的类型。例如,表达式 ( n > 0 ) ? 2.9 : 1的类型是double型。如果n是一个浮数,该表达式的值是1.0,而不是1。

条件运算符的优先级较低,只比赋值运算符高。它的结合方向是自右向左(见表5.6所示)。例如:

(1)( n > 0 ) ? 2.9 : 1等价于n > 0 ? 2.9 : 1

(2)a > b ? a : c > d ? c : d等价于a > b ? a : ( c > d ? c : d ) 灵活地使用条件表达式,不但可以使C语言程序简单明了,而且还能提高运算效率。

5.5.6 逗号表达式

C语言中,逗号既可以作为分隔符,又可作为运算符。逗号作为分隔符使用时,用于间隔说明语句中的变量或函数中的参数,例如:

18

int a,b,c;

printf(“%d %d”,x,y);

逗号作为运算符使用时,将若干个独立的表达式连接在一起,组成逗号表达式。逗号表达式的一般形式是: 表达式1,表达式2,…,表达式 n

逗号表达式的运算过程是:先计算表达式1的值,然后计算表达式2的值,…,最后计算表达式n的,并将表达式n的值作为逗号表达式的值,将表达式n的类型作为逗号表达式的类型。

例如,设a,b,c都是整型变量,计算逗号表达式” ( a = 2 ),( b = 3 ),( c = a + b ) ”的值,该表达式由3个独立的表达式通过逗号运算符连接而成,从左到右依次求解这3个表达式后,该逗号表达式的值和类型由最后一个表达式” c = a + b “决定,其值是5,类型是整型。

逗号运算符的优先级是所有运算符中最低的,它的结合性是从左到右(见表5.6所示)。例如:表达式” ( a = 2 ),( b = 3 ),( c = a + b ) “等价于” a = 2,b = 3,c = a + b”。

逗号表达式常用于for循环语句中。

5.5.7 位运算

位运算是C语言与其它高级语言相比较,一个比较有特色的地方,利用位运算可以实现许多汇编语言才能实现的功能。

所谓位运算是指进行二进制位的运算。C语言提供的位运算符如表5.12所示。

表5.12 位 运 算 符

运算符 名 称 & 按位“与” | 按位“或” ∧ 按位“异或” ~ 取 反 << 左 移 >> 右 移

在使用位运算符时,注意以下几点:

(1)位运算符中除 ~ 是单目运算以外,其余均为二目运算

(2)位运算符所操作的操作数只能是整型或字符型的数据以及它们的变体 (3)操作数的移位运算不改变原操作数的值

C语言的位运算符分为位逻辑运算符和移位运算符两类。下面将分别介绍各个位运算符。

1、位逻辑运算符

位逻辑运算符有如下4种,二进制位逻辑运算的真值表见表5.13所示。

表5.13 二进制位逻辑运算真值表

A B ~A A | B A & B A ∧ B

19

0 0 1 0 0 0 0 1 1 1 0 1 1 0 0 1 0 1 1 1 0 1 1 0

(1)单目运算符:~ ( 取反 )

(2)双目运算符:& ( 按位 “ 与 “ )、| ( 按位 “或” )、∧ ( 按位”异或”)

位逻辑运算符的运算规则:先将两个操作数(int或char类型)化为二进制数,然后按位运算。

例如,位非运算~,将操作数按二进制数逐位求反,即1变为0,0变为1。

设a = 84,b = 59,则a & b结果为16。因为84的二进制数为01010100,而59的二进制数为00111011,按上表的运算规则逐位求与,得二进制数00010000,即是十进制数16。具体过程如下:

01010100(十进制84的二进制数) & ) 00111011(十进制59的二进制数) 00010000(十进制16的二进制数)

注意,二进制位逻辑运算和普通的逻辑运算的区别。假设 x = 0,y = 28,则x & y等于0,x | y 等于28,而x && y等于0,x || y等于1。在做位运算时,只有对应位进行运算,相邻位之间没有关系。

对于位“异或”运算∧有几个特殊的操作: (1)a ∧ a的值为0

(2)a ∧ ~a = 二进制全1(如果a以16位二进制数表示,则为65535) (3)~( a ∧ ~a ) = 0

除此以外,位“异或”运算∧还有一个很特别的应用,即通过使用位“异或”运算而不虚临时变量就可以交换两个变量的值。假设a = 19,b = 23,想将a和b的值互换,可执行语句: a ∧ = b ∧ = a ∧ = b ;该语句等效于下述两步: b ∧ = a ∧ = b ; a = a ∧ b ;

b ∧ = a ∧ = b可解释为:b = b ∧ ( a ∧ b ) a ∧ b ∧ b a ∧ 0 = a 因为操作数的位运算并不改变原操作数的值,除第一个b外,其余的a、b都是指原来的a、b,即b得到a原来的值。

a = a ∧ b可解释为:

a = a ∧ b ( a ∧ b ) ∧ ( b ∧ a ∧ b ) a ∧ a ∧ b ∧ b ∧ b = b 最初两步之一的“ b ∧ = a ∧ = b;” 中 “ a ∧ = b”使a改变,b也已经改变,分别将原来的式子代入最后的a = a ∧ b,a得到b原来的值。 2、移位运算

移位运算是指对操作数以二进制位为单位进行左移或右移的操作。移位运算有两种: >> (右移) 和 << (左移)。

a >> b表示将a的二进制值右移b位,a << b表示将a的二进制值左移b位。要求a和b都是整型,b只能为正数,且不能超过机器字所表示的二进制位数。

20

移位运算具体实现有3种方式: 循环移位、逻辑移位、算术移位(带符号)。 (1)循环移位:在循环移位中,移入的位数等于移出的位数。

(2)逻辑移位:在逻辑移位中,移出的位丢失,移入的位取0。

(3)算术移位:在算术移位(带符号)中,移出的位丢失,左移入的位取0,右移入的位取符号位,即最高位代表数据符号,保持不变。

C语言中的移位运算方式与具体的C语言编译器有关,通常实现中,左移位运算后右端出现的空位补0,移至左端之外的位则舍弃;右移运算与操作数的数据类型是否带有符号位有关,不带符号位的操作数右移位时,左端出现的空位补0,移至右端之外的位则舍弃,带符号位的操作数右移位时,左端出现的空位按符号位复制,其余的空位补0,移至犹端之外的位则舍弃。

例如,假设 a = 58(10) = 72(8)=00111010(2),a << 2的值为: 00111010 00 = 11101000(2) = 350(8)=232 (10)= 58*4

在数据可表达的范围里,一般左移1位相当于乘2,作移2位相当于乘4。 同样,假设 a = 58(10) = 00111010(8),a >> 1的值为: 0 00111010 = 00011101 (2) = 35(8) = 29 (10) = 58/2 一般右移1位相当于除2,右移2位相当于除4。 再次提醒:操作数的移位运算并不改变原操作数的值。即经过上述移位运算,a仍为58,除非通过赋值 a = a >> 2,改变a的值。

复合位赋值运算符就是在赋值运算符 = 前加上位运算符。

5.5.8 其它运算

1、长度运算

长度运算符sizeof是一个单目运算符,用来返回变量或数据类型的字节长度。使用长度运算符可以增强程序的可移植性,使之不受具体计算机数据类型长度的限制。

例如,设a是整形变量,则sizeof(a)求整型变量a的长度,值为4(bytes),sizeof(int)求整型的长度,值为4(bytes),sizeof(double)求双精度浮点型的长度,值为8(bytes)。 2、特殊运算符

C语言中,还有一些比较特殊的、具有专门用途的运算符。例如: (1)( )括号:用来改变运算顺序

(2)[ ] 下标:用来表示数组元素,祥见下一章 (3)* 和 & : 与指针运算有关,祥见第7章 (4)-> 和 . :用来表示结构分量,祥见第8章 3、运算符的优先级与结合

C语言中,运算符共分15个优先级,分别用1~15来表示,1表示优先级最高,15表示优先级最低。

C语言中运算符的结合性分两类,左结合(从左到右)和右结合(从右到左)。单目运算符、双目运算符和赋值运算符的结合性是从右到左,其它运算符的结合性是从左到右。

5.5.9 程序解析

例5.10 输入一行字符,将其中的大写字母转换为相应的小写字母后输出,小写字母转换为相应的大写字母后输出,其它字符按原样输出。

21

输入一行字符,就是输入以回车符 ? \\ n ?结束的一批字符,即以? \\ n ?作为循环的结束标志,大小写字母的判断和转换用else-if语句实现。 #include void main() { char ch;

printf(\ ch = getchar(); while(ch!='\\n') {

if(ch>='A'&&ch<='Z') // 如果ch是大写字母 ch = ch - 'A' + 'a'; // 大写字母转换为小写字母 else if(ch >= 'a' && ch <='z') // 如果ch是小写字母 ch = ch - 'a' + 'A'; // 小写字母转换为大写字母 putchar(ch); // 输出转换后的字符 ch = getchar(); // 读入下一个字符 }

printf(\}

运行结果:input characters: Reold 123? rEOLD 123? 程序还可以写成: #include void main() { char ch;

printf(\

while((ch = getchar()) != '\\n') //直到输入回车为止 {

if(ch>='A'&&ch<='Z') //如果ch是大写字母 ch = ch - 'A' + 'a'; //大写字母转换为小写字母 else if(ch >= 'a' && ch <='z') //如果ch是小写字母 ch = ch - 'a' + 'A'; //小写字母转换为大写字母 putchar(ch); //输出转换后的字符 }

printf(\}

运行结果:input characters: Reold 123? rEOLD 123?

其中( ch = getchar()) != ?\\n?是一个关系表达式,运算符 != 的左侧是赋值表达式。运算时,先计算赋值表达式( ch = getchar()),把输入的字符赋给变量ch,同时该赋值表达式的值就是变量ch的值;然后再和 ? \\ n ? 比较。这样,用一个表达式就实现了输入和比较两种运算。

( ch = getchar() ) != ? \\n ? 和 ch = getchar() != ? \\ n ? 不等价

因为赋值运算符=的优先级低于关系运算符 !=,所以不能省略 ( ch = getchar() ) != ? \\ n ? 中的括号。表达式 ch = getchar() != ? \\ n ?等价于 ch = ( getchar() != ? \\ n ? ),它是一个赋值表达式,运算时,先计算关系表达式getchar() != ? \\ n ?,其值是0或1,再赋给ch。故ch中存放的不是输入的字符,而是关系运算的结果0或1。

22

练 习:

(1)a && ( b || c )等价于 a && b || a && c (2)a || ( b && c )等价于 ( a || b ) && ( a || c ) (3)! ( a && b )等价于 ! a || !b (4)! ( a || b )等价于 ! a && ! b

(5)输入一行字符,统计出其中的英文字母、空格、数字和其他字符的个数

(6)输入一行字符,统计其中单词的个数。各单词之间用空格分隔,空格数可以是多个

23

本文来源:https://www.bwwdw.com/article/wb26.html

Top