【C初阶02】分支语句和循环语句(rand函数+%2d)


本章重点学习分支语句和循环语句的使用。

分支语句

  • if
  • switch

循环语句

  • while
  • for
  • do while

goto语句


C语言是一门结构化的程序设计语言
1.顺序结构
2.选择结构
3.循环结构

什么是语句?

C语言中由一个分号 ; 隔开的就是一条语句。 比如:

printf("hehe");
1+2;

注:为空语句

分支语句(选择结构)

if语句

那if语句的语法结构是怎么样的呢?
演示代码:

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

演示代码:

#include <stdio.h>
//代码1
int main()
{
	int age = 0;
	scanf("%d", &age);
	if(age<18)
	{
		printf("未成年\n");
	}
}
//代码2
#include <stdio.h>
int main()
{
	int age = 0;
	scanf("%d", &age);
	if(age<18)
	{
		printf("未成年\n");
	}
	else
	{
		printf("成年\n");
	}
}
//代码3
#include <stdio.h>
int main()
{
	int age = 0;
	scanf("%d", &age);
	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");
	}
}

解释一下: 如果表达式的结果为真,则语句执行。
在C语言中如何表示真假?

0表示假,非0表示真。

如果条件成立,要执行多条语句,怎应该使用代码块。

#include <stdio.h>
int main()
{
	if(表达式)
	{
		语句列表1}
	else
	{
		语句列表2}
	return 0;
} 

这里的一对 { } 就是一个代码块。
悬空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");//和离他最近的if匹配
		
	return 0;
}

结果为空白
原因:else与前文最近的if匹配
改正:

//适当的使用{}可以使代码的逻辑更加清楚。
//代码风格很重要
#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;
}

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更好,逻辑更加清晰,不容易出错。
错误例子

int age = 10;
if(13 <= age <23)
	printf("未成年\n");
	//错误原因13 <= age表达式值为0.表达式为假,值就为0。
	//13 <= age < 23实际为0 < 23,if内条件成立

在这里插入图片描述
改正

int age = 10;
if(13 <= age && age <23)
	printf("未成年\n");
	//错误原因13 <= age表达式值为0.表达式为假,值就为0。
	//13 <= age < 23实际为0 < 23,if内条件成立

练习

  1. 判断一个数是否为奇数
  2. 输出1-100之间的奇数
//1.
if( n %2)
	printf("n为奇数");
//2.
int a = 1;
while(a<=100)
{
	if( a % 2 )
		printf("%d  ",a);
	a++;
}	

switch语句

switch语句也是一种分支语句。 常常用于多分支的情况。
比如:

输入1,输出星期一
输入2,输出星期二
输入3,输出星期三
输入4,输出星期四
输入5,输出星期五
输入6,输出星期六
输入7,输出星期七

那我没写成 if...else if ...else if 的形式太复杂,那我们就得有不一样的语法形式。 这就是switch 语句。

switch(整型表达式)
{
	语句项;
}

语句项是什么呢?

//是一些case语句:
//如下:
case 整形常量表达式:
语句;

在switch语句中的 break
在switch语句中,我们没法直接实现分支,搭配break使用才能实现真正的分支。
比如:

#include <stdio.h>
int main()
{
	int day = 0;
	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;
	}
	return 0;
}
//结果是什么都不输出

有时候我们的需求变了:

  1. 输入1-5输出的是“weekday”;
  2. 输入6-7输出“weekend”

所以我们的代码就应该这样实现了:

#include <stdio.h>
//switch代码演示
int main()
{
	int day = 0;
	switch(day)
	{
		case 1case 2:
		case 3:
		case 4:
		case 5:
			printf("weekday\n");
			break;
		case 6:
		case 7:
			printf("weekend\n");
			break;
	}
	return 0;
}

break语句的实际效果是把语句列表划分为不同的部分。
编程好习惯

在最后一个 case 语句的后面加上一条 break语句。

(之所以这么写是可以避免出现在以前的最后一个 case 语句后面忘了添加 break语句)例如,在case7后面加case8,然而原先的case7后没有break,case7和case8的逻辑将出问题。

default子句
如果表达的值与所有的case标签的值都不匹配怎么办?
其实也没什么,结果就是所有的语句都被跳过而已。
程序并不会终止,也不会报错,因为这种情况在C中并不认为错误。
但是,如果你并不想忽略不匹配所有标签的表达式的值时该怎么办呢?
你可以在语句列表中增加一条default子句,把下面的标签

