理解C语言——从小菜到大神的晋级之路(5)——程序流程控制

来源:互联网 发布:java时间轴处理 编辑:程序博客网 时间:2024/06/10 11:21

   本期视频点击这里

        C语言中的控制流语句用于决定代码中各个语句的执行顺序。通常程序的运行次序的结构有顺序结构、选择结构和循环结构。


1、顺序结构


        在正常情况下,C程序都是从main函数的起始位置开始,按由上到下顺序执行。程序执行以语句为单位。通常一个表达式之后加一个分号“;”构成一条语句,如赋值表达式“x = 1”加一个分号就构成了赋值语句“x = 1;”。除了单条的语句之外,使用一对大括号{}组合的多条语句可以构成一条复合语句。在语法上,复合语句和单条语句等价,只是不以分号结尾。

输入输出函数:

        C语言中最简单的输入输出函数有printf和scanf函数,分别实现向控制台格式化输出和从控制台格式化输入数据。
(1)printf的原型为:

int printf ( const char * format, ... );


        传入该函数的是可变参数,作用是将参数format所指向的C字符串输出到标准输出stdout中。参数format中可以包含显式字符和格式标识符,格式标识符通常由%开头,并用不同的字符表示数据应该以怎样的格式写入format字符串中并输出。其中常用的有:

10进制有符号整数:%d
10进制无符号整数:%u
8进制无符号整数:%o
16进制无符号整数:%x, %X, (小写/大写表示)
10进制浮点数(小数点表示):%f
10进制浮点数(科学计数法):%e,%E
字符型数据:%c
字符串数据:%s

        除了表示数据类型外,格式标识符还可以附带其他信息。完整的格式标识符原型为:
%[flags][width][.precision][length]specifier

        其中的可选部分包含多种信息,如:
  • flag:可取值为:+、-、#、0和空格
  • width:可取某个数值或*。数值表示输出数据的最小宽度,*表示宽度不表示在标识符中而由后续的参数指定。
  • .precision:表示数据输出的精度。对于整型数据表示数据输出的位数,对于浮点数则用于表示小数点后输出的位数(默认为6)
  • length:改变数据类型的长度。常用取值有hh、h、l、ll、和L等。

        当printf执行成功后,函数返回输出的总字符个数;若执行失败,则返回错误信息。例子:
/* printf example */#include <stdio.h>int main(){   printf ("Characters: %c %c \n", 'a', 65);   printf ("Decimals: %d %ld\n", 1977, 650000L);   printf ("Preceding with blanks: %10d \n", 1977);   printf ("Preceding with zeros: %010d \n", 1977);   printf ("Some different radices: %d %x %o %#x %#o \n", 100, 100, 100, 100, 100);   printf ("floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);   printf ("Width trick: %*d \n", 5, 10);   printf ("%s \n", "A string");   return 0;}

(2)scanf函数的声明为
int scanf ( const char * format, ... );

        该函数从命令行窗口中读取输入的数据,并根据format参数保存到对应的内存地址中。保存数据的内存地址必须是已经有效分配好的、有写入权限的内存区域。
        同printf函数类似,format也是一个字符串格式。在内容上,format字符串中可以包含三种内容:
  • 空字符:在遇到第一个非空字符之前,所有的空字符都将被忽略。
  • 非空字符(除格式标识):函数将读取输入的字符同format中的这个字符进行比较,如果一致那么将丢弃该字符并读取下一个,如果不一致则会失败,不会继续读取后续的输入。
  • 格式标识:同printf类似,格式标识指定了输入数据的类型。每一个格式标识同后面的参数指定的内存地址一一对应。
        格式标识符的原型为:
%[*][width][length]specifier

  • *:表示字符从输入数据流中读取,但是被忽略,不被存入格式标识符对应的内存中。
  • width:读入当前格式标识符对应位置变量的最大字符数量。
  • lengh:同printf中的lengh类似,改变对应存储位置的数据类型

例子:

/* scanf example */#include <stdio.h>int main (){  char str [80];  int i;  printf ("Enter your family name: ");  scanf ("%79s",str);   printf ("Enter your age: ");  scanf ("%d",&i);  printf ("Mr. %s , %d years old.\n",str,i);  printf ("Enter a hexadecimal number: ");  scanf ("%x",&i);  printf ("You have entered %#x (%d).\n",i,i);   return 0;}

2、选择结构


        选择结构是程序的基本结构之一,实现了根据不同条件实现不同代码的功能。选择结构是由实现逻辑判断的选择语句实现的。根据逻辑判断的结果不同,选择结构执行的流程也不同。实现选择结构通常有两种语句:if语句和switch语句。

(1)if语句
        C语言的if语句是最简单的选择语句,if关键字后面的括号中表示判断条件表达式,后面接一条语句或复合语句。当判断条件表达式为真(即表达式的值为非0)时,执行下面的语句;如果判断条件表达式为假(即表达式的值为0),则跳过后面的语句不执行。 其实现方法是
