C语言之分支语句和循环语句

前言

一、什么是语句?

二、分支语句(选择结构)

2.1 if语句

2.2 switch语句

三、循环语句

3.1 while循环

3.2 break与continue语句

3.3 getchar()与putchar()

3.3.1 缓冲区

3.4 for循环

3.4.1 一些for循环的变种

3.5 do...while循环

四、goto语句


前言

本章将详细介绍分支语句(选择结构)和循环语句。


一、什么是语句?

C语言语句可分为以下五类:

  1. 表达式语句
  2. 函数调用语句
  3. 控制语句
  4. 复合语句
  5. 空语句

本博客将介绍控制语句。

控制语句用于控制程序的执行流程,以实现程序的各种结构方式(在C语言中有三种结构:顺序结构、选择结构、循环结构),它们又特定的语句定义符组成,C语言中有九中控制语句。

可以分为以下三类:

  1. 条件判断语句(分支语句):if语句、switch语句;
  2. 循环执行语句:do...while语句、while语句、for语句;
  3. 转向语句:break语句、goto语句、continue语句、return语句。

二、分支语句(选择结构)

什么是分支语句,通俗来讲就是选择。

2.1 if语句

if语句为C语言中一种最常见的分支语句,其语法如下:

语法结构:
//单分支
if(表达式)语句;//双分支
if(表达式)语句1:
else语句2;//多分支
if(表达式1)语句1;
else if(表达式2)语句2;
else语句3;

其中表达式最终只有两个值,分别为真和假,C语言中规定,0为假,非0为真,下面用代码分别演示:

int main()
{int age = 0;scanf("%d", &age);//单分支if (age < 18){printf("未成年\n");}//双分支if (age < 18){printf("未成年\n");}else{printf("成年\n");}//多分支if (age < 18){printf("少年\n");}else if(age>=18 && age<30){printf("青年\n");}else if (age >= 30 && age < 50){printf("中年\n");}else if (age >= 50 && age < 80){printf("老年\n");}else{printf("寿星\n");}return 0;
}

在C语言中,if语句中为单条语句时可以不加大括号{},多条语句必须加大括号{},但我建议不管是单条还是多条语句,都加上大括号{},养成编程好习惯。

另外,我们还要区分以下多分支语句的情况:

//区分if...if 与 if else...if的区别
int main()
{int age = 0;scanf("%d", &age);//if...if多分支if (age < 18){printf("少年\n");}if (age >= 18 && age < 30){printf("青年\n");}if (age >= 30 && age < 50){printf("中年\n");}if (age >= 50 && age < 80){printf("老年\n");}else{printf("寿星\n");}//if else if多分支if (age < 18){printf("少年\n");}else if (age >= 18 && age < 30){printf("青年\n");}else if (age >= 30 && age < 50){printf("中年\n");}else if (age >= 50 && age < 80){printf("老年\n");}else{printf("寿星\n");}return 0;
}
多分支if...ifif  else..if
功能提供多种情况提供多种情况
执行方式逐一执行,每条if语句都会进行判断直接进入为真的语句,并不会逐一执行

看看下列代码:

//悬空else
int main()
{int a = 0;int b = 2;if (a == 1)  //1if (b == 2) //2printf("hehe\n");elseprintf("haha\n");return 0;
}

你觉得打印结果是什么呢?打印结果什么都没有。为什么呢?这是因为代码风格的问题,在使用if语句时,必须要注意的一个问题是else和if的匹配问题,上述代码中的else是与第2个if匹配的,因为在C语言中规定,else总是与离得最近的if匹配,故什么都没有打印,下列为改正代码:

int main()
{int a = 0;int b = 2;if (a == 1){if (b == 2)printf("hehe\n");}else{printf("haha\n");}return 0;
}

因此,适当的加上大括号{},能更好的理解代码,以上的else将与第1个if匹配,这样就通俗易懂了。

并且,在书写if语句时,要编写逻辑清晰的代码,列如以下代码:

//代码1
if(condition)
{return x;
}
return y;//代码2
if(condition)
{return x;
}
else
{return y;
}//代码3
int num = 1;
if(num == 5)
{printf("hehe\n");
}//代码4
int num = 1;
if(5 == num)
{printf("hehe\n");
}

上述代码中,逻辑是相同的,但代码2与代码4的风格更好,逻辑性更强,不容易出错。

当我们想用变量与常量作为表达式时,推荐用代码4形式,不容易出错:

int num = 1;
if (num = 1)
{printf("haha\n");
}