default:

写在任何一个case标签可以出现的位置。
当 switch表达式的值并不匹配所有case标签的值时,这个default子句后面的语句就会执行。
所以,每个switch语句中只能出现一条default子句。
但是它可以出现在语句列表的任何位置,而且语句流会像贯穿一个case标签一样贯穿default子句。
编程好习惯

在每个 switch 语句中都放一条default子句是个好习惯,甚至可以在后边再加一个 break 。

练习

#include <stdio.h>
int main()
{
	int n = 1;
	int m = 2;
	switch (n)
	{
	case 1:
		m++;
	case 2:
		n++;
	case 3:
		switch (n)
		{//switch允许嵌套使用
			case 1:
				n++;
			case 2:
				m++;
				n++;
				break;
		}
	case 4:
		m++;
		break;
	default:
		break;
	}
	printf("m = %d, n = %d\n", m, n);// m =5,n =3
	return 0;
}

swtich语句中可以出现if,不能出现continue没有意义,也不知道跳到哪里去

循环语句

  • while
  • for
  • do while

while循环

我们已经掌握了,if语句:

if(条件)
	语句;

当条件满足的情况下,if语句后的语句执行,否则不执行。但是这个语句只会执行一次。
但是我们发现生活中很多的实际的例子是:同一件事情我们需要完成很多次。
那我们怎么做呢? C语言中给我们引入了:while语句,可以实现循环。

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

while语句执行的流程
在这里插入图片描述

比如我们实现:

在屏幕上打印1-10的数字。

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

这个代码已经帮我了解了while语句的基本语法,那我们再了解一下:
while语句中的break和continue

break介绍

//break 代码实例
#include <stdio.h>
int main()
{
	int i = 1;
	while(i<=10)
	{
		if(i == 5)
			break;
		printf("%d ", i);
		i = i+1;
	}
	return 0;
}

这里代码输出的结果是什么?

1 2 3 4
1 2 3 4 5
1 2 3 4 5 6 7 8 9 10
1 2 3 4 6 7 8 9 10

总结: break在while循环中的作用:

其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。 所以:while中的break是用于永久终止循环的。

continue介绍

//continue 代码实例1
#include <stdio.h>
int main()
{
	int i = 1;
	while(i<=10)
	{
		if(i == 5)
			continue;
		printf("%d ", i);
		i = i+1;
	}
	return 0;
}

这里代码输出的结果是什么?

1 2 3 4√(死循环)
1 2 3 4 5
1 2 3 4 5 6 7 8 9 10
1 2 3 4 6 7 8 9 10

//continue 代码实例2
#include <stdio.h>
int main()
{
	int i = 1;
	while(i<=10)
	{
		i = i+1;
		if(i == 5)
			continue;
		printf("%d ", i);
	}
	return 0;
}

这里代码输出的结果是什么?

1 2 3 4
1 2 3 4 5
1 2 3 4 5 6 7 8 9 10
1 2 3 4 6 7 8 9 10
2 3 4 6 7 8 9 10√

总结: continue在while循环中的作用就是:

continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,而是直接跳转到while语句的判断部分。进行下一次循环的入口判断。

getchar()

介绍getchar(),putchar()

//代码1
	int ch = getchar();

	putchar(ch);
	printf("%c\n", ch);//由下图见,只接收一个字符

在这里插入图片描述

//代码2
	int ch = getchar();
	while ((ch = getchar() )!= EOF)//EOF在输入里表示ctrl+Z
	{
		putchar(ch);
	}

在这里插入图片描述

//代码3
#include <stdio.h>
int main()
{
	while ((ch = getchar()) != EOF)
	{
		if (ch <0|| ch >9)
			continue;
		putchar(ch);
	}
	return 0;
}//只打印0-9的字符

再看几个代码:

//关于getchar,可以接受一个键盘的字符
int main()
{
	int ret = 0;
	char password[20] = { 0 };
	printf("请输入密码:>");
	scanf("%s",password );//输入密码并存放到password数组中
	printf("请确认(Y/N):>");
	ret = getchar();
	if ('Y' == ret)
	{
		printf("确认成功");
	}
	else
	{
		printf("放弃确认");
	}
	return 0;
}

