【手把手带你练习】分支和循环语句

2021年6月19日 4点热度 0条评论 来源: Stella_sss

【手把手带你练习】分支和循环语句

前言

上一篇文章我们介绍了分支和循环语句,但是光说不练假把式,下面我们就通过以下练习来对上一章的内容进行巩固吧!

分支语句练习

1. 判断一个数是否为奇数

解题思路:
整数分为奇偶数,偶数能被 2 整除,奇数不能被 2 整除,所以如果一个数除以 2 余 0,则该数是偶数,否则是奇数。

具体做法:
先输入一个数用 i 保存起来,再用 if 语句进行判断。

代码如下:

#include<stdio.h>
int main()
{ 
	int i = 0;
	scanf("%d", &i);//先输入一个数,放到i中
	if (i % 2 == 0)//if 语句进行判断
	{ 
		printf("%d 不是奇数",i);
	}
	else
	{ 
		printf("%d 是奇数",i);
	}
	return 0;
}

输入5,输出结果如下:

2. 输出1-100之间的奇数

解题思路:
法一:把1~100的数一一列举,再依次判断是否为奇数,是奇数的输出,否则不输出。

具体做法:
先用一个循环把1~100的数列出来,再在循环中进行是否为奇数的判断,是则输出,否则不输出。

代码如下:

#include<stdio.h>
int main()
{ 
	int i = 1;
	while (i <= 100)//列出1-100
	{ 
		if (i % 2 != 0)//判断是否为奇数
			printf("%d ", i);//是则输出
		i++;
	}
	return 0;
}

输出结果如下:

法二:因为连续奇数之间的差值为 2,而我们可以很容易的知道第一个奇数是1,所以只要依次加上差值 2,就可以写出1~100之间的所有奇数

具体做法:
先输出1,再依次+2输出,知道 i >100为止

#include<stdio.h>
int main()
{ 
	int i = 1;
	while (i <= 100)
	{ 
		printf("%d ", i);//从1开始输出
		i += 2;//每次+2再输出
	}
	return 0;
}

输出结果如下:

循环语句练习

3. 计算 n 的阶乘。

解题思路:
n!=1 * 2 * 3 * …… * (n-1)* n

具体做法:
先定义一个整形 z=1,再依次把1~n乘以 z 。

代码如下:

#include<stdio.h>
int main()
{ 
	int i = 1;
	int z = 1;//用来储存乘积的值
	int n = 0;
	scanf("%d", &n);
	for (i = 1; i <= n; i++)//依次列出1-n的值
	{ 
		z *= i;//进行累乘
	}
	printf("n! = %d", z);
	return 0;
}
}

输入4,输出结果如下:

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

解题思路:
第三题中我们已经求出了n!,现在要把 1~10的阶乘加起来,所以我们应该用到两个循环:
一个用来求阶乘,一个用来依次把阶乘加起来。

具体做法:
先定义一个整形 z=1,再依次把1~n乘以 z 。

代码如下:

#include<stdio.h>
int main()
{ 
	int i = 1, j = 1, z = 1;
	int sum = 0;
	for (i = 1; i <= 10; i++)//列出1-10
	{ 
		for (j = 1; j <= i; j++)
		{ 
			z *= j;//计算阶乘
		}
		sum += z;//把计算的阶乘加起来
	}
	printf("sum = %d", sum);
	return 0;
}

输出结果如下:

但是,我们怎么知道这个结果是不是正确的呢?

计算1~10的阶乘的和有点太大, 我们可以先用1-3的阶乘的和来验证一下。

1!+2!+3!=9。结果应输出9,而上图结果却输出了15,说明一定是哪里出了bug,这时候应该怎么办呢?

遇到问题先别慌,给up主点个赞放松一下,咱们再一步步来找bug!

现在我们的程序可以正常运行,说明我们是运行的时候出了错误,那么我们可以用调试的方法让代码一步一步执行,观察代码是不是按照我们的期望执行的,当我们找到代码执行与期望不符的地方,说明bug就在那里。

按住 F10 或者Ctrl + F10进入调试。

F10 - 单步执行(逐过程)
F11 - 单步执行(逐语句) - 遇到自定义函数,想进入函数时按F11 用于看函数内部细节时

程序进入调试后,打开一个监视窗口



继续按F10观察程序的运行。


我们继续往下调试。

调试继续进行。

思考一下,为什么 z 变成了12?

我们求3!的时候,z 应该是 1 * 2 * 3 = 6。
而监视器中却是12,说明在 z * 1 * 2 * 3 之前,z 的值不是 1 ,而是 2 。那么为什么 z 的值是 2 呢?

因为 z 的定义放在了for循环的外面,每一次我们求完 z 的值之后,z 并没有被重置,而是把值累积了起来,于是求出的值与理想中的不一致。

所以,我们发现,是由于每次求完阶乘之后,z 的值没有重新赋为 1,导致了错误,所以我们应该在内层的 for 循环前把 z 重新赋为 1 ,再运行结果。

