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

2023-11-23 04:38

本文主要是介绍理解C语言——从小菜到大神的晋级之路(5)——程序流程控制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

   本期视频点击这里

        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;elsea = m;

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

if(x == 0)
{if(y == 1)a = n;
}
elsea = 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;
elsea = 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语句过分排斥。

这篇关于理解C语言——从小菜到大神的晋级之路(5)——程序流程控制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/415393

相关文章

C语言逗号运算符和逗号表达式的使用小结

《C语言逗号运算符和逗号表达式的使用小结》本文详细介绍了C语言中的逗号运算符和逗号表达式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 在C语言中逗号“,”也是一种运算符,称为逗号运算符。 其功能是把两个表达式连接其一般形式为:表达

Go语言实现桥接模式

《Go语言实现桥接模式》桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化,本文就来介绍一下了Go语言实现桥接模式,感兴趣的可以了解一下... 目录简介核心概念为什么使用桥接模式?应用场景案例分析步骤一:定义实现接口步骤二:创建具体实现类步骤三:定义抽象类步骤四:创建扩展抽象类步

GO语言实现串口简单通讯

《GO语言实现串口简单通讯》本文分享了使用Go语言进行串口通讯的实践过程,详细介绍了串口配置、数据发送与接收的代码实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录背景串口通讯代码代码块分解解析完整代码运行结果背景最近再学习 go 语言,在某宝用5块钱买了个

GO语言zap日志库理解和使用方法示例

《GO语言zap日志库理解和使用方法示例》Zap是一个高性能、结构化日志库,专为Go语言设计,它由Uber开源,并且在Go社区中非常受欢迎,:本文主要介绍GO语言zap日志库理解和使用方法的相关资... 目录1. zap日志库介绍2.安装zap库3.配置日志记录器3.1 Logger3.2 Sugared

Go语言中如何进行数据库查询操作

《Go语言中如何进行数据库查询操作》在Go语言中,与数据库交互通常通过使用数据库驱动来实现,Go语言支持多种数据库,如MySQL、PostgreSQL、SQLite等,每种数据库都有其对应的官方或第三... 查询函数QueryRow和Query详细对比特性QueryRowQuery返回值数量1个:*sql

深入理解Redis线程模型的原理及使用

《深入理解Redis线程模型的原理及使用》Redis的线程模型整体还是多线程的,只是后台执行指令的核心线程是单线程的,整个线程模型可以理解为还是以单线程为主,基于这种单线程为主的线程模型,不同客户端的... 目录1 Redis是单线程www.chinasem.cn还是多线程2 Redis如何保证指令原子性2.

深入理解MySQL流模式

《深入理解MySQL流模式》MySQL的Binlog流模式是一种实时读取二进制日志的技术,允许下游系统几乎无延迟地获取数据库变更事件,适用于需要极低延迟复制的场景,感兴趣的可以了解一下... 目录核心概念一句话总结1. 背景知识:什么是 Binlog?2. 传统方式 vs. 流模式传统文件方式 (非流式)流

深入理解Go之==的使用

《深入理解Go之==的使用》本文主要介绍了深入理解Go之==的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录概述类型基本类型复合类型引用类型接口类型使用type定义的类型不可比较性谈谈map总结概述相信==判等操作,大

GO语言中gox交叉编译的实现

《GO语言中gox交叉编译的实现》本文主要介绍了GO语言中gox交叉编译的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、安装二、使用三、遇到的问题1、开启CGO2、修改环境变量最近在工作中使用GO语言进行编码开发,因

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础