在这里插入图片描述
此处代码有问题,调试发现ret内值为10(回车符)printf("%d", '\n');//验真输出为10
关于输入缓冲区
在这里插入图片描述
修改:在确认前加getchar();接收回车字符"\n"
在这里插入图片描述
缺陷,密码有空格时,getchar再次失效
在这里插入图片描述
再次修改,思路:接收密码用循环getchar,直到接收到回车\n停止

int main()
{
	int ret = 0;
	char password[20] = { 0 };
	printf("请输入密码:>");
	scanf("%s",password );//输入密码并存放到password数组中
	while(ch = getchar() != '\n')
	{
		;
	}
	printf("请确认(Y/N):>");
	ret = getchar();
	if ('Y' == ret)
	{
		printf("确认成功");
	}
	else
	{
		printf("放弃确认");
	}
	return 0;
}

这样ch将不断循环接收空格以后的字符直到接收回车
在这里插入图片描述

for循环

我们已经知道了while循环,但是我们为什么还要一个for循环呢? 首先来看看for循环的语法:
语法

for(表达式1;表达式2;表达式3)
	循环语句;

表达式1 表达式1为初始化部分,用于初始化循环变量的。 表达式2 表达式2为条件判断部分,用于判断循环时候终止。** 表达式3 表达式3为调整部分**,用于循环条件的调整。
实际的问题:

使用for循环 在屏幕上打印1-10的数字。

#include <stdio.h>
int main()
{
	int i = 0;
	//for(i=1/*初始化*/; i<=10/*判断部分*/; i++/*调整部分*/)
	for(i=1; i<=10; i++)
	{
		printf("%d ", i);
	}
	return 0;
}

for循环的执行流程图:
在这里插入图片描述

现在我们对比一下for循环和while循环。

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

可以发现在while循环中依然存在循环的三个必须条件,但是由于风格的问题使得三个部分很可能偏离较远,这样查找修改就不够集中和方便。所以,for循环的风格更胜一筹。 for循环使用的频率也最高。
break和continue在for循环中
我们发现在for循环中也可以出现break和continue,他们的意义和在while循环中是一样的。 但是还是有些差异回忆上文while死循环:

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

for语句的循环控制变量
一些建议:

  1. 不可在for 循环体内修改循环变量,防止 for 循环失去控制。
  2. 建议for语句的循环控制变量的取值采用“前闭后开区间”写法。
int i = 0;
//前闭后开的写法
//这样写可以清晰看出循环10次
for(i=0; i<10; i++)
{}
//两边都是闭区间
for(i=0; i<=9; i++)
{}
//都是0-9

一些for循环的变种

#include <stdio.h>
int main()
 {
	//变种1
	//死循环
	for(;;)
	{
		printf("hehe\n");
	}
	//变种2
	int x, y;
	for (x = 0, y = 0; x<2 && y<5; ++x, y++)
	{
		printf("hehe\n");
	}
	return 0;
}//两个hehe
//0 0
//1 1
//2 2
//

1.for循环的初始化,调整,判断都可以省略但是
for循环的判断部分,如果被省略,那判断条件就是:恒为正
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,表达式为真。右值为0,表达式为假。

do…while循环

do语句的语法:

do
	循环语句;
while(表达式);

执行流程
在这里插入图片描述

do语句的特点
循环至少执行一次,使用的场景有限,所以不是经常使用。

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

do while循环中的break和continue

#include <stdio.h>
int main()
{
	int i = 1;
	do
	{
		if(5 == i)
			break;
		printf("%d\n", i);
		i++;
	}while(i<10);
	return 0;
}//1 2 3 4
#include <stdio.h>
int main()
{
	int i = 1;
	do
	{
		if(5 == i)
			continue;
		printf("%d\n", i);
		i++;
	}while(i<=10);
	return 0;
}//1 2 3 4 死循环

练习

  1. 计算 n的阶乘。

  2. 计算 1!+2!+3!+……+10!

  3. 在一个有序数组中查找具体的某个数字n。 编写int binsearch(int x, int v[], int n); 功能:在v[0]<=v[1]<=v[2]<=
    ….<=v[n-1]的数组中查找x.

  4. 编写代码,演示多个字符从两端移动,向中间汇聚。
    解释题意想要的效果为如下变化 例如
    ###################
    w#################!
    we###############!!
    wel#############!!!
    welc###########d!!!
    welco#########ld!!!
    welcom#######rld!!!
    welcome#####orld!!!
    welcome ###world!!!
    welcome t# world!!!
    welcome to world!!!

  5. 编写代码实现,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则提示登录成,如果三次均输入错误,则退出程序。