程序不会报错,但逻辑错误

程序会报错,这样可以防止我们出错,故推荐用以下形式:

int num = 1;
if(1 == num)
{printf("haha\n");
}

2.2 switch语句

switch适合用于处理多分支情况,常常用于有唯一取值的情况,而if语句更经常用于处理范围。

语法结构:

switch(整数表达式)
{case 整形常量表达式:语句;.....
{

比如:

输入1输出星期一
输入2输出星期二
输入3输出星期三
输入4输出星期四
输入5输出星期五
输入6输出星期六
输入7输出星期七
//switch语句
int main()
{int num = 0;scanf("%d", &num);switch (num){case 1:printf("星期一");break;case 2:printf("星期二");break;case 3:printf("星期三");break;case 4:printf("星期四");break;case 5:printf("星期五");break;case 6:printf("星期六");break;case 7:printf("星期天");break;default:printf("输入错误\n");break;}return 0;
}

语句中的break非常重要,如果我们少加或者不加break,上述代码将会执行不同的结果:

//switch语句
int main()
{int num = 0;scanf("%d", &num);switch (num){case 1:printf("星期一");case 2:printf("星期二");break;case 3:printf("星期三");break;case 4:printf("星期四");break;case 5:printf("星期五");break;case 6:printf("星期六");break;case 7:printf("星期天");break;default:printf("输入错误\n");break;}return 0;
}

当我们输入1时,将会打印星期一星期二,这是因为我们在case1中没有加break,将会一直执行,直到遇到break,跳出。故我们要养成在每一个语句项加上break的情况,但面对不同情况我们也要懂得随机应变,比如以下需求:

输出工作日和周末:

//switch语句
int main()
{int num = 0;scanf("%d", &num);switch (num){case 1:case 2:case 3:case 4:case 5:printf("工作日");break;case 6:case 7:printf("周末");break;default:printf("输入错误\n");break;}return 0;
}

很多人会疑问,switch的default语句是必须得吗?default语句是与case不匹配后执行的语句,default语句其实也不是必须的,但我们一般会加上,这是一种良好的编程习惯。


对于switch语句,我们要关注以下两个方面:

  1. switch(整形表达式)
  2. case 整形常量表达式

switch()中只能是整形,不能是其它类型,有人会问,为什么也看见可以放字符型呢?因为字符也是整形的一类。

case 后跟整形常量表达式,注意是常量,不能放变量。


三、循环语句

while循环
for循环
do...while循环

while循环、for循环、do...while循环有一个共同的特点:

判断部分总是比循环体多执行一次。

3.1 while循环

while循环语法结构while(表达式){循环语句;
}

while循环语句执行流程:

3.2 break与continue语句

作用作用域
break用于永久终止循环while、for、do...while、switch
continue跳过本次循环,执行下一次循环while、for、do...while

在for循环、while循环、do...while循环中,break的功能是一样的。

但对于continue,在for循环、while循环、do...while循环中根据代码情况是有一定的差异:

while循环与do...while循环情况相同

#include<stdio.h>
int main()
{int i = 1;while(i <= 10){if(5 == i)continue; //此时的continue将跳过本次循环,执行下一次循环,但控制条件i,在continue //语句的后面,因此该程序将进入死循环状态i++;printf("%d ", i);}do{if(5 == i)continue; //此时的continue将跳过本次循环,执行下一次循环,但控制条件i,在continue //语句的后面,因此该程序将进入死循环状态i++;printf("%d ", i);}while(i <= 10);for(i=1; i<=100; i++){if(5 == i)continue;  // 此时continue将跳过本次循环,执行下一次循环,for循环中的控制条件i是 // 不受影响的printf("%d ", i);}
}

3.3 getchar()与putchar()

作用返回值
getchar()从键盘读取字符

返回类型为int,

成功:读取到字符后,返回该字符的ASCII码值

失败:读取返回EOF --> -1

putchar()打印字符int类型

3.3.1 缓冲区

        概念:我们进行从键盘输入时,并不是直接传递到了程序上,先是存放在缓冲区中。

//代码什么意思?#include <stdio.h>int main(){int ch = 0;while ((ch = getchar()) != EOF)putchar(ch);return 0;}

该代码是一种多组输入的形式,重复在键盘上进行输入然后读取打印,直到输入失败EOF结束。

 想要结束:Ctrl+z,具体的原理图如下:第一次缓冲区里有A\n,putchar()读取走了A,又继续输入B\n,此时缓冲区里有\nB\n,然后又进行读取,因此可以看到打印结果是字符换行字符换行.....

因此,getchar()常常用来清空缓冲区:

int main()
{printf("请输入密码:>");char password[20] = { 0 };scanf("%s", password);//清理缓冲区getchar()printf("请确认密码(y/n):>");int ch = getchar();if (ch == 'y'){printf("确认成功\n");}else{printf("确认失败\n");}return 0;
}

这份清空缓冲区的代码是有bug的,当scanf输入:123空格abc\n 时,getchar()只读取了空格,而空格后还有东西。

scanf()读取,默认遇到空格就停止

正确写法如下:

int main()
{printf("请输入密码:>");char password[20] = { 0 };scanf("%s", password);//清理缓冲区while (getchar() != '\n'){;}printf("请确认密码(y/n):>");int ch = getchar();if (ch == 'y'){printf("确认成功\n");}else{printf("确认失败\n");}return 0;
}

当然,如果想继续读取空格后的内容的话,可以参考如下代码:

int main()
{char arr[20] = {0};scanf("%[^\n]", arr);printf("%s\n", arr);return 0;
}

scanf("%[^\n]", arr);中的%[^\n]表示读取到\n停止,当然也可以将\n换成自己的需求。

3.4 for循环

for循环语法结构
for(表达式1; 表达式2; 表达式3)
{循环语句;
}

表达式1:为初始化部分,用于初始化循环变量的。(该部分仅仅首次循环执行)

表达式2:为条件判断部分,用于判断循环什么时候终止。

表达式3:为调整部分,用于循环条件的调整。(执行完循环体后才执行该部分)

for循环的执行流程图:

对比一下for循环和while循环:

int i = 0;
//实现相同的功能,使用while
i=1;//初始化部分
while(i<=10)//判断部分
{printf("hehe\n");i = i+1;//调整部分
}//实现相同的功能,使用for
for(i=1; i<=10; i++)
{printf("hehe\n");
}

与while循环的区别在于初始化和调整部分放置位置不同,这也是for循环的优点之一,修改起来更加方便。

看一下代码:

int i = 1;
for(i = 1; i<=10; i++)
{i = 0 // 可行吗??
}

这是不规范的代码,容易产生Bug,建议不可在for 循环体内修改循环变量,防止 for 循环失去控制。

在看以下两份代码:

int i = 0;
//前闭后开的写法
for(i=0; i<10; i++)
{}//两边都是闭区间
for(i=0; i<=9; i++)
{}

你觉得那种定义更加直观呢?建议议for语句的循环控制变量的取值采用“前闭后开区间”写法。

前闭后开能更加直观的直到该循环执行多少次。(看判断条件就可以了)

3.4.1 一些for循环的变种

//代码1:for循环的三个部分均可以省略
//该程序是一个死循环,造成死循环的原因:省略了判断部分
//for循环中,判断部分不写,恒为真
for(;;)
{printf("hehe\n");
}//代码2
int i = 0;
int j = 0;
//如果省略掉初始化部分,这里打印多少个hehe?
//3个。
//for循环省略掉初始化条件部分,会造成的影响,
//因为for循环中初始化部分在整个循环中只会执行一次,
//当程序结束,又一次执行内层循环时,本该为j重新赋值时,发现没有初始化部分,此时j已自增到3了
for(; i<10; i++)
{for(; j<10; j++){printf("hehe\n");}
}//代码3-使用多余一个变量控制循环
//此情况根据具体需求设定
int x, y;
for (x = 0, y = 0; x<2 && y<5; ++x, y++)
{printf("hehe\n");
}

针对代码2:

笔试题:

//请问循环要循环多少次?
#include <stdio.h>
int main()
{int i = 0;int k = 0;for(i =0,k=0; k=0; i++,k++)k++;return 0;
}

答:0次。因为判断部分k = 0 是一种赋值语句,因此判断部分为0,则为假,不进入循环体。

3.5 do...while循环

//do...while循环语法结构
do循环语句;
while(表达式); //注意结尾要加;

do..while语句执行流程:

do...while循环最大的特点:循环至少执行一次

四、goto语句

//goto语句语法结构
goto label;  //label可以是任何除C关键字以外的纯文本,它可以设置在C程序中goto语句的前面或者后面。
label:根据需求编写代码....

C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。 从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。 但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。列如:

for(...)for(...){for(...){if(disaster)goto error;}}…
error:if(disaster)// 处理错误情况

注意:在任何编程语言中,都不建议使用 goto 语句。因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改。任何使用 goto 语句的程序可以改写成不需要使用 goto 语句的写法。

以下为一个利用goto语句编写的关机程序:

#include <stdio.h>
#include <stdlib.h> //使用system()需要包含的头文件
int main()
{char input[10] = {0};system("shutdown -s -t 60");again:printf("电脑将在1分钟内关机,如果输入:我是猪,就取消关机!\n请输入:>");scanf("%s", input);if(0 == strcmp(input, "我是猪")){system("shutdown -a");}else{goto again;}return 0;
}

使用循环实现:

#include <stdio.h>
#include <stdlib.h>int main(){char input[10] = {0};system("shutdown -s -t 60");while(1){printf("电脑将在1分钟内关机,如果输入:我是猪,就取消关机!\n请输入:>");scanf("%s", input);if(0 == strcmp(input, "我是猪")){system("shutdown -a");break;}}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/792387.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AcWing 785. 快速排序——算法基础课题解

AcWing 785. 快速排序 文章目录 题目描述CGo模板 题目描述 给定你一个长度为 n 的整数数列。 请你使用快速排序对这个数列按照从小到大进行排序。 并将排好序的数列按顺序输出。 输入格式 输入共两行&#xff0c;第一行包含整数 n。 第二行包含 n 个整数&#xff08;所有…

C语言中的结构体:高级特性与扩展应用

前言 结构体在C语言中的应用不仅限于基本的定义和使用&#xff0c;还包含一些高级特性和扩展应用&#xff0c;这些特性和应用使得结构体在编程中发挥着更加重要的作用。 一、位字段&#xff08;Bit-fields&#xff09; 在结构体中&#xff0c;我们可以使用位字段来定义成员…

AJAX —— 学习(二)

目录 一、利用 JSON 字符串 返回数据 &#xff08;一&#xff09;基础代码 &#xff08;二&#xff09;原理及实现 二、nodmon 工具 自动重启服务 &#xff08;一&#xff09;用途 &#xff08;二&#xff09;下载 &#xff08;三&#xff09;使用 三、IE 缓存问题 &a…

QA测试开发工程师面试题满分问答8: mysql数据库的索引定义、用途和使用场景

MySQL数据库索引是一种数据结构&#xff0c;用于提高数据库的查询效率。索引是基于表中的一个或多个列构建的&#xff0c;它们允许数据库系统快速定位和访问表中的特定数据&#xff0c;而无需扫描整个表。 索引的定义 在MySQL中&#xff0c;可以使用CREATE INDEX语句定义索引…

pulsar集群部署流程及方案

# 部署方案: 集群模式部署,broker和bookie混合部署,zk同时部署在三台机器上面(资源充足zk最好单独部署,注意pulsar和zk版本兼容性) # 1.集群资源使用(实际测试情况CPU使用率比内存高,建议CPU设置大于内存,不同业务场景有差异) 三台主机centos7 16核16GB,每台挂载1TB机械硬盘(不…

Linux:进程终止和等待

一、进程终止 main函数的返回值也叫做进程的退出码&#xff0c;一般0表示成功&#xff0c;非零表示失败。我们也可以用不同的数字来表示不同失败的原因。 echo $?//打印最近一次进程执行的退出码 而作为程序猿&#xff0c;我们更需要知道的是错误码所代表的错误信息&#x…

MongoDB聚合运算符:$lte

文章目录 语法举例 $lte聚合运算符用于比较两个值&#xff0c;如果第一个小于等于第二个&#xff0c;返回true&#xff1b;如果第一个值大于第二个值&#xff0c;返回false。 语法 { $lte: [ <expression1>, <expression2> ] }$lte可以用来比较任何类型的值&…

嵌入式算法开发系列之卡尔曼滤波算法

卡尔曼滤波算法 文章目录 卡尔曼滤波算法前言一、卡尔曼滤波算法原理二、算法应用三、C语言实现总结 前言 在嵌入式系统中&#xff0c;传感器数据通常受到噪声、误差和不确定性的影响&#xff0c;因此需要一种有效的方法来估计系统的状态。卡尔曼滤波算法是一种基于概率理论的…

网络安全系统之——PKI体系

一、公钥基础设施 公钥基础设施 PKI&#xff08;Public Key Infrastructure&#xff09;是通过使用公钥技术和数据证书来提供信息系统安全服务&#xff0c;并负责验证数字证书持有者身份的一种体系。PKI 基础设施采用证书管理公钥&#xff0c;通过第三方可信任认证中心&#xf…

【信号与系统 - 2】傅里叶变换与反变换

1 傅里叶变换与频谱密度函数 非周期信号可以看成是 T → ∞ T\to{\infty} T→∞ 的周期信号 由于 w ↓ 2 π T ↑ w\downarrow\frac{2\pi}{T\uparrow} w↓T↑2π​&#xff0c; T T T 无限大&#xff0c;则基波频率 w w w 无限小&#xff0c;可以视为 d w dw dw 在频谱图…

RL — 强化学习算法概述

目录 一、说明二、无模型算法三、基于模型的 RL四、价值学习五、策略梯度5.1 强度:5.2 局限性5.3 蒙特卡洛政策梯度六、TRPO公司七、行动者兼评论家八、基于模型的 RL一、说明 我们在本系列中研究了许多强化学习 (RL) 算法,例如,用于 MoJoCo 任务的策略梯度方法、用于 At…

【亲测有效】Ubuntu系统下调整/home分区大小(无损扩容)

一、引言 当时给系统分区的时候&#xff0c;home和根分区都是100GB左右&#xff0c;突然发现home 分区不够用了&#xff0c;于是决定将根分区的部分空间挪移到home分区。 常用调整分区大小的工具有&#xff1a;GParted工具&#xff0c;DiskGenius工具。如果GParted工具无法调…

Linux文件权限管理详解——以CentOS为例

Linux文件权限管理详解——以CentOS为例 一、引言 在Linux系统中,文件权限管理是一项非常重要的任务。正确的文件权限设置能够保护系统的安全性,防止未授权访问和数据泄露。本文将详细介绍Linux文件权限管理的基本概念、常用命令以及如何在CentOS系统中进行实际操作。 二、…

电工技术学习笔记——直流电路及其分析方法

一、直流电路 电路的组成 1. 电压和电流的参考方向 电压&#xff08;Voltage&#xff09;&#xff1a;电压是电场力对电荷产生的作用&#xff0c;表示为电荷单位正电荷所具有的能量。在电路中&#xff0c;电压通常被定义为两点之间的电势差&#xff0c;具有方向性&#xff0c;…

HomePlug AV

目录 HomePlug AV的基本概念基本术语网络概念网络实例 HomePlug AV物理层&#xff08;PHY&#xff09;HomePlug AV OFDM收发器架构PHY的调制模式FC调制和ROBO调制物理层的特点OFDM频域/时域转换开窗/槽式OFDM信号和噪声PHY发送控制——信道自适应PHY帧格式&#xff08;Symbol&a…

中间件复习之-RPC框架

什么是RPC框架&#xff1f; RPC(Remote Procedure Call):远程过程调用。当多个应用部署在多个服务器上时&#xff0c;由于他们不在一个内存空间上&#xff0c;因此需要网络来进行通信&#xff0c;而RPC允许它像调用本地方法一样调用远程服务。 RPC原理 服务消费方通过RPC客户…

Unity类银河恶魔城学习记录12-3 p125 Limit Inventory Slots源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Inventory.cs using Newtonsoft.Json.Linq; using System.Collections; us…

如何用python开发“跳一跳”游戏【附源码】

话不多说,直接上代码: import pygame import random # 游戏参数 WIDTH, HEIGHT = 600, 800 PLAYER_SIZE = 50 OBSTACLE_WIDTH = 100 OBSTACLE_HEIGHT = 20 OBSTACLE_GAP = 200 GRAVITY = 0.5 # 颜色 WHITE = (255, 255, 255) BLACK = (0, 0, 0) BLUE = (0, 0, 255) # 初始…

【面试八股总结】进程(一)

参考资料 &#xff1a;小林Coding、阿秀、代码随想录 一、什么是进程&#xff1f; 1. 基本概念 进程是具有独立功能的程序在一个数据集合上运行的过程&#xff0c;是系统进行资源分配和调度的一个独立单位。 2. 进程控制块 系统通过进程控制块PCB描述进程的进本情况…

20.2k stars项目搭建私人网盘界面美功能全

Nextcloud是一套用于创建网络硬盘的客户端&#xff0d;服务器软件。其功能与Dropbox相近&#xff0c;但Nextcloud是自由及开放源代码软件&#xff0c;每个人都可以在私人服务器上安装并执行它。 GitHub数据 20.2k stars561 watching3.2k forks 开源地址:https://github.com/ne…