
3.1 C语言的语句类型
C语言所提供的语句主要有:
(1)表达式语句,比如x=y+z;。
(2)复合语句(用花括号括起来的语句),比如{…}。
(3)函数调用语句,比如printf("x=%d",x);。
(4)空语句。
(5)条件语句。
(6)循环语句。
(7)开关语句。
(8)转向语句。
(9)返回语句。
(10)循环中止语句。
(11)循环短路语句。
C语言的语句可以分为简单语句和构造语句两大类。
简单语句是不包含子语句的语句,如表达式语句、转向语句、返回语句等。
构造语句是包含子语句的语句。子语句可以是简单语句,也可以是复合语句、条件语句、循环语句、开关语句等。
C语言是一种结构化程度很高的语言,它所提供的语句的结构,如顺序结构、条件分支结构、循环结构,保证了程序执行时的流程控制,常规的就是三种流程控制:顺序执行、条件转移、循环重复。
这里先介绍几种比较简单的语句形式。
3.1.1 表达式语句
一个表达式后面加上一个分号“;”,就形成了一个表达式语句。用得最多的就是由赋值表达式构成的赋值语句。例如“x=300”是一个赋值表达式,而“x=300;”则是一个赋值语句。
C语言中大部分语句都是表达式语句。
任何表达式加上分号都会成为语句,表达式语句应有其实际意义,通过对该语句的执行,会改变某些变量的值,或者执行某个函数。例如下面这些语句是合法的,也是有实际意义的。

但是,可能某些表达式语句并没有调用函数,也没有改变某些变量的值,例如:

这样的语句显然没有什么实际意义,虽然也是合法的表达式语句,但是在实际编写程序的时候,应该尽量注意不要出现这样的语句。
3.1.2 复合语句
C语言中经常需要把几个语句作为一个语句来使用,这种语句被称为复合语句。它用一对花括号“{}”把多个语句组合成为一个语句。复合语句在语法上等价于一个简单语句,并且在程序中作为一个简单语句来使用。在循环语句、条件语句、开关语句等处经常需要用到复合语句,因为在很多场合规定只能有一个语句,但往往需要多个语句才能完成任务,这时选用复合语句是最好的选择。
复合语句的子语句可以是简单语句、构造语句,也可以是复合语句,形成多层复合语句的嵌套。
C语言对复合语句的嵌套层数没有限制。
注意
复合语句的右花括号后面,不要再加上“;”,因为右花括号本身就意味着一个语句的结束。
复合语句也可以被看成是一个分程序,C语言对定义变量的位置没有限制,可以在复合语句的花括号内进行变量定义。在复合语句内定义的变量,其作用域仅限于该复合语句之内。例如:

变量x、y和i仅在这个复合语句内有效,离开这个复合语句,这三个变量就无效。
3.1.3 空语句
空语句仅包含一个分号“;”,它什么也不做,但它是一种语句。
其作用有两点:
一般在循环语句中使用空语句,提供一个不执行任何操作的空循环体。例如:

或:

由于“;”是一个空语句,应防止无意之中加上一个“;”,而导致程序产生错误。例如我们想写一个程序:

但如果无意中在圆括号后面多加一个“;”,成为:

这使循环体成为了空循环体,不会执行原来正确的循环体,从而产生了错误的结果。
3.1.4 转向语句和语句标号的使用
转向语句(goto语句)是无条件转移语句,它的形式为:

在程序中一旦碰到它,即刻转移到它后面的语句标号所指定的目标语句上去。
在结构化的程序设计中,为了保持良好的程序结构,应该避免使用goto语句。因为它的跳转,会使程序流程变得跟“麻花”一样糟糕。在这里我们只是为了便于理解后面的内容,简单地介绍一下它的功能与作用。不推荐在编程中使用它,除非在非常有必要的情况下。
在C语言中,任何语句都可以有前缀部分“:”。
这个标识符被称为语句标号,它是用来指示语句在程序中的位置。标号所指明的语句通常被用于goto语句的转移目标。
由于语句标号是一种标识符,所以它的命名规则和变量的命名规则相同。
语句标号后面应是冒号“:”,而不是分号“;”,例如:

是正确的,而:

则是错误的。
一般情况下,goto语句总是和语句标号配合起来使用的。goto语句用来跳转,而标号则指明跳转的目标所在。例如:

(1)标号和变量一样,有其作用域,也即作用的范围。对于函数来说,标号的作用域就限于当前这个函数。C语言规定,标号可以附加到与goto语句属于同一函数的另外一条语句上去。例如:

由于语句“goto lp1;”和语句标号“lp1:”都在同一个函数内,所以是合法的。
如果语句“goto lp1;”和语句标号“lp1:”不在同一个函数内,比如“goto lp1;”语句在main主函数内,而语句标号“lp1:”在子函数比如sun(x,y)内,它们二者不在同一个函数内,所以不能完成跳转,这样使用是错误的。
(2)对于复合语句来说,标号的作用域是当前层次的复合语句。标号可以附加到与goto语句属于同一层次的复合语句上。
用goto语句把程序流程从复合语句的内层转移到复合语句的外层,且属于同一函数的语句是允许的。但是,在大多数系统中,用goto语句把程序流程从复合语句的外层转移到复合语句的内层某处是不合法的。对于有多层嵌套的复合语句来说,一定要注意标号的作用域。
概括起来说,就是“同一函数,同一层次可以跳转”。
(3)如果语句标题和goto语句属于同一个函数,可是语句标号和goto语句不在同一复合语句中。这时如果goto语句处在内层,语句标号处在外层,由内层跳转向外层也是合法的。概括说就是“同一函数,不同层次,允许由内向外跳转”。
(4)goto语句可以向前跳转,也可以向后跳转。
向后跳转就是跳过一段程序,副作用一般不大。而向前跳转就形成了一个循环。由于goto语句是无条件转移,所以向前跳转时会形成死循环。在向前跳转的程序段中,必须有一个判断语句能够使程序跳出循环。
注意
尽管原理是这样,但实际应用中尽量不要使用goto语句,以免造成死循环。
为了理解,仅举一例。比如利用if和goto语句构成的循环求n!。
【例3.1】利用if和goto语句构成的循环求n!。

之所以介绍goto语句,是为了深层理解C语言。在汇编语言中就是利用语句标号和一系列跳转语句来实现循环结构的。C语言可以看作是汇编语言的升级,但是在C语言中尽量不要使用goto跳转语句。
(5)在一些特殊的场合下不得不用goto语句,这也是goto语句在C语言中的唯一用处。
例如,当程序需要从嵌套很深的多层循环中转移到外层时,必须使用goto语句。如果仅仅使用循环中止语句(break语句),只能使程序转移到外一层循环处。如果从最内层转移到最外层,就要使用多处break语句一层一层转移,并且每层都必须有条件语句(if语句),显然是很不方便的。而这时使用goto语句的话,只需要一个语句。例如:

在这个例子中,由于需要从三层循环中跳到最外层,所以使用goto语句最方便。如果使用break语句,则要复杂得多。例如:


在这里如果使用break语句,需要使用多个break语句不说,还会出现判断条件将会因具体程序的不同而相当复杂,特别是语句标号并不紧跟着循环语句,用break语句跳出循环之后仍然需要使用goto语句跳转到语句标号上去。
再来看goto语句的几个实例。
【例3.2】goto语句构成程序跳转。

总之,关于goto语句一定要慎重使用,最好不用。