练习答案

//1.
int Factorial(int n)
{
	int  i = 0, mul = 1;
	for (i = 1; i <= n; i++)
	{
		mul = mul * i;
	}
	return mul;
}
//2.计算1!+2!+3!+……10!
int Fac_add()
{
	int Sum = 0, i = 0, j = 0, Mul = 0;
	for (i = 1; i <= 10; i++)
	{
		Mul = 1;
		for (j = 1; j <= i;j++)
		{
			Mul *= j;//Mul依次为1!,2!……,10!
		}
		Sum += Mul;
	}
	return Sum;
}

阶乘的和优化

//优化
int Fact_add()
{
	int Sum = 0, i = 0,Mul = 1;
	for (i = 1; i <= 10; i++)
	{
		Mul *= i;//Mul依次为1!,2!……,10!
		Sum += Mul;
	}
	return Sum;
}
// Mul = 1*1       Sum = 0 +1
// Mul = 1*1*2     Sum = 0 + 1 + 2
// Mul = 1*1*2*3   Sum = 0 + 1 + 2 + 6
//3.基础解法
	int arr[] = { 1,2,3,4,5,6,7 };
	int k = 8;
	//写一个代码,在arr数组(有序)中找到4
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	//顺序查找
	for (i = 0; i < sz; i++)
	{
		if (k == arr[i])
		{
			printf("找到了,下标是:%d \n", i);
			break;
		}
	}
	if (i == sz)
	{
		printf("找不到\n");
	}

有序数组查找优化,折半查找法思想
顺序查找O(n)

在这里插入图片描述

❤折半查找O(log2n)

例如:2^32个数字,只需查找32次
在这里插入图片描述

//3.折半查找
//3.
	int arr[] = { 1,2,3,4,5,6 };
	int k = 4;//要查找的数字
	//写一个代码,在arr数组(有序)中找到4
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int pre = 0;
	//折半查找
	int left = 0;
	int right = sz - 1;
	while(left <= right)
	{
		pre = (left + right)/2;//折半查找的下标
		if (arr[pre] == k)
		{
			printf("找到了,下标是 %d \n", pre);
			break;
		}
		else if (arr[pre] > k)//说明k可能在pre位置的左边
		{
			right = pre-1;
		}
		else
		{
			left = pre+1;
		}
	}
	if(left > right)
		printf("没找到\n");

//4.思路,两串字符
###################
welcome to world!!!
添加Sleep函数每次打印停顿一秒
添加system(“cls”);//执行清空屏幕
细节char arr1[] = “abc”;
保存时,会自动在末尾加‘\0’
例如:
char arr[] = “abc”;
[a b c \0]
0 1 2 3
sizeof计算的长度也是4

//
	char arr1[] = "welcome to world!!!";
	char arr2[] = "###################";
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	int left = 0;
	int right = sz - 2;
	while (left <= right)
	{
		printf("%s\n", arr2);
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		system("cls"); //<stdlib.h>
		left++;
		right--;
		Sleep(1000);//头文件<windows.h>
	}

最终结果为动态向中间汇聚
//5.
细节
== 不能用来比较两个字符串是否相等,应该使用一个库函数-strcmp