这时候我们再把原来改为 3 的值改回 10。

#include<stdio.h>
int main()
{ 
	int i = 1, j = 1, z = 1;
	int sum = 0;
	for (i = 1; i <= 10; i++)
	{ 
		z = 1;
		for (j = 1; j <= i; j++)
		{ 
			z *= j;//计算阶乘
		}
		sum += z;//把计算的阶乘加起来
	}
	printf("sum = %d", sum);
	return 0;
}

再次运行程序,结果如下:

但是大家有没有发现,这个方法其实有点繁琐。我们每求一个阶乘都要从 1 开始往后乘。而实际上,通过仔细观察我们发现:

1!=1
2!=1 * 2 =1!*2
3!=1 * 2 * 3 = 2!*3
4!=1 * 2 * 3 * 4=3!*4
5!=……………=4!*5
6!=……………=5!*6
7!=……………=6!*7
……
n!=……=(n-1)!*n

那么我们只需要在前面求出来的 (n-1)!的基础上 *n就行了。
代码简化如下:

#include<stdio.h>
int main()
{ 
	int i = 1, z = 1;
	int sum = 0;
	for (i = 1; i <= 10; i++)
	{ 
		z *= i;//计算阶乘 - n!=(n-1)!*n
		sum += z;//把计算的阶乘加起来
	}
	printf("sum = %d", sum);
	return 0;
}

运行结果和上面一样:

通过上面的问题,我们应该学会如何运用调试来找bug。
如果你觉得以上方法对你有用,记得动动手指点赞收藏关注一波噢

综合练习

5. 在一个有序数组中查找具体的某个数字n。

问题描述:
编写一段代码,在一个有序数组arr[ ]={1,2,3,4,5,6,7,8,9,10},中查找具体的某个数字,数字为7。

思路:
先编写出一个有数组,然后依次把我们要找的数字与数组中的每一个元素进行比较,找到则输出数组下标,找不到则输出“找不到”。

具体做法:

  1. 先把要有序数组、要找的具体数字和数组下标存起来。
  2. 计算数组元素个数。
  3. 将每个元素依次与要找的数进行比较
  4. 找到了则打印数组下标,跳出循环;如果没找到,则打印“找不到”


具体代码如下:

#include<stdio.h>
int main()
{ 
	int arr[] = {  1,2,3,4,5,6,7,8,9,10 };//定义一个有序数组
	int k = 7;//定义我们要找的具体数字
	int i = 0;//定义下标
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数
	for (i = 0; i < sz; i++)
	{ 
		if (arr[i] == k)//每个元素依次与k进行比较
		{ 
			printf("找到了,下标为%d\n", i);
			break;//找到之后,跳出循环;没找到则继续找直到i>=k
		}
	}
	if (i >= sz)//当i>=k,说明没有找到
	{ 
		printf("找不到");
	}
	return 0;
}

程序运行结果如下:

k 改为17时,运行结果如下:

但是我们发现这是一个有序的数组。

如果我们要找的数在最后一个,那程序就要找很多次,有没有办法可以对代码进行优化呢?

答案是有的。既然这是一个有序数组,那么我们可以思考从中间查找,就像玩猜数字一样,我们先猜一个数字,然后对方告诉你猜大了还是猜小了,如果猜大了,我们就往小了猜,如果猜小了,我们下次就往大了猜,这样比从1开始依次往大猜效率会更高。

当我们每次猜都从中间值猜起,那么我们每次缩小的范围就更多,在理论上效率更高。

这也就是我们接下来要实现的折半查找(二分查找)。

那么我们应该如何实现呢?


实现代码如下:

#include<stdio.h>
int main()
{ 
	int arr[] = {  1,2,3,4,5,6,7,8,9,10 };
	int k = 17;
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数
	int left = 0;//最左边元素下标
	int right = sz - 1;//最右边元素下标
	while (left<=right)
	{ 
		int mid = (left + right) / 2;//求中间元素下标
		if (arr[mid] > k)//每个元素依次与k进行比较
		{ 
			right = mid - 1;
		}
		else if (arr[mid] < k)
		{ 
			left = mid + 1;
		}
		else
		{ 
			printf("找到了,下标为%d\n", mid);
			break;//找到之后,跳出循环;
		}
	}
	if (left>right)//当left>right,说明没有找到
	{ 
		printf("找不到");
	}
	return 0;
}

程序运行结果如下:

k 改为17时,运行结果如下:

虽然这段代码看起来比第一种方法更长,但是当要查找的数组很大时,程序查找的速度就会快很多。

6. 从两边开始逐渐打印字符串。

问题描述:
编写一段代码,使“Hello world!”字符串从两边开始逐渐向中间打印,直到打印出整个字符串为止。
即:屏幕上如下逐渐打印出“Hello world!”
##########
H########!
He######d!
Hel#####ld!
Hell####rld!
Hello##orld!
Hello world!