if(a == 0/*判断条件*/){     printf("True");   //执行语句}

        if还可以接else实现二选一的操作,在if-else选择语句中,else部分是非必须的,应根据需要选择是否添加else部分。 实现方法是

if(a == 0){     printf("True"); //表达式成立时执行}else{     printf("False");//表达式不成立时执行}


        另外,为了保持良好的编程风格,我们推荐无论是if还是else后面都是用大括号构成的符合语句,即使里面只有简单的一条语句也不例外。如果不适用大括号,则可能会面临if和else关键字匹配的混乱,如

if(x == 0)     if(y == 1)          a = n;     else          a = m;

        在该段程序中,else部分一定是同if(y == 1)部分匹配的,二者共同构成一条if-else语句。如果希望else同更外层的if匹配,则必须使用大括号{}:

if(x == 0){     if(y == 1)          a = n;}else     a = m;

             if和else匹配的原则是,逐条语句(包括复合语句)向上查找,与找到的第一个if匹配。


        在实际使用的过程中,经常会遇到多级判断的情况。此时如果使用多层嵌套的if-else语句则会相当繁琐。所以C语言提供了else if语句实现级联的判断。在级联的判断中,每个判断条件都会被依次求值,只要有一个满足条件,就会执行对应的程序,并终止整个选择过程。使用方法如下:
if( x == 0)     a = 2;else if(x == 1)     a = 4;else if(x == 3)     a = 6;else if(x == 4)     a = 8;else     a = 10;

(2)switch语句
        有时候当多级判断的条件相近时(比如上例),多层的if-else也显得比较繁琐。在测试表达式是否与一些常量数值中的某一个匹配并执行相应的分支动作时,switch语句是一个更好的选择。switch语句的使用方法如下:
switch(表达式){case 常量值1:      执行语句;case 常量值2:      执行语句;case 常量值3:      执行语句;default:     执行语句;}

        在执行switch语句时,首先计算表达式的值。当表达式的某一个值与某个分支匹配,那么语句将从该分支开始执行;如果没找到任何匹配,则从default分支开始执行;如果没有default分支且没有任何匹配,则该switch语句不执行任何操作。各个分支的排列没有任何影响。
        需要注意到一点是,switch语句通常不会只执行一个分支,而是以某一个分支作为切入点依次执行。如果我们需要只执行某一个分支,那么需要在每一个分支的执行语句中包含break;来跳出。

3、循环结构


        循环结构实现将一段代码反复循环运行多次的功能。有了循环结构,我们就没有必要在将需要重复执行的代码反复拷贝粘贴多次,既简单又方便。C语言中实现循环结构总共有三种语句,即while、do-while和for。

(1)while

        while结构实现方式如:
while(表达式){     循环体;}

        while循环在每次执行前先计算表达式的值。当表达式的值非0,则执行循环体的语句,完成后继续计算表达式的值,如此循环,直到表达式的值为0,此时跳出循环执行后续部分。

(2)do-while

        do-while结构的实现方式如:
do{     循环体;}while(表达式);

        在使用上,do-while循环同while循环类似,只是执行顺序上稍有不同:do-while循环首先会执行循环体,然后判断表达式是否成立。也就是说,无论表达式是否成立,循环体至少会被执行一次。

(3)for循环

        for循环通常是这三种循环结构中最为常用的一种。实现方式如:
for(表达式1; 表达式2; 表达式3){     循环体;}

        执行时,首先计算表达式1的值,再计算表达式2的值,如果表达式2为假,则直接跳出循环。如果表达式2为真,则执行循环体,然后计算表达式3,再次计算表达式2并判断,如此循环往复,直到表达式2的值为0。
一般在使用时,通常将表达式1用作初始化循环变量,表达式2用于控制循环流程,表达式3用于修改循环变量,如:
for(int x = 0; x < 10; x++){     printf("Number x: %d\n", x);}

(4)异常循环
       通常异常循环主要有以下几种:
  • 中止本次循环:在某一次循环中触发了某种条件,导致本次循环不再继续执行,而是重新判断条件并执行下一次循环。实现该功能需在循环体中包含continue语句,当程序执行到continue时,本次循环将中止,随后开始执行下一次循环。
  • 中止整个循环:在某一次循环中触发了某种条件,导致整个循环过程中止,不再执行后面的循环。该功能需要在循环体中使用break语句实现。当程序执行到break时循环直接跳出,执行循环后面的语句。
  • 死循环:死循环指的是退出条件永远无法满足,始终在执行的循环过程。死循环通常由代码的错误产生,并且会导致程序的bug。不过在某些场合中会特别定义死循环来实现一些特殊的场景,如Windows开发中的消息循环,在没有接收到退出消息是将作为一个死循环一直执行。


4、无条件跳转语句

C语言中可以为任何语句前面加上标号用于定义语句的位置。格式为:
flag: printf("这是一条语句.\n");

        定义了标号之后,就可以使用无条件跳转语句跳转到该标号所在的位置。无条件跳转语句goto是一个比较特殊的语句,当执行到goto语句时,程序将无条件跳转到标号的位置:
goto flag;

        goto语句可以完全改变程序的执行流程。如果滥用将极大破坏程序的结构和可读性,因此应尽量避免直接使用,而优先选择上述三种常用的结构实现流程控制。不过在某些特殊情况下,使用goto可以大大简化代码的结构和流程,此时也不应该对goto语句过分排斥。

0 0
原创粉丝点击