int i = 0;
char password[20] = {0};
for( i = 0; i<3;i++)
{
	printf("请输入密码;>");
	scanf("%s",password):
	if(strcmp(password,"123456") == 0)
	{
		printf("登陆成功\n");
		break;
	}
	if (i == 3)
		printf("三次密码均错误。退出程序\n");

练习参考代码:

//代码1
//编写代码,演示多个字符从两端移动,向中间汇聚
#include <stdio.h>
int main()
{
	char arr1[] = "welcome to bit...";
	char arr2[] = "#################";
	int left = 0;
	int right = strlen(arr1)-1;
	printf("%s\n", arr2);
	//while循环实现
	while(left<=right)
	{
		Sleep(1000);
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		left++;
		right--;
		printf("%s\n", arr2);
	}
	//for循环实现
	for (left=0, right=strlen(src)-1;
		left <= right;
		left++, right--)
	{
		Sleep(1000);
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		printf( "%s\n", target);
	}
	retutn 0;
}
//代码2
int main()
{
	char psw[10] = "" ;
	int i = 0;
	int j = 0;
	for (i = 0; i < 3 ; ++i)
	{
		printf( "please input:");
		scanf("%s", psw);
		if (strcmp(psw, "password" ) == 0)
			break;
	}
	if (i == 3)
		printf("exit\n");
	else
		printf( "log in\n");
}

折半查找算法
比如我买了一双鞋,你好奇问我多少钱,我说不超过300元。你还是好奇,你想知道到底多少,我就让你猜,你会怎么猜?
答案:你每次猜中间数。
代码实现:

实现在主函数内:
int main()
{
	int arr[] = {1,2,3,4,5,6,7,8,9,10};
	int left = 0;
	int right = sizeof(arr)/sizeof(arr[0])-1;
	int key = 7;
	int mid = 0;
	while(left<=right)
	{
		mid = (left+right)/2;
		if(arr[mid]>key)
		{
			right = mid-1;
		}
		else if(arr[mid] < key)
		{
			left = mid+1;
		}
		else
			break;
	}
	if(left <= right)
		printf("找到了,下标是%d\n", mid);
	else
		printf("找不到\n");
}
如果实现一个二分查找函数:
int bin_search(int arr[], int left, int right, int key)
{
	int mid = 0;
	while(left<=right)
	{
		mid = (left+right)>>1;
		if(arr[mid]>key)
		{
			right = mid-1;
		}
		else if(arr[mid] < key)
		{
			left = mid+1;
		}
		else
			return mid;//找到了,返回下标
	}
	return -1;//找不到
}

猜数字游戏实现

参考代码:

❤rand函数

MSDN手册
手册使用
在这里插入图片描述

在MSDN上查到
rand函数返回一个范围为0到RNAD_MAX的伪随机整数,在调用rand之前,使用srand函数为伪随机数生成器播种。
RAND_MAX转到定义发现值为0x7fff转化为十进制为32767,即函数生成的随机数范围为0-32767
srand((unsigned)time(NULL))详解

情况一:

int random = rand();

两次执行rand函数,发现生成的随机数完全一样。

在这里插入图片描述
在这里插入图片描述
情况二:参照手册,在调用rand之前,使用srand函数为伪随机数生成器播种。

//srand函数定义
void srand( unsigned int seed );

srand函数内种子为常量时,每次生成的随机数相同

srand(1);
int random = rand();

在这里插入图片描述
情况三:
srand函数内种子需要时刻变化,才能完成每次生成随机数不同。
使用时间戳
拿时间戳设置随机数的生成起点,在MSDN内查看time函数
发现其返回值实际为Long类型
在这里插入图片描述

在这里插入图片描述

//time函数定义
time_t time( time_t *timer );
srand((unsigned int)time(NULL));
int random = rand();

在这里插入图片描述
此时生成的数字不够随机,比较相近,原因在于srand函数在game函数内调用,game函数在主函数内调用多次,将srand函数调用放在主函数体内,整个工程只调用一次。
在这里插入图片描述
在这里插入图片描述
修改后,生成随机数完成
在这里插入图片描述
情况四:想要控制生成的随机数范围

rand()%100;//将范围控制在0-99
rand()%100+1;//将范围控制在1-100

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("**********************************\n");
printf("*********** 1.play **********\n");
printf("*********** 0.exit **********\n");
printf("**********************************\n");
}
//TDD-测试驱动开发。
//RAND_MAX--rand函数能返回随机数的最大值。

void game()
{
	int random_num = rand()%100+1;
	int input = 0;
	while(1)
	{
		printf("请输入猜的数字>:");
		scanf("%d", &input);
		if(input > random_num)
		{
			printf("猜大了\n");
		}
		else if(input < random_num)
		{
			printf("猜小了\n");
		}
		else
		{
			printf("恭喜你,猜对了\n");
			break;
		}
	}
}
int main()
{
	int input = 0;
	srand((unsigned)time(NULL));
	do
	{
		menu();
		printf("请选择>:");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			game();
			break;
		case 0:
			break;
		default:
			printf("选择错误,请重新输入!\n");
			break;
		}
	}while(input);
	return 0;
}

goto语句
C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。
从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。
但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程,例如一次跳出两层或多层循环。
这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环。
下面是使用goto语句的一个例子:
一个关机程序

#include <stdio.h>
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;
}

而如果不适用goto语句,则可以使用循环:

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

关于shutdown命令的扩展-(请点这里)
goto语言真正适合的场景如下:

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


