C语言分支与循环基础知识详解



前言

C语言是结构化的程序设计语言,这里的结构指的是顺序结构选择结构循环结构,C语言是能够实现这三种结构的,其实我们如果仔细分析,我们日常所见的事情都可以拆分为这三种结构或者这三种结构的组合。


一、分支结构

也就是选择结构。

1. if语句

基本语句

格式如下:

if ( 表达式 )
 {
 语句体
 }

表达式成立(为真),则语句执行,表达式不成立(为假),则语句不执行。
同时,由于c语言中0表示假,非0表示真,所以这个表达式也可以是一个整形值。

else

else是在if的表达式为假时执行的语句部分
例如在判断一个数是奇数还是偶数时,如果只使用if的基本语句,那需要进行两次两次判断,但显而易见的是,一个数是奇数还是偶数是一个对立事件,那么就可以使用if-else结构进行判断,如下:

#include <stdio.h>
int main()
{
 int num = 0;
 scanf("%d", &num);
 if(num % 2 == 1)
 	printf("%d 是奇数\n", num);
 else
 	printf("%d 是偶数\n", num);
 return 0;
}

这样我们就得到一个双分支结构了。

嵌套if

在 if-else语句中,else 可以与另⼀个 if 语句连用,构成多重判断。

#include <stdio.h>
int main()
{
 int num = 0;
 scanf("%d", &num);
 if(num == 0)
 	printf("输⼊的数字是0\n");
 else if(num > 0) //这⾥的 if 相当于嵌套在else语句中,形成了嵌套结构
 	printf("输⼊的数字是正数\n");
 else//这里的else要在if和else if的表达式均不成立时才会执行
 	printf("输⼊的数字是负数\n");
 
 return 0;
}

而借助嵌套else,我们就可以得到多分支结构了!
你可以根据下面这个题目,分别利用基本语句和多分支结构尝试解决,感受多分支结构在处理问题上的简洁性:

输⼊⼀个⼈的年龄
如果年龄<18岁,打印"少年"
如果年龄在18岁⾄44岁打印"⻘年"
如果年龄在45岁⾄59岁打印"中⽼年"
如果年龄在60岁⾄89岁打印"⽼年"
如果90岁及以上打印"⽼寿星"

悬空else问题

来看下面这个题目

#include <stdio.h>
int main()
{
	int a = 0;
	int b = 2;
	if(a == 1)
		if(b == 2)
			printf("hehe\n");
	else
		printf("haha\n");
	return 0;
}

这个代码的执行结果是什么?

这里便涉及到了悬空else问题,也许你会觉得结果是“haha”,这显然是因为你讲这个else与上面的 if(a==1)这个条件判断语句并列在一起了,但实际上如果有多个 if 和 else ,可以记住这样⼀条规则, else 总是跟最接近的 if 匹配。
当然,这一规则的前提是没有大括号。

在c语言中,语句的缩进与对齐不会像python中那样影响语句的进行。

如果你希望上面的代码可以打印出haha,你可以尝试加一个大括号。

2. 关系操作符

C语言用于比较的表达式,称为“关系表达式”,里面使用的运算符就称为“关系运算符”,主要有下面6个。

> ⼤于运算符
< ⼩于运算符
>= ⼤于等于运算符
<= ⼩于等于运算符
== 相等运算符
!= 不相等运算符

使用方式如下:

a == b;
a != b;
a < b;
a > b;
a <= b;
a >= b;

关系表达式通常返回0或1,表示真假。
C语言中,0表示假,所有非零值表示真。比如,20>12返回112>20 返回0。关系表达式常用于 ifwhile 结构。

值得注意的是,‘==’和‘=’是两个完全不同的符号,前者为关系表达式,后者为赋值语句,务必小心他们的混淆。
如果在if的表达式中错误的将将前者写作了后者,可能会导致死循环等严重的问题。

另一个值得注意的事情是:多个关系操作符之间不易连用。
比如下面这个式子:

 i < j < k

它实际上表达的是什么意思呢?

 (i < j) < k

