【C语言】控制语句

目录

1. 分支语句

1.1 if

1.1.1 语法结构

1.1.2 演示代码

1.1.3 悬空else问题

1.2 switch

1.2.1 语法结构

1.2.2 演示代码

1.2.3 case穿透现象

2. 循环语句

2.1 while

2.1.1 语法结构

2.1.2 演示代码

2.2 for

2.2.1 语法结构

2.2.2 演示代码

2.2.3 表达式的省略

2.2.4 C99中的for语句

2.2.5 C++11 范围for

2.3 do while

2.3.1 语法结构

2.3.2 演示代码

3. 跳转语句

3.1 break

3.2 continue

3.3 goto

3.4 return


1. 分支语句

分支语句又称选择语句、条件判断语句。

1.1 if

1.1.1 语法结构

if (表达式)
    语句
if (表达式)
    语句1
else
    语句2
if (表达式1)
    语句1
else if (表达式2)
    语句2
...
else if (表达式n)
    语句n
else
    语句n+1

1.1.2 演示代码

if (age < 18)
{
	printf("未成年\n");
	printf("不能饮酒\n");
} // 控制多条语句要用{}括起来
if (age < 18)
{
	printf("未成年\n");
	printf("不能饮酒\n");
}
else
    printf("成年\n");
if (age <= 6)
    printf("童年\n");
else if (age >= 7 && age <= 17)
    printf("少年\n");
else if (age >= 18 && age <= 40)
    printf("青年\n");
else if (age >= 41 && age <= 65)
    printf("中年\n");
else
    printf("老年\n");

1.1.3 悬空else问题

没有{}的约束下else和离它最近的if匹配。

例题1

#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和if (b == 2)匹配,上述代码规范写法如下:

#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;
}

什么都不输出。

例题2

#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和if (a == 1)匹配。代码运行结果为:haha

例题3

#include <stdio.h>

int main()
{
	int a = 1, b = 2, c = 3, d = 0;
	if (a == 1 && b++ == 2)
	if (b != 2 || c-- != 3)
		printf("%d,%d,%d\n", a, b, c);
	else
		printf("%d,%d,%d\n", a, b, c);
	else
		printf("%d,%d,%d\n", a, b, c);
	return 0;
}

第一个else和if (b != 2 || c-- != 3)匹配,第二个else只能和if (a == 1 && b++ == 2)匹配。上述代码规范写法如下:

#include <stdio.h>

int main()
{
	int a = 1, b = 2, c = 3, d = 0;
	if (a == 1 && b++ == 2)
	{
		if (b != 2 || c-- != 3)
			printf("%d,%d,%d\n", a, b, c);
		else
			printf("%d,%d,%d\n", a, b, c);
	}
	else
		printf("%d,%d,%d\n", a, b, c);
	return 0;
}

代码如何执行?

  1. 初始值:a = 1, b = 2, c = 3, d = 0
  2. 表达式a == 1 && b++ == 2为真,进入{}
  3. 执行b++操作:a = 1, b = 3, c = 3, d = 0
  4. 表达式b != 2 || c-- != 3中的b != 2为真,可以确定整个表达式为真,不执行c-- != 3(短路原则)
  5. 打印a,b,c:1,3,3

1.2 switch

1.2.1 语法结构

switch (整型常量表达式)
{
    case 整型常量表达式1:
        语句1
        break;
    case 整型常量表达式2:
        语句2
        break;
    ...
    case 整型常量表达式n:
        语句n
        break;
    default:
        语句n + 1
        break;
}
switch (整型常量表达式)
{
    case 整型常量表达式1:
    ....
    case 整型常量表达式a:
        语句1
        break;

    case 整型常量表达式a+1:
    ....
    case 整型常量表达式b:
        语句2
        break;

    ....

    case 整型常量表达式c:
    ....
    case 整型常量表达式d:
        语句n
        break;

    default:
        语句n+1
        break;
}

1.2.2 演示代码

switch (day)
{
	case 1:
		printf("星期一\n");
		break;
	case 2:
		printf("星期二\n");
		break;
	case 3:
		printf("星期三\n");
		break;
	case 4:
		printf("星期四\n");
		break;
	case 5:
		printf("星期五\n");
		break;
	case 6:
		printf("星期六\n");
		break;
	case 7:
		printf("星期日\n");
		break;
	default:
		printf("输入有误,请重新输入\n");
		break;
}
switch (day)
{
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
		printf("工作日\n");
		break;
	case 6:
	case 7:
		printf("休息日\n");
		break;
	default:
		printf("输入有误,请重新输入\n");
		break;
}

1.2.3 case穿透现象

在switch语句中,如果case控制的语句体后面不写break,将出现穿透现象。在不判断下一个case值的情况下,向下运行,直到遇到break,或者整体switch语句结束。