本章完

疑问(未解决)
数组名arr本质是地址,sizeof是怎么确定数组长度的

	int arr[] = { 1,2,3,4,5,6,7 };
	int k = 4;
	//写一个代码,在arr数组(有序)中找到4
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

回忆字符数组

"hello hehe.\n"

这种由双引号引起来的一串字符称为字符串字面值,或简称字符串。
注:字符串的结束标志是一个\0的转义字符。在计算字符串长度的时候\0是结束标志,不算做字符串内容。

char arr1[] = "hehe";
char arr2[] = { 'h', 'e', 'l', 'l', 'o'};
char arr3[] = { 'h', 'e', 'l', 'l','o', '\0' };
printf("%s\n", arr1);
printf("%s\n", arr2);
printf("%s\n", arr3);

在这里插入图片描述


练习题

1.下面代码执行的结果是:

#include <stdio.h>
int main()
{
	int  i = 0;
	for( i = 0;i<10;i++)
	{
		if(i = 5)
			printf("%d",i);
	}
	return 0 ;
}
  • 1 2 3 4 5 6 7 8 9 10
  • 5 5 5 5 5 5 5 5 5 5 5
  • 死循环的打印5√
  • 0 1 2 3 4 5 6 7 8 9
    2.关于if语句说法正确的是
  • if语句后面只能跟一条语句
  • if语句中0表示假,1表示真
  • if语句是一种分支语句,可以实现单分支,也可以实现多分支√
  • else语句总是和它的对齐的if语句匹配
    1不能表示所有的真

3.关于switch说法不正确的是

  • switch语句中的default子句可以放在任意位置
  • switch语句中case后的表达式只能是整形常量表达式
  • switch语句中的case子句必须在default子句之前√
  • switch语句中case表达式不要求顺序
int func(int a)
{
	int b;
	switch (a)
	{
		case 1: b = 30;
		case 2: b = 20;
		case 3: b = 16;
		default: b = 0;
	}
	return b;
}

则func(1) = {}

  • 30
  • 20
  • 16
  • 0√

5.switch(c)语句中,c不可以是什么类型

  • int
  • long
  • char
  • float√
    如果是char类型识别ascii码值即可
    6.下面代码的执行结果是什么
#include <stdio.h>
int main()
{
	int x = 3;
	int y = 3;
	switch( x%2 )
	{
	case 1:
		switch(y)
		{
			case 0:
				printf("first");
			case 1:
				printf("second");
			default:
				printf("hello");
		}
	case 2:
		printf("third");
	}
	return 0;
}
  • secondthird
  • hello
  • firstsecond
  • hellothird√
    7.从大到小输出
    写代码将三个数按从大到小输出
//2.b,c比较,大的放b,小的放c,a,b比较,大的放a。排出最大的到a。再比较bc
	int a = 1;
	int b = 2;
	int c = 3;
	int tmp = 0;
	if (b > c)
		;
	else
	{
		tmp = b;
		b = c;
		c = tmp;
	}
	if (a > b)
		;
	else
	{
		tmp = a;
		a = b;
		b = tmp;
	}
	if (b > c)
		;
	else
	{
		tmp = b;
		b = c;
		c = tmp;
	}

	printf("从大到小依次为%d, %d, %d \n", a, b, c);

8.打印三的倍数的数
写一个代码打印1-100之间所有3的倍数的数字

//规律:三的倍数%3 == 0
int i = 1;
	while (i <= 100)
	{
		if (i % 3 == 0)
			printf("%d  ", i);
		i++;
	}

9.最大公约数
给定两个数,求这两个数的最大公约数
分析:用辗转相除法
大数/小数 -余数1
小数/余数1 -余数2
余数1/余数2 - 余数3
当余数为0时此时的被除数即为最大公约数

int a = 0;
	int b = 0;
	int tmp = 0;
	printf("输入两个数,以空号隔开\n");
	scanf("%d %d", &a, &b);
	if (0 == a / b)
	{
		//说明a为小数
		tmp = a;
		a = b;
		b = tmp;
	}
	while (0 != a%b)
	{
		tmp = a%b;
		a = b;
		b = tmp;
	}
	printf("这两个数字的最大公约数为 %d", b);