其实它是这样的,在(i < j)这个式子得出结果后,再与后面的k进行比较。
上面说过,关系操作符的结果为0或1,那么这个式子的最终结果就为:
0 < k 或1 < k
这显然与我们预期的不同

那么如果想要表达与数学中使用的连等相同的结果,我们可以使用 && (后文会提到的逻辑操作符)来连接两个式子,比如上面的式子可以改写为:

i < j && j < k 

这样就能得到我们希望的结果了。

3. 条件操作符

条件操作符也叫三目操作符,需要接受三个操作数,形式如下:

exp1 ? exp2 : exp3

条件操作符的计算逻辑是:如果 exp1 为真,exp2 计算,计算的结果是整个表达式的结果;如果exp1 为假,exp3 计算,计算的结果是整个表达式的结果。

条件操作符可以替代一些 if语句
比如我们可以使用条件操作符改写下面的语句:

#include <stdio.h>
int main()
{
 int a = 0;
 int b = 0;
 scanf("%d", &a);
 if (a > 5)
 b = 3;
 else
 b = -3;
 printf("%d\n", b);
 return 0;
}

可以改写为:

#include <stdio.h>
int main()
{
 int a = 0;
 int b = 0;
 scanf("%d", &a);
 b = a>5 ? 3:-3;
 printf("%d\n", b);
 return 0;
}

4. 逻辑操作符

逻辑运算符提供逻辑判断功能,用学构建更复杂的表达式,主要有下面三个运算符:
! :逻辑取反运算符(改变单个表达式的真假)
&& :逻辑与运算符,就是并且的意思(两侧的表达式都为真,则为真,否则为假)
|| :逻辑或运算符,就是或者的意思(两侧至少有一个表达式为真,则为真,否则为假)
注:C语言中,非0表示真,0表示假

逻辑取反运算符-!

逻辑取反操作符
比如,我们有一个变量叫flag,如果flag为假,要做一个什么事情,就可以这样写代码:

#include <stdio.h>
int main()
{
 int flag = 0;
 if(!flag)
 {
 printf("do something\n");
 }
 return 0;
}

如果 flag 为真, !flag 就是假,如果 flag 为假,!flag 就是真
所以上面的代码的意思就是 flag 为假,执行 if 语句中的代码。

逻辑与运算符-&&

逻辑与运算符
即当&&操作符两边都为真时才为真,否则为假。

逻辑或操作符-||

逻辑或运算符

即当 || 操作符两边都为假时才为假,否则为真。

短路

C语言逻辑运算符有一个特点,它总是先对左侧的表达式求值,再对右边的表达式求值,这个顺序是
保证的。如果左边的表达式满足逻辑运算符的条件,就不再对右边的表达式求值。这种情况称为“短路。

如下面的代码:

int month = 2;
if(month >= 3 && month <= 5)...

在这里,&&的左边为假,那么逻辑操作符的最终结果已经确定,那么就不会再进行&&后面的语句。

同样的,在逻辑或运算符中:

int month = 1;
if(month == 12 || month==1 || month == 2)...

逻辑或操作符进行了两次运算就得出了结果,那么最右边的式子就不会进行运算。

利用这个原理,不妨计算一下下面这个代码的结果

#include <stdio.h>
int main()
{
 int i = 0,a=0,b=2,c =3,d=4;
 i = a++ && ++b && d++;
 //i = a++||++b||d++;
 printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
 return 0;
}

5. switch

除了 if 语句外,C语言还提供了 switch 语句来实现分支结构。
switch 语句是一种特殊形式的 if…else 结构,用于判断条件有多个结果的情况。它把多重的 else if 改成更易用、可读性更好的形式。
其基本结构为:

switch (expression) {
 	case value1: statement
 	case value2: statement
 	default: statement//非必要
}

上面代码中,根据表达式 expression 不同的值,执行相应的 case 分支。如果找不到对应的值
就执行 default 分支。

注意:
1.switch 后的expression 必须是整型表达式
2.case 后的值,必须是整形常量表达式

提示:整形包括字符(char)和整数(int)

switch中的break