#include <stdio.h>

int main()
{
	int day = 0;
	scanf("%d", &day);

	switch (day)
	{
	case 1:
		printf("星期一\n");
	case 2:
		printf("星期二\n");
	case 3:
		printf("星期三\n");
	case 4:
		printf("星期四\n");
	case 5:
		printf("星期五\n");
	case 6:
		printf("星期六\n");
	case 7:
		printf("星期日\n");
	default:
		printf("输入有误,请重新输入\n");
		break;
	}

	return 0;
}

2. 循环语句

循环语句又称迭代语句。

2.1 while

2.1.1 语法结构

while (表达式)
    循环体

2.1.2 演示代码

#include <stdio.h>

int main()
{
	int i = 1;

	while (i <= 10)
	{
		printf("%d ", i);
		i++;
	}

	return 0;
}
// 1 2 3 4 5 6 7 8 9 10 

2.2 for

2.2.1 语法结构

for (初始化表达式; 条件判断表达式; 调整表达式)
    循环体

2.2.2 演示代码

#include <stdio.h>

int main()
{
	int i = 0;

	for (i = 1; i <= 10; i++)
	{
		printf("%d ", i);
	}

	return 0;
}
// 1 2 3 4 5 6 7 8 9 10 

2.2.3 表达式的省略

三个表达式都是可以省略的:

  • 省略初始化表达式表示不对循环控制变量赋初值
  • 省略条件判断表达式表示判断恒成立
  • 省略调整表达式表示不对循环控制变量做调整

全部省略即for(;;)表示无限循环,相当于while(1)。

2.2.4 C99中的for语句

在C99中,for语句的第一个表达式可以替换为一个声明,这一特性使得程序员可以声明一个用于循环的变量:

// 声明一个变量
for (int i = 0; i < 10; i++)
{
    //...
}

// 声明多个变量,只要它们的类型相同
for (int i = 0, j = 0; i < 10; i++)
{
	//...
}

变量i不需要在该语句前进行声明。事实上,如果变量i在之前已经进行了声明,这个语句将创建一个新的i且该值仅用于循环内。

for语句声明的变量不可以在循环外访问(在循环外不可见)。

2.2.5 C++11 范围for

在这里提一下C++的范围for(不是C语言的语法,是C++的语法)。

C++11新标准引入了一种更简单的for语句,这种语句可以遍历容器或其他序列的所有元素。范围for语句(range for statement)的语法形式是:

for (declaration : expression)
    statement

expression表示的必须是一个序列,比如用花括号括起来的初始值列表、数组或者vector或string等类型的对象,这些类型的共同特点是拥有能返回迭代器的begin和end成员。

declaration定义一个变量,序列中的每个元素都得能转换成该变量的类型。确保类型相容最简单的办法是使用auto类型说明符,这个关键字可以令编译器帮助我们指定合适的类型。如果需要对序列中的元素执行写操作,循环变量必须声明成引用类型。

每次迭代都会重新定义循环控制变量,并将其初始化成序列中的下一个值,之后才会执行statement。像往常一样,statement可以是一条单独的语句也可以是一个块。所有元素都处理完毕后循环终止。

之前我们已经接触过几个这样的循环。接下来的例子将把vector对象中的每个元素都翻倍,它涵盖了范围for语句的几乎所有语法特征:

vector<int> v = { 0,1,2,3,4,5,6,7,8,9 };
// 范围变量必须是引用类型,这样才能对元素执行写操作
// C++11中,auto仅有自动推断变量类型的功能
for (auto& r : v)
	r *= 2; // 将v中每个元素的值翻倍

for语句头声明了循环控制变量r,并把它和v关联在一起,我们使用关键字auto令编译器为r指定正确的类型。由于准备修改v的元素的值,因此将r声明成引用类型。此时,在循环体内给r赋值,即改变了r所绑定的元素的值。

范围for语句的定义来源于与之等价的传统for语句:

for (auto beg = v.begin(), end = v.end(); beg != end; ++beg)
{
	auto& r = *beg; // r必须是引用类型,这样才能对元素执行写操作
	r *= 2;         // 将v中每个元素的值翻倍
}

学习了范围for语句的原理之后,我们也就不难理解为什么强调不能通过范围for语句增加vector对象(或者其他容器)的元素了。在范围for语句中,预存了end()的值。一旦在序列中添加(删除)元素,end函数的值就可能变得无效了。

2.3 do while

2.3.1 语法结构

do
{
    循环体
} while (表达式);

2.3.2 演示代码

#include <stdio.h>

int main()
{
	int i = 10;

	do
	{
		printf("%d ", i);
	} while (i < 10);

	return 0;
}
// 10
// 先执行一次循环体,再判断表达式
// 即do while循环结构至少执行一次循环体

3. 跳转语句