10.打印1000年到2000年之间的闰年
分析:闰年的标准:
普通闰年:公历年份是4的倍数,且不是100的倍数的,为闰年(如2004年、2020年等就是闰年)。
世纪闰年:公历年份是整百数的,必须是400的倍数才是闰年(如1900年不是闰年,2000年是闰年)。

	int i = 1000;
	while (i <= 2000)
	{
		if ((i % 4 == 0) && (i % 100 != 0))
			printf(" 普通闰年,%d \n", i);
		if (i % 400 == 0)
			printf("世纪闰年,%d \n", i);
		i++;
	}
	

11.打印100-200之间的素数
素数:只能被1和自身整除
用试除法,即每一个数字都用2到他自身-1的数字除,观察是否有可整除的除数,有则不是素数

	int i = 0;
	int j = 0;
	for (i = 100; i <= 200; i++)
	{
		for (j = 2; j < i; j++)
		{
			if (i%j == 0)
			{
				break;//说明i不是素数,无需检测,直接跳出测下一个
			}
		}
		if (j == i)
			printf(" %d ", i);
	}

打印素数优化
思路:如果一个数字不是素数,一定可以表示为 i = a*b;并且a或b中一定有一个数字是<= 开平方i
换句话说例如,判断15是否为素数,只要在2-√15中找到一个数把15整除,还是试除法,不过除的少了
库函数sqrt(15)为 开平方函数,头文件<math.h>
优化1

for (j = 2; j < sqrt(i); j++)

优化2

for (j = 2; j < i/2; j++)

优化3:跳过偶数

for (i = 101; i <= 200; i+=2)
	{
		for (j = 2; j < i; j++)//此处可按优化1,2修改
		{

12.关于while(条件表达式)循环体,以下叙述正确的是()?(假设循环体里面没有break,continue,return,goto等等语句)

  • 循环体的执行次数总是比条件表达式的执行次数多一次
  • 条件表达式的执行次数总是比循环体的执行次数多一次√
  • 条件表达式的执行次数与玄幻提的执行次数一样
  • 条件表达式的执行次数与循环体的执行次数无关
    13.有以下程序
#include <stdio.h>
int main()
{
	int a = 0,b = 0;
	for( a = 1,b = 1;a <= 100;a++)
	{
		if( b >= 20) break;
		if (b % 3 == 1)
		{
			b = b+3;
			continue;
		}
		b = b-5;
	}
	printf("%d\n",a);
	return 0;
}

程序的输出结果是?

  • 10
  • 9
  • 8√
  • 7

14.数9的个数
编写程序数一下1到100的所有整数中出现多少个数字9
思路:
%10取出个位的9
/10后%10取出十位的9

	int i = 0;
	int count = 0;
	for (i = 1; i <= 100; i++)
	{
		if (i % 10 == 9 )
			count++;//个位为9
		if ((i / 10) % 10 == 9)
			count++;//十位为9
	}
	printf("1-100中数字9的个数为 %d \n",count);

15.分数求和
计算1/1-1/2+1/3-1/4+1/5……+1/99-1/100的值,打印出结果(交错加减)
细节
1/2结果为整形0
1.0/2结果为浮点数

int main()
{
	int i = 0;
	double sum = 0;
	int flag = 0;
	for (i = 1; i <= 100; i++)
	{
		/*sum += flag * 1.0 / i;
		flag = -flag;*/

		if (i % 2 != 0)
			sum += 1.0 / i;
		else
			sum -= 1.0 / i;
	}
	printf(" %lf ", sum);

	return 0;
}

16.求最大值
求10个整数中最大值

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int max = arr[0];//细节,不要随便赋值0
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		if (arr[i] > max)
		{
			max = arr[i];
		}
	}
	printf("max = %d ", max);
	return 0;
}

17.乘法口诀表

int main()
{
	int i = 0 ,j = 0;
	for (i = 1; i < 10; i++)
	{
		for (j = 1; j <= i; j++)
		{
			printf(" %d*%d = %d ",j,i,i*j);
		}
		printf("\n");
	}
	return 0;
}

在这里插入图片描述
发现三四列对不齐
使用

❤%2d

%2d 意思为打印该数字的时候,打印两位,如果不够两位,则用空格补齐。其中%2d为右对齐,%-2d为左对齐
%2d效果
在这里插入图片描述
%-2d效果
在这里插入图片描述
18.二分查找
编写代码在一个整形有序数组中查找具体的某个数
要求:找到了就打印数字所在的下标,找不到则输出:找不到
在这里插入图片描述
代码见上文

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值