c语言的switch在跳转到case对应的结构体以后,不会停止执行执行,而是向后继续执行所有的case语句,包括defualt(后文介绍)后的语句,为了阻止他的这一行为从而达到我们的预期,我们应该在每个case后的预聚体结束后加上break来停止switch的执行。
那么上面的基本结构在大多数情况下都可以更改为:

switch (expression) {
 	case value1: statement;break;
 	case value2: statement;break;
 	default: statement;break;//非必要

当然,break并不永远是个必选项。
比如说下面这道题:

输⼊1~5,输出的是“⼯作⽇”;
输⼊6~7,输出“休息⽇”

那么就可以这么写:

#include <stdio.h>
int main()
{
	 int day = 0;
	 scanf("%d", &day);
 	switch(day)
	 {
 		case 1case 2:
 		case 3:
 		case 4:
		case 5:
			printf("⼯作⽇\n");
		break;
 		case 6:
 		case 7:
 			printf("休息⽇\n");
 			break;
 		}
 	return 0;
}

因此,应该根据实际的情况,来在代码中觉得是否使用 break,或者在哪里使用break,才能正确完成实际的需求。

switch 中的 default

在使用 switch 语句的时候,我们经常可能遇到一种情况,比如 switch 后的表达式中的值无法匹配代码中的 case 语句的时候,这时候要不就不做处理,要不就得在 switch 语句中加入default 子句。
比如上面的代码可以进行改写:

#include <stdio.h>
int main()
{
 int day = 0;
 scanf("%d", &day);
 switch(day)
 {
 	case 1case 2:
 	case 3:
 	case 4:
 	case 5:
 		printf("⼯作⽇\n");
 		break;
 	case 6:
 	case 7:
 		printf("休息⽇\n");
 		break;
 	default:
		printf("输⼊错误\n");
		break;
	}
	return 0;
}

很显然,加入这个 default ,可以显著的增加代码的健壮性。

case和default的顺序

其实,在 switch 语句中 case 语句和 default 语句是没有顺序要求的,只要你的顺序是满足实际需求的就可以。
不过我们通常 是把 default 子句放在最后处理的。

二、循环结构

1. while循环

基本语法:

while(表达式)
 语句;//如果循环体想包含更多的语句,可以加上⼤括号

在执行时,while会先判断表达式是否为true(非0),若是,则执行语句,然后再次判断表达式,若成立继续执行,直到某次表达式为false,循环结束。
break会直接停止while的执行,continue会跳过本次循环,但应该注意,在while中使用 continue 如果处理不当,很可能导致死循环。
while执行流程
来使用while循环解决一个问题吧!

输⼊⼀个正的整数,逆序打印这个整数的每⼀位
例如:
输⼊:1234,输出:4 3 2 1
输⼊:521,输出:1 2 5

解析:

1. 要想得到n的最低位,可以使⽤n%10的运算,得到的余数就是最低位,如:1234%10得到4
2. 要想去掉n的最低位,找出倒数第⼆位,则使⽤ n=n/10 操作就可以去掉最低位的,如:
    n=1234/10得到123123相较于1234就去掉了最低位,123%10就得到倒数第⼆位33. 循环12两个步骤,在n变成0之前,就能到所有的位

参考代码:

#include <stdio.h>
int main()
	{
	 int n = 0;
	 scanf("%d", &n);
	 while(n)
	 {
		 printf("%d ", n%10);
		 n /= 10;
	 }
	 return 0;
}

2. for 循环

在 3 种循环结构中,for 循环是使用次数最高的!!
基础语法为:

for(表达式1; 表达式2; 表达式3)
 语句;//如果循环体想包含更多的语句,可以加上⼤括号

表达式1 用于循环变量的初始化
表达式2 用于循环结束条件的判断
表达式3 用于循环变量的调整

首先执行表达式1初始化循环变量,接下来就是执行 表达式2 的判断部分,表达式2 的结果如果==0,则循环结束;
表达式2的结果如果 !=0 则执行循环语句,循环语句执行完后,再去执行表达式3,调整循环变量,然后再去表达式2的地方执行判断,表达式2的结果是否为0,决定循环是否继续。
整个循环的过程中,表达式1初始化部分只被执行1次,剩下的就是表达式2、循环语句、表达式3在循环。
for 循环执行流程
下面是对for循环的一个简单的使用:

在屏幕上打印1~10的值
#include <stdio.h>
int main()
{
 int i = 0;
 for(i=1; i<=10; i++)
 {
 printf("%d ", i);
 }
 return 0;
}

当然,你也可以试一下用while 循环解决这个问题。这里给出一个参考:

#include<stdio.h>
int main()
{
	int a = 1;
	while (a <= 10)
	{
		printf("%d ", a);
		a++;
	}
	return 0;
}

当然,对于while 来说,这个问题的解法是十分多样的,不妨自己尝试一下。

3. while 与for 的对比

在这里插入图片描述
for 和 while 在实现循环的过程中都有初始化、判断、调整这三个部分,但是 for 循环的三个部分非常集中,便于代码的维护,而如果代码较多的时候 while 循环的三个部分就比较分散,所以从形式上 for 循环要更优一些。

4. do-while 循环

在循环语句中 do while 语句的便带最少的,它的语法如下:

do
 语句;//如果循环体想包含更多的语句,可以加上⼤括号
while(表达式)

while 和 for 这两种循环都是先判断,条件如果满足就进入循环,执行循环语句,如果不满足就跳出循环;
而 do while 循环则是先直接进入循环体,执行循环语句,然后再执行 while 后的判断表达式,表达式为真,就会进行下一次,表达式为假,则不再继续循环。
do while循环语句执行流程
⼀般 do while 使⽤在循环体⾄少被执⾏⼀次的场景下,所以较少⼀些。

下面这类问题适合使用 do while 解决:

输⼊⼀个正整数,计算这个整数是⼏位数?
例如:
输⼊:1234 输出:4
输⼊:12 输出:2

代码示例:

#include <stdio.h>
int main()
{
	 int n = 0;
	 scanf("%d", &n);
	 int cnt = 0;
	 do
	 {
		 cnt++;
		 n = n / 10;
	 } while (n);
	 printf("%d\n", cnt);
	 return 0;
}

5. 循环嵌套

把一个循环嵌套在另一个循环中就叫做循环嵌套,来看一个例子:

题目:

找出100~200之间的素数,并打印在屏幕上。
注:素数⼜称质数,只能被1和本⾝整除的数字。

解析:

1. 要从100~200之间找出素数,⾸先得有100~200之间的数,这⾥可以使⽤循环解决。
2. 假设要判断i是否为素数,需要拿2~i-1之间的数字去试除i,需要产⽣2~i-1之间的数字,也可以使⽤
循环解决。
3. 如果2~i-1之间有数字能整除i,则i不是素数,如果都不能整除,则i是素数。

参考代码:

#include <stdio.h>
int main()
{
	 int i = 0;
	 //循环产⽣100~200的数字
	 for(i=100; i<=200; i++)
	 {
		 //判断i是否为素数
		 //循环产⽣2~i-1之间的数字
		 int j = 0;
		 int flag = 1;//假设i是素数
		 for(j=2; j<i; j++)
		 {
			 if(i % j == 0)
			 {
				 flag = 0;
				 break;
			 }
		 }
		 if(flag == 1)
		 	printf("%d ", i);
	 }
	 return 0;
}

6. goto语句

C语言提供了一种非常特别的语法,就是 goto 语句和跳转标号,goto 语句可以实现在同一个函数内跳转到设置好的标号处。
来看一个例子:

#include <stdio.h>
int main()
{
 	printf("hehe\n");
 	goto next;
 	printf("haha\n");
 next://这个next就是一个标号
 	printf("跳过了haha的打印\n"); 
 return 0;
}

但是由于goto 语句十分容易导致死循环,且过多的goto 会显著降低代码的阅读性,因此,除了在跳出三层以上的循坏时之外,应尽量减少goto的使用!!!

你可以在我的空间找到关于分支与循环的一个练习详解,喜欢的看一下吧!
https://blog.csdn.net/fhvyxyci/article/details/139662224

感谢您的阅读,如果喜欢的话,点个关注,点个点赞收藏吧!!!

  • 30
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值