690 likes | 829 Views
第 3 章 顺序结构程序设计 3.1 C 的语句 3.2 赋值运算与赋值语句 3.3 数据输入 / 输出 3.4 顺序结构程序举例 本章小结. 3.1 C 的 语 句 C 语言中语句的分类如图 3-1 所示。 图 3-1 C 语句的分类. 3.1.1 简单语句 1 .表达式语句 在表达式之后加上分号就构成表达式语句。一般形式为: 表达式 ; 最典型的表达式语句是由赋值表达式构成的语句。例如: m+=x; i=j=k=5; 都是由赋值表达式构成的表达式语句。由赋值表达式构成的语句习惯称为赋值语句。.
E N D
第3章 顺序结构程序设计3.1 C的语句3.2 赋值运算与赋值语句3.3 数据输入/输出3.4 顺序结构程序举例本章小结
3.1 C 的 语 句C语言中语句的分类如图3-1所示。 图3-1 C语句的分类
3.1.1 简单语句1.表达式语句在表达式之后加上分号就构成表达式语句。一般形式为:表达式;最典型的表达式语句是由赋值表达式构成的语句。例如:m+=x;i=j=k=5;都是由赋值表达式构成的表达式语句。由赋值表达式构成的语句习惯称为赋值语句。
其他表达式加分号也构成了语句。例如:x+y-z;也是一个语句。不过从语义上讲,该语句没有实际意义。因为求表达式x+y-z的值之后,没有保留,对变量x、y、z的值也没有影响。其他表达式加分号也构成了语句。例如:x+y-z;也是一个语句。不过从语义上讲,该语句没有实际意义。因为求表达式x+y-z的值之后,没有保留,对变量x、y、z的值也没有影响。
另一种典型的表达式语句是函数调用之后加分号,一般形式为:函数调用;该表达式语句未保留函数调用的返回值。但该表达式语句中的函数调用引起实参与形参的信息传递和函数体的执行,将使许多变量的值被设定或完成某种特定的处理。如调用输入函数使指定的变量获得输入数据,调用输出函数使输出项输出等。另一种典型的表达式语句是函数调用之后加分号,一般形式为:函数调用;该表达式语句未保留函数调用的返回值。但该表达式语句中的函数调用引起实参与形参的信息传递和函数体的执行,将使许多变量的值被设定或完成某种特定的处理。如调用输入函数使指定的变量获得输入数据,调用输出函数使输出项输出等。
2.空语句空语句是什么也不做的语句,它只有一个分号。C语言引入空语句是出于两个实用上的考虑:一是为了构造特殊控制的需要。如循环控制结构需要一个语句作为循环体,当需循环执行的动作已全部由循环控制部分完成时,就需要一个空语句的循环体;二是在复合语句的末尾设置一个空语句,以便能用goto语句将控制转移到复合语句的末尾。另外,C语言引入空语句使程序中连续出现多个分号不再是错误,编译系统遇到这种情况,就认为后继的分号都是空语句。2.空语句空语句是什么也不做的语句,它只有一个分号。C语言引入空语句是出于两个实用上的考虑:一是为了构造特殊控制的需要。如循环控制结构需要一个语句作为循环体,当需循环执行的动作已全部由循环控制部分完成时,就需要一个空语句的循环体;二是在复合语句的末尾设置一个空语句,以便能用goto语句将控制转移到复合语句的末尾。另外,C语言引入空语句使程序中连续出现多个分号不再是错误,编译系统遇到这种情况,就认为后继的分号都是空语句。
3.1.2 复合语句用花括号将若干个语句括起来就构成了复合语句。它将若干个语句变成一个顺序执行的整体,从逻辑上讲它相当于一个语句,能用作其他控制结构的成分语句。
例如交换两个整型变量a、b的值,作为一个复合语句写成:{ int t; t=a; a=b; b=t;}在构造复合语句时,为完成复合语句所要完成的操作,可能需要临时工作单元。如上面例子中的变量t。在C语言的复合语句中,在语句序列之前可以插入变量定义,引入只有在复合语句内部才可使用的临时单元。
注意:复合语句的“}”后面不能出现分号,而“}”前复合语句中最后一条语句的分号不能省略。例如:{t=a; a=b; b=t;};和{t=a; a=b; b=t}第一个复合语句语句后面加了分号,实际上构成了一个空语句,即相当于写了两个语句,一个是复合语句,另一个是空语句。第二个复合语句中的第三个语句没有分号,因此是错误的复合语句。
3.1.3 流程控制语句C语言中控制程序流程的语句有3类,共9种语句。1.选择语句选择语句有if语句和switch语句两种。if语句根据实现选择分支的多少又有多种格式,包括单分支、双分支和多分支if语句。switch语句能实现多个分支流程。
2.循环语句循环语句有while、do…while和for语句3种。当循环语句的循环控制条件为真时,反复执行指定操作,是C语言中专门用来构造循环结构的语句。2.循环语句循环语句有while、do…while和for语句3种。当循环语句的循环控制条件为真时,反复执行指定操作,是C语言中专门用来构造循环结构的语句。
3.转移语句转移语句有break、continue、return和goto共4种。它们都能改变程序原来的执行顺序并转移到其他位置继续执行。例如,循环语句中break语句终止该循环语句的执行,而循环语句中的continue语句只结束本次循环并开始下次循环,return语句用来从被调函数返回到主调函数并带回函数的运算结果,goto语句可以无条件转向任何指定的位置执行。3.转移语句转移语句有break、continue、return和goto共4种。它们都能改变程序原来的执行顺序并转移到其他位置继续执行。例如,循环语句中break语句终止该循环语句的执行,而循环语句中的continue语句只结束本次循环并开始下次循环,return语句用来从被调函数返回到主调函数并带回函数的运算结果,goto语句可以无条件转向任何指定的位置执行。
3.2 赋值运算与赋值语句赋值语句是高级语言中用来实现运算的一个重要语句,而且赋值语句可以将运算结果存起来。C语言将赋值也看作一种运算,赋值运算构成赋值表达式,赋值表达式后面加上分号就构成了赋值语句。
3.2.1 赋值运算1.赋值运算的一般形式在C语言中,通常把“=”称为赋值号,也叫赋值运算符。它是一个双目运算符,需要连接两个运算量:左边必须是变量,右边则是表达式。赋值运算的一般形式为:变量=表达式
赋值运算的意义是先计算表达式的值,然后将该值传送到变量所对应的存储单元中。即计算表达式的值,并将该值赋给变量。赋值表达式的值即是被赋值变量的值。赋值运算的意义是先计算表达式的值,然后将该值传送到变量所对应的存储单元中。即计算表达式的值,并将该值赋给变量。赋值表达式的值即是被赋值变量的值。
赋值运算实际上代表一种传送操作(Move),即将赋值号右边表达式的值传送到左边变量所对应的存储单元中。在这里,变量与确定的内存单元相联系,既具有值属性,也具有地址属性,它可以出现在赋值运算符的左边,故称为左值(Left Value)表达式。将常量、变量、函数等运算对象用运算符连接起来的表达式,只有值属性而无地址属性,它只能出现在赋值运算符的右边,故称为右值(Right Value)表达式。
注意:赋值运算符左边一定要求是左值表达式,它代表一定的内存单元,显然只有内存单元才能存放表达式的值。赋值右边可以是任何表达式。注意:赋值运算符左边一定要求是左值表达式,它代表一定的内存单元,显然只有内存单元才能存放表达式的值。赋值右边可以是任何表达式。
2.复合赋值运算在程序设计中,经常遇到在变量已有值的基础上作某种修正的运算。如x=x+5.0。这类运算的特点是:变量既是运算对象,又是赋值对象。为避免对同一存储对象的地址重复计算,C语言还提供了10种复合赋值运算符:+=、-=、*=、/=、%=、<<=、>>=、&=、|=、^=其中,前5种是常用的算术运算,后5种是关于位运算的复合赋值运算符。2.复合赋值运算在程序设计中,经常遇到在变量已有值的基础上作某种修正的运算。如x=x+5.0。这类运算的特点是:变量既是运算对象,又是赋值对象。为避免对同一存储对象的地址重复计算,C语言还提供了10种复合赋值运算符:+=、-=、*=、/=、%=、<<=、>>=、&=、|=、^=其中,前5种是常用的算术运算,后5种是关于位运算的复合赋值运算符。
一般地,记θ为一个双目运算符,复合赋值运算的格式为:xθ=e其等价的表达式为:x=xθ(e)注意:当e是一个复杂表达式时,等价表达式的括号是必需的。即e表示表达式,使用复合赋值运算符连接两个运算量时,要把右边的运算量视为一个整体。例如,x*=y+5表示x=x*(y+5),而不是x=x*y+5。自增运算符++和自减运算符--是复合赋值运算符中的特殊情况,它们分别相当于+=和-=。例如,x++包含有赋值运算x+=1,--k包含有赋值运算k-=1。一般地,记θ为一个双目运算符,复合赋值运算的格式为:xθ=e其等价的表达式为:x=xθ(e)注意:当e是一个复杂表达式时,等价表达式的括号是必需的。即e表示表达式,使用复合赋值运算符连接两个运算量时,要把右边的运算量视为一个整体。例如,x*=y+5表示x=x*(y+5),而不是x=x*y+5。自增运算符++和自减运算符--是复合赋值运算符中的特殊情况,它们分别相当于+=和-=。例如,x++包含有赋值运算x+=1,--k包含有赋值运算k-=1。
3.赋值运算的优先级各种赋值运算符都属于同一优先级,且优先级仅比逗号运算符高,比其他所有运算符都低。例如:x=13<y,7+(y=8)表达式中有算术运算符、关系运算符、赋值运算符和逗号运算符,运算顺序依次是y=8→7+(y=8)→13<y→x=13<y→x=13<y,7+(y=8),运算完成后x的值为0,y的值为8,整个表达式是一个逗号表达式,表达式的值为15。如果将表达式改成:x=(13<y,7+(y=8))则整个表达式变成了一个赋值表达式,将右边逗号表达式的值赋给左边变量x。3.赋值运算的优先级各种赋值运算符都属于同一优先级,且优先级仅比逗号运算符高,比其他所有运算符都低。例如:x=13<y,7+(y=8)表达式中有算术运算符、关系运算符、赋值运算符和逗号运算符,运算顺序依次是y=8→7+(y=8)→13<y→x=13<y→x=13<y,7+(y=8),运算完成后x的值为0,y的值为8,整个表达式是一个逗号表达式,表达式的值为15。如果将表达式改成:x=(13<y,7+(y=8))则整个表达式变成了一个赋值表达式,将右边逗号表达式的值赋给左边变量x。
赋值表达式的结合性为从右到左。例如:x=y=17/2运算时先计算17/2,结果为8,将8赋给y,即赋值表达式y=17/2的值为8,再将该赋值表达式的值赋给x。整个运算按照自右至左的顺序计算。赋值表达式的结合性为从右到左。例如:x=y=17/2运算时先计算17/2,结果为8,将8赋给y,即赋值表达式y=17/2的值为8,再将该赋值表达式的值赋给x。整个运算按照自右至左的顺序计算。
4.赋值运算的副作用C语言允许在一个表达式中使用一个以上的赋值类运算符(包括赋值运算符、复合赋值运算符、自增运算符、自减运算符等),使程序简洁,但同时也造成了阅读与理解程序的困难,所以用户应该有限制地使用复合赋值运算符或者用圆括号加以说明。4.赋值运算的副作用C语言允许在一个表达式中使用一个以上的赋值类运算符(包括赋值运算符、复合赋值运算符、自增运算符、自减运算符等),使程序简洁,但同时也造成了阅读与理解程序的困难,所以用户应该有限制地使用复合赋值运算符或者用圆括号加以说明。
赋值运算所引起的副作用表现在不易理解和结果不确定两个方面。(1)不易理解。(2)结果不确定。为了提高程序的可移植性,应当将表达式分解,使之在任何机器上运行都能得到同一结果。赋值运算所引起的副作用表现在不易理解和结果不确定两个方面。(1)不易理解。(2)结果不确定。为了提高程序的可移植性,应当将表达式分解,使之在任何机器上运行都能得到同一结果。
3.2.2 赋值语句用赋值运算符连接两个运算量就得到赋值表达式,在赋值表达式后面加分号就构成赋值语句。赋值语句的一般形式为:变量=表达式;执行赋值语句将实现一个赋值操作,即先计算表达式的值,然后将该值传送到变量所对应的存储单元中。赋值语句与赋值表达式不一样,赋值语句可以作为程序中一个独立的程序行,而赋值表达式是作为一个运算量,可以出现在表达式中。当然,在进行赋值运算时,也实现了一个赋值操作。
3.2.3 赋值时的数据类型转换赋值表达式的类型就是被赋值变量的类型。当赋值运算符两边的数据类型不一致时,C编译系统自动将赋值运算符右边表达式的数据类型转换成与左边变量相同的类型。转换的基本原则是:(1)将整型数据赋给单、双精度变量时,数值不变,但以浮点数形式存储到变量中。(2)将实型数据(包括单、双精度)赋给整型变量时,先舍去实数的小数部分,然后赋给整型变量。如a为整型变量,则执行a=3.145后,a的值为3。
(3)将一个double型数据赋给float变量时,截取其前面7位有效数字,存放到float变量的存储单元(4个字节)中,但应注意数值范围不能溢出。将一个float型数据赋给double变量时,数值不变,有效位数扩展到16位,在内存中以8个字节存储。(4)字符型数据赋给整型变量时,将字符的ASCII码值赋给整型变量。(3)将一个double型数据赋给float变量时,截取其前面7位有效数字,存放到float变量的存储单元(4个字节)中,但应注意数值范围不能溢出。将一个float型数据赋给double变量时,数值不变,有效位数扩展到16位,在内存中以8个字节存储。(4)字符型数据赋给整型变量时,将字符的ASCII码值赋给整型变量。
(5)将一个占字节多的整型数据赋给一个占字节少的整型变量或字符变量(如把一个4字节的long型数据赋给一个2字节的short型变量,或将一个2字节或4字节的int型数据赋给1字节的char型变量),只将其低字节原封不动地送到该变量(即发生截断)。例如:int i=8808; char ch;ch=i;printf(“%d %c\n”,i,ch);程序段运行结果如下:8808 h
在Turbo C 2.0中int型变量i占2个字节,其中存放整型数据8808,二进制存储格式为:0010001001101000截去高8位后,余下的低8位的值是104,它代表字符h。在Visual C++6.0中int型变量i占4个字节,存储整型数据8808的两个高位字节为0,两个低位字节与Turbo C 2.0相同。
(6)将有符号整数赋值给长度相同的无符号整型变量时,按字节原样连原有的符号位也作为数值一起赋值。例如:int a=-1;unsigned int b; b=a;printf(“%d,%u\n”,a,b);在Turbo C 2.0环境中,int型变量占2个字节,a为负数时,按补码存储,其二进制存储格式为16个1,将它转换成unsigned int型后,将最高位的符号位也视为数值位,所以其值为65 535(216-1)。由于b是无符号整型变量,因此,不能用%d输出格式符,而要用输出无符号数的%u格式符。在Turbo C 2.0环境下程序段的运行结果为:-1,65535
在Visual C++ 6.0环境中,int型变量占4个字节,a为负数时,按补码存储,其二进制存储格式为32个1,将它转换成unsigned int型后,将最高位的符号位也视为数值位,所以其值为4 294 967 295(216-1)。在Visual C++ 6.0环境下程序段的运行结果为:-1,4294967295
(7)将无符号整数赋值给长度相同的有符号整型变量时,应使符号位有效,但注意不要超出有符号整型变量的数值范围,否则会出错。例如:unsigned a;int b;a=65535;b=a;printf(“%d\n”,b);在Turbo C 2.0环境下执行b=a时,将a的2个字节(全为1)原样赋给b,由于b的数值范围为-32 768~32 767,显然不能正确反映65 535,对一个有符号的整型数据来说,第1个二进位是1表示此数是一个负数,16位全为1是-1的补码。
在Turbo C 2.0环境下运行,以上程序的输出结果为-1。如果在Visual C++ 6.0环境下运行,将a=65535改为4294967295,输出结果也是-1。以上的赋值规则比较复杂,涉及到数据在计算机内部的表示方法。在刚开始学习时,不必深究转换细则,只要知道基本的概念即可。
3.3 数据输入/输出3.3.1 格式输入/输出1.格式输出函数printf(1)printf函数的调用形式printf函数的作用是将输出项按指定的格式输出。一般调用形式为:printf(格式控制字符串,输出项表)其中,格式控制字符串用来确定输出项的输出格式和需要原样输出的字符。输出项可以是常量、变量或表达式,输出项表中的各输出项之间要用逗号分隔。
注意:① 输出项表中的每一个输出项必须有一个与之对应的格式说明。每个格式说明均以%开头,以一个格式符结束。输出项与格式符必须按照从左到右的顺序在类型上一一匹配。② 当格式符个数少于输出项时,多余的输出项不予输出。若格式符多于输出项时,各个系统的处理不同。Turbo C和Visual C++对于缺少的项都输出不定值。
③ 用户可以根据需要,指定输出项的字段宽度,对于实型数据还可指定小数部分的位数。当指定的域宽大于输出项的宽度时,输出采取右对齐方式,左边填空格。若字段宽度前加一个-号,则输出采取左对齐方式。④ 格式控制字符串可以包含转义字符,如\n、\t等。⑤ 如果想输出字符%,则应在格式控制字符串中用连续的两个百分号(即%%)表示。⑥ 每次调用printf函数后,函数将得到一个整型函数值,该值等于正常输出的字符个数。
(2)格式说明格式说明以字符%开头,格式符结束,中间可以插入附加格式说明符。格式说明的一般形式为:%[-][+][][#][w][.p][h/l/L]格式符其中用方括号括住的内容可以缺省。① 附加格式说明符w:字段宽度说明。-:左对齐标志。+:适用于带符号的数值数据输出,根据数值的正、负,在输出项之前加上符号 + 或 - 。缺省时,只对负数输出负号 - 。空格:若对应输出的数值数据是一个正数,符号用空格代替。若 + 和空格同时出现,空格附加格式说明被略去。 #:适用于八进制数、十六进制数和浮点数格式输出。
.p:小数点和p,其中p为十进数。对于g或e格式输出,p指明输出精度(有效数字位数),缺省时,p=6。对于f格式输出,p指出输出项小数点之后的数字个数,缺省时,p=6。对于s格式输出,p指明最多输出字符串的前p个字符,多余截断,缺省时,字符串的内容全部输出。对于d、i、o、u、x,表示至少出现的数字个数。同字段宽度说明一样,p也可以是一个字符 * ,而实际值由后面一个整数参数的值给出,若该值为负值,相当于没有给出p。
h/l/L:长度修正符h用于格式符d、i、o、u、x,表示对应的输出项是短整型(short)或无符号短整型(unsigned short)。长度修正符l用于格式符d、i、o、u、x,表示对应的输出项是长整型或无符号长整型。长度修正符L用于格式符e、f、g,表示对应的输出项是long double型。
② 格式符d格式符和i格式符:将输出项作为带符号整型数据,并以十进制形式输出。注意,对于long型数据输出,必须在格式符之前插入l 附加格式说明符。o格式符:将输出项作为无符号整型数据,并以八进制形式输出。由于将内存单元中的各位值(0或1)按八进制形式输出,输出的数值不带符号,符号位也一起作为八进制数的一部分输出。
x格式符:将输出项作为无符号整型数据,并以十六进制形式输出。与o格式符一样,符号作为十六进制数的一部分输出。u格式符:将输出项作为无符号整型数据,以十进制形式输出。【例3.2】整型数据的输出格式示例。x格式符:将输出项作为无符号整型数据,并以十六进制形式输出。与o格式符一样,符号作为十六进制数的一部分输出。u格式符:将输出项作为无符号整型数据,以十进制形式输出。【例3.2】整型数据的输出格式示例。
c格式符:将输出项作为字符,以字符形式输出。一个整型数据,只要它的值在0~255范围内,可以用字符形式输出,输出以该整数为ASCII码值的字符,反之,一个字符数据也可以用整数形式输出,输出该字符的ASCII码值。s格式符:用于输出一个字符串。【例3.3】字符型数据和字符串输出格式示例。c格式符:将输出项作为字符,以字符形式输出。一个整型数据,只要它的值在0~255范围内,可以用字符形式输出,输出以该整数为ASCII码值的字符,反之,一个字符数据也可以用整数形式输出,输出该字符的ASCII码值。s格式符:用于输出一个字符串。【例3.3】字符型数据和字符串输出格式示例。
f格式符:以小数形式输出实型数据。小数点后的数字个数为p个,p的默认值为6。若p为0,不显示小数点。格式转换时有四舍五入处理。【例3.4】实型数据输出精度测试。f格式符:以小数形式输出实型数据。小数点后的数字个数为p个,p的默认值为6。若p为0,不显示小数点。格式转换时有四舍五入处理。【例3.4】实型数据输出精度测试。
e格式符:以指数形式输出实型数据。指数形式如下。[-]x.xxxxxe±xx小数点前有1位非零数字,小数点后的数字个数为p-1个,p的默认值为6。若p为0,不显示小数点。格式转换时有四舍五入处理。字符e之后是指数,指数部分至少包含2位数字。若输出值的绝对值不少于1E+100,则指数部分多于2位数字。e格式符:以指数形式输出实型数据。指数形式如下。[-]x.xxxxxe±xx小数点前有1位非零数字,小数点后的数字个数为p-1个,p的默认值为6。若p为0,不显示小数点。格式转换时有四舍五入处理。字符e之后是指数,指数部分至少包含2位数字。若输出值的绝对值不少于1E+100,则指数部分多于2位数字。
g格式符:用于输出实型数据,g格式能自动使用%f和%e表示中的较精确者来表示实数。另外,选择这种输出形式时,有无附加格式说明符#也对输出形式有影响。如#缺省,输出时,小数部分无意义的0及小数点不输出;如有#,则无意义的0及小数点照常输出。【例3.5】实型数据输出格式示例。g格式符:用于输出实型数据,g格式能自动使用%f和%e表示中的较精确者来表示实数。另外,选择这种输出形式时,有无附加格式说明符#也对输出形式有影响。如#缺省,输出时,小数部分无意义的0及小数点不输出;如有#,则无意义的0及小数点照常输出。【例3.5】实型数据输出格式示例。
2.格式输入函数scanfscanf函数的作用是把从键盘上输入的数据传送给对应的变量。一般调用形式为:scanf(格式控制字符串,输入项地址表)其中,格式控制字符串的含义同printf函数。输入项地址表是由若干个地址组成,代表每一个变量在内存中的地址。2.格式输入函数scanfscanf函数的作用是把从键盘上输入的数据传送给对应的变量。一般调用形式为:scanf(格式控制字符串,输入项地址表)其中,格式控制字符串的含义同printf函数。输入项地址表是由若干个地址组成,代表每一个变量在内存中的地址。
格式控制字符串通常包含格式说明,它直接用于解释输入字符序列。控制字符串可以包含:① 空格、制表符或换行,它们使输入读到下一个非空格类字符。② 普通字符(不包括%),它们应与输入串中下一个非空格符相匹配。③ 格式说明,以%开头至格式符结束的字符序列组成。格式说明引导对下一输入字段进行转换。
格式说明的一般形式为:%[*][w][h/l/L]格式符其中用方括号括住的内容可以缺省,下面来说明它们的意义。① *:赋值抑制符,对应的输入项读入后不赋予相应的变量,即跳过该输入值。带星号的格式说明不对应输入项存储地址,用它来跳过一个输入数据项。
② w:字段宽度说明,表示输入数据项的字段宽度。若实际输入字段宽度小于w,取实际宽度。除格式符c外,输入字段定义为从下一个非空格字符起(因此可能跳过若干个空格符、制表符或换行符),到一个与所解释类型相矛盾的字符,或到由字段宽度说明的长度为止。
③ h/l/L:h修饰格式符d、i、o、u、x,表示读入的整数转换成短整型存储;l修饰格式符d、i、o、u、x时,表示读入的整数转换成长整型存储;l修饰格式符e、f、g时,表示读入的实数是按double型存储。L修饰格式符e、f、g时,表示读入的实数是按long double型存储。
函数scanf()的格式符很多,下面详细介绍常用的输入格式符。① d格式符:用来输入整型数据。将输入数据作为十进制形式的整型数据。将其转换成二进制形式后,存储到对应数据存储地址中。一般从键盘读入数据,不指定输入数据项的字段宽度,数据项与数据项之间用空格符、制表符或回车分隔。