解题思路:
字符串从“##########”变成“Hello world!”,首先应该分别用arr1和arr2两个字符类型数组来保存,然后再依次把arr2中两端的值赋给arr1中两端的值,每赋值依次,打印依次,依次来实现逐渐打印。

具体做法:

  1. 首先分别定义两个字符串,用strlen函数求出字符串长度,然后写出左右两端元素的下标
  2. 分别将arr2中两端元素的值传给arr1,然后打印arr1。
  3. 因为我们要逐渐打印字符串,所以每次打印之后要引用一个系统函数Sleep( )让程序暂停一下,再继续进行。
  4. 重复2、3步骤直到整个字符串打印出来为止。

求字符串长度的函数:strlen( )

当然,我们也可以用sizeof来实现:

len = sizeof (arr1) / sizeof (arr1[0])

让程序停顿的函数:Sleep(1000)

实现代码如下:

#include<stdio.h>
#include<string.h>
#include<windows.h>
int main()
{ 
	char arr1[] = "############";//分别定义两个字符串
	char arr2[] = "Hello world!";
	int len = strlen(arr1);//求字符串长度 
	//strlen - 用于求字符串长度的函数,使用时要引头文件<string.h>
	int left = 0;//分别定义两端的下标
	int right = len - 1;
	while (right >= left)//循环直到所有元素都打印出来为止
	{ 
		arr1[left] = arr2[left];//将arr2中的左边元素传递给arr1
		arr1[right] = arr2[right];//将arr2中的右边元素传递给arr1
		printf("%s\n", arr1);//打印arr1
		Sleep(1000);//停顿1000毫秒 - 1秒
		left++;//调整两端坐标
		right--;
	}
	return 0;
}

程序运行结果如下:

那么我们有没有办法让所有打印都在一行实现呢?

这时候我们就要借助清空函数的帮忙咯~我们在下一次打印之前,把之前在屏幕上打印的内容都清空,那么每次打印的时候,文字就都出现在第一行啦!

改变后结果如下:

7. 模拟用户登录情景

问题描述:
编写一段代码,模拟用户输入密码,并且只允许输入三次密码,如果密码正确则提示登录成功,如果三次均输入错误,则退出程序。密码为:abcdef

思路:先把密码存到字符串中,然后再把输入的密码与字符串比较,如果一样,则输出登录成功,程序结束;如果不同则重新输入,输入和比较最多循环三次,三次之后程序结束。

具体做法:

  1. 首先定义一个字符串用来存放密码。
  2. 在屏幕上输出“请输入密码:>”提示用户输入密码
  3. 开始一个循环,把用户输入的密码存到1.中定义的字符串
  4. 将字符串与正确密码进行比较,密码正确则输出“登录成功”,跳出循环;密码错误,则输出“密码错误,请重新输入:>”提示用户重新输入密码。
  5. 用 if 语句实现输入超过三次都不正确时,输出“很抱歉,三次密码均错误,您已没有机会”

这里要强调的是,字符串的比较不能直接将两个字符串用“ == ”来判断相等,因为当我们拿password与密码“ abcdef ”进行比较时,passowrd传过去的是password的地址,而“ abcdef ”传的是首元素的地址,我们比较的是实际上是地址而不是字符串的内容。

所以这里在比较字符串的时候,我们要用到字符串函数:strcmp。

详见https://cplusplus.com/reference/cstring/strcmp/?kw=strcmp

代码如下:

#include<stdio.h>
#include<string.h>
int main()
{ 
	int i = 0;
	char password[20] = {  0 };//定义一个字符串来存放密码
	for (i = 0; i < 3; i++)//循环三次,只能输入三次密码
	{ 
		printf("请输入密码:>");
		scanf("%s", password);
		if (strcmp(password, "abcdef") == 0)//对比输入的字符串和密码
		{ 
			printf("登录成功\n");
			break;//密码正确,则跳出循环
		}
		else
		{ 
			printf("密码错误\n");
		}
	}
	if (i >= 3)
	{ 
		printf("很抱歉,三次密码均错误,您已没有机会\n");
	}
	return 0;
}

运行结果如下:

总结

经过上面几道题目的练习,相信你一定对C语言中的分支和循环语句有了更深的认识和理解,我们会发现,灵活地运用分支和循环语句,我们就已经可以解决很多问题了。

最后,本文的代码已上传至Gitee啦!想要的话点击链接自取噢~https://gitee.com/fang-qiuhui/my-code/blob/master/practice_2021_6_19/practice_2021_6_19/practice_2021_6_19.cpp

感谢你看到这里,和我一起努力学习,持续精进,欢迎大家持续关注我的文章噢!

如果你喜欢我的文章,或者觉得本文给你带来了收获,别忘了动动小手指一键三连噢!

    原文作者:Stella_sss
    原文地址: https://blog.csdn.net/weixin_53286472/article/details/118053589
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。