跳转语句又称转向语句。

3.1 break

break用于跳出当前的那一层循环或switch语句。

#include <stdio.h>

int main()
{
	int i = 1;

	while (i <= 10)
	{
		if (5 == i)
			break;
		printf("%d ", i);
		i++;
	}

	return 0;
}
// 1 2 3 4 
#include <stdio.h>

int main()
{
	int i = 0;

	for (i = 1; i <= 10; i++)
	{
		if (5 == i)
			break;
		printf("%d ", i);
	}
	return 0;
}
// 1 2 3 4 
#include <stdio.h>

int main()
{
	int i = 1;

	do
	{
		if (5 == i)
			break;
		printf("%d ", i);
		i++;
	}
	while (i < 10);

	return 0;
}
// 1 2 3 4 
#include <stdio.h>

int main()
{
	int day = 6;

	switch (day)
	{
	case 1:
		printf("星期一\n");
		break;
	case 2:
		printf("星期二\n");
		break;
	case 3:
		printf("星期三\n");
		break;
	case 4:
		printf("星期四\n");
		break;
	case 5:
		printf("星期五\n");
		break;
	case 6:
		printf("星期六\n");
		break;
	case 7:
		printf("星期日\n");
		break;
	default:
		printf("输入有误,请重新输入\n");
		break;
	}

	return 0;
}
// 星期六

3.2 continue

continue用于终止本次循环,只要遇到continue,后面的代码就不会执行,直接进入下一次循环的入口。

#include <stdio.h>

int main()
{
	int i = 1;

	while (i <= 10)
	{
		if (5 == i)
			continue;
		printf("%d ", i);
		i++;
	}

	return 0;
}
// 1 2 3 4 死循环
#include <stdio.h>

int main()
{
	int i = 0;

	for (i = 1; i <= 10; i++)
	{
		if (5 == i)
			continue;
		printf("%d ", i);
	}
	return 0;
}
// 1 2 3 4 6 7 8 9 10 
#include <stdio.h>

int main()
{
	int i = 1;

	do
	{
		if (5 == i)
			continue;
		printf("%d ", i);
		i++;
	}
	while (i < 10);

	return 0;
}
// 1 2 3 4 死循环

3.3 goto

goto语句又称无条件转移语句。

[标号语句]    标识符: 语句
[goto语句]    goto 标识符;

标号是放置在语句开始处的标识符,一条语句可以有多个标号。

goto语句可以跳转到函数中任何有标号的语句处。

goto语句可以用于跳出多层循环,但是不建议使用,以免造成程序流程的混乱。

做一个关机程序:60s后关机,如果输入:我是猪,则取消关机。

使用goto语句:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	char input[20] = { 0 };
	system("shutdown -s -t 60"); // 执行系统命令:60s后关机

again:
	printf("请注意,你的电脑将在60秒后关机,如果输入:我是猪,则取消关机\n");
	scanf("%s", input);
	if (strcmp(input, "我是猪") == 0)
	{
		system("shutdown -a"); // 执行系统命令:取消关机
	}
	else
	{
		goto again;
	}

	return 0;
}

使用while循环:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	char input[20] = { 0 };
	system("shutdown -s -t 60");

	while (1)
	{
		printf("请注意,你的电脑将在60秒后关机,如果输入:我是猪,则取消关机\n");
		scanf("%s", input);
		if (strcmp(input, "我是猪") == 0)
		{
			system("shutdown -a");
			break;
		}
	}

	return 0;
}

3.4 return

return 表达式;

有返回值的C函数要有return语句。如果遗漏main函数中的return语句,程序在运行至最外面的右花括号( } )时会返回0。因此,可以省略main函数末尾的return语句(强烈建议不要省略)。但是,不要在其他有返回值的函数中漏掉它。

在main函数中执行return语句是终止程序的一种方法,另一种方法是调用exit函数,此函数属于<stdlib.h>头。传递给exit函数的实际参数和main函数的返回值具有相同的含义:两者都说明程序终止时的状态。

为了表示正常终止,传递0:

exit(0);

因为0有点模糊,所以C语言允许用EXIT_SUCCESS来代替(效果是相同的):

exit(EXIT_SUCCESS);

传递EXIT_FAILURE表示异常终止:

exit(EXIT_FAILURE);

EXIT_SUCCESS和EXIT_FAILURE都是定义在<stdlib.h>中的宏。EXIT_SUCCESS和EXIT_FAILURE的值都是由实现定义的,通常分别是0和1。

作为终止程序的方法,return语句和exit函数关系紧密。事实上,main函数中的语句

return 表达式;
// 等价于
exit(表达式);

return语句和exit函数之间的差异是:不管哪个函数调用exit函数都会导致程序终止,return语句仅当由main函数调用时才会导致程序终止。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值