预计阅读本页时间:-
我们已经在前几章里多次使用了术语表达式和语句,现在该进一步学习它们的意思了。语句组成了C的基本的程序步骤,并且大多数语句由表达式构造而成。这一事实建议您先了解一下表达式。
5.4.1 表达式
表达式(expression)是由运算符和操作数组合构成的(回忆一下,操作数是运算符操作的对象)。最简单的表达式是一个单独的操作数,以此作为基础可以建立复杂的表达式。下面是一些表达式:
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
正如您所看到的,操作数可以是常量、变量或者是二者的组合。一些表达式是多个较小的表达式的组合,这些小的表达式被称为子表达式(subexpression)。例如,c/d是第4个例子的子表达式。
每一个表达式都有一个值
C的一个重要的属性是每一个C表达式都有一个值。为了得到这个值,您可以按照运算符优先级描述的顺序来完成运算。我们所列出的前几个表达式的值很明显,但是有=的表达式的值是什么呢?那些表达式与=左边的变量取得的值相同。所以,表达式q=5*2作为一个整体的值为10。表达式q>3呢?这样的关系表达式如果条件为真取得的值为1,如果条件为假取得的值为0。表5.3中是一些表达式和它们的值:
表5.3 一些表达式和它们的值
表 达 式 | 值 |
---|---|
-4+6 | 2 |
c=3+8 | 11 |
5>3 | 1 |
6+(c=3+8) | 17 |
最后的表达式有点奇怪!然而,它在C中是完全合法的(但是不建议使用),因为它是两个子表达式的和,每一个子表达式都有一个值。
5.4.2 语句
语句(statement)是构造程序的基本成分。程序(program)是一系列带有某种必需的标点的语句集合。一个语句是一条完整的计算机指令。在C中,语句用结束处的一个分号标识。所以:
只是一个表达式(它可能是一个较大语句的一个部分),而:
是一个语句。
什么构成了一条完整的指令?首先,C把任何后面加有一个分号的表达式看作是一个语句(它们被称为表达式语句)。所以,C将不反对像下面的各行:
但是这些语句对您的程序不做任何事情,不能被认为是有作用的语句。更典型地,语句会改变值和调用函数:
尽管一个语句(或者至少是一个有作用的语句)是一条完整的指令,但不是所有的完整的指令都是语句。考虑下面的语句:
在此语句中,子表达式y=5是一个完整的指令,但是它只是一个语句的一部分。因为一条完全的指令不必是一个语句,所以分号被用来识别确实是语句的指令。
到目前为止,您已经遇到了4种语句。程序清单5.13给出了使用这4种语句的简短的例子。
程序清单5.13 addemup.c程序
我们讨论程序清单5.13。此时,您一定很熟悉声明语句了。但是,我们将提醒您它用于建立变量的名字和类型并导致为它们分配内存空间。注意一个声明语句不是一个表达式语句。也就是说,如果您从声明里去掉分号,您所得到的不是一个表达式,也不具有一个值:
赋值语句(assignment statement)被许多程序广为使用:它为一个变量分配一个值。它的结构是一个变量名,变量后面紧跟着一个赋值运算符,赋值运算符后跟一个表达式,表达式后面跟上一个分号。注意在while循环语句中包含了一个赋值语句。赋值语句是表达式语句的特例。
函数语句(function statement)引起函数的执行。在这个例子里,调用了printf( )函数来打印结果。while语句有三个不同的部分(请参见图5.6)。首先是关键字while,然后是在圆括号里的一个判断条件,最后是满足判断条件时将执行的语句。包含在循环里的可以是一个像本例中那样的简单语句,这个简单语句不需要用花括号来划分出来;也可以像以前的例子中那样是一个复合语句,复合语句需要有花括号。后面马上就要讨论有关复合语句的内容。
图5.6 一个简单的while循环的结构
while语句属于一类有时被称为“结构化语句”(structured statement)的语句,因为它们的结构比一个简单的赋值语句复杂。在后面的章节里,我们将遇到许多其他的结构化语句。
副作用和顺序点
现在我们再讨论一些C的术语。副作用(side effect)是对数据对象或文件的修改。例如,语句:
的副作用是将变量states的值设置为50。这是副作用?这看起来更像是主要目的!然而,从C的角度来看,主要目的是对表达式求值。给C一个表达式4+6,C将计算它的值为10。给C一个表达式states=50,C将计算它的值为50。计算这个表达式的副作用就是把变量states的值改变为50。跟赋值运算符一样,增量运算符和减量运算符也有副作用,它们主要由于副作用而被使用。
一个顺序点(sequence point)是程序执行中的一点;在该点处,所有的副作用都在进入下一步前被计算。在C中,语句里的分号标志了一个顺序点。它意味着在一个语句中赋值运算符、增量运算符及减量运算符所做的全部改变必须在程序进入下一个语句前发生。在后续章节中我们将要讨论的一些运算符也有顺序点。任何一个完整的表达式的结束也是一个顺序点。
什么是完整的表达式呢?一个完整的表达式(full expression)是这样一个表达式——它不是一个更大的表达式的子表达式。完整表达式的例子包括一个表达式语句里的表达式和在一个while循环里作为判断条件的表达式。
顺序点帮助阐明后缀增量动作何时发生。例如,考虑下面的代码:
有时C的初学者会设想在本程序中“先使用该值,然后增加它的值”的意思是在使用了printf( )语句后再增加guest的值。然而,因为guests++<10是while循环的判断条件,所以它是一个完整表达式,这个表达式的结束就是一个顺序点。因此,C保证副作用(增加guest的值)在程序进入printf( )前发生。同时使用后缀形式保证了guest在与10比较后才增加。
现在考虑这个语句:
表达式4+x++不是一个完整表达式,所以C不能保证在计算子表达式4+x++后立即增加x。这里,完整表达式是整个赋值语句,并且分号标记了顺序点,所以C能保证的是在程序进入后续语句前x将被增加两次。C没有指明x是在每个子表达式被计算后增加还是在整个表达式被计算后增加,这就是我们要避免使用这类语句的原因。
5.4.3 复合语句(代码块)
复合语句(compound statement)是使用花括号组织起来的两个或更多的语句;它也被称为一个代码块(block)。shoes2.c程序使用一个代码块以使while语句包含多个语句。比较下面的两个程序段:
在程序段1中,只有赋值语句包含在while循环中。在没有花括号的情况下,while循环语句的范围是从while到下一个分号。printf( )函数只在循环结束后被调用一次。
在程序段2中,花括号确保两个语句都是while循环的一部分,所以每次循环执行时都将调用printf( )。根据while语句的结构(请参见图5.7),整个复合语句被认为是一个语句。
图5.7 一个具有复合语句的while循环