C语言程序练习题(一)

冰冻三尺,非一日之寒;滴水石穿,非一日之功。


前言

这是一篇专门练习分支语句和循环语句的笔记。
分支语句:

  • if
  • switch

循环语句:

  • while
  • for
  • do while

goto语句:


一、循环练习题

1.计算n的阶乘

思路:

n的阶乘的阶乘就是, 1 1 1 ⋅ 2 \cdot 2 2 ⋅ 3 \cdot 3 3 ⋅ 4 \cdot 4 4 ⋅ 5 \cdot 5 5 ⋅ . . . . n \cdot ....n ....n
需要产生数字   1 \ 1  1   n \ n  n之间的数字。
输入的n必须是大于等于1的。

求n的阶乘
#include <stdio.h>
	int main() {
    int i = 0;
    int n = 0;
    int ret = 1;
    //1*2*3*4*5
    scanf("%d", &n);
    for(i = 1; i <= n; i++){
	ret *= i;
	}
    printf("%d ", ret);
    
	return 0;
}

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

思路:

n的阶乘的阶乘就是, 1 1 1 ⋅ 2 \cdot 2 2 ⋅ 3 \cdot 3 3 ⋅ 4 \cdot 4 4 ⋅ 5 \cdot 5 5 ⋅ . . . . n \cdot ....n ....n
求的是1到10各阶层之间的和。
每个阶层乘完后需要用一个变量进行存放。

求1!+2!+3!+…+10!(错误示例)
#include <stdio.h>
	int main() {
    int i = 0;
    int n = 0;
    int ret = 1;
    int sum = 0;
 //由于这里10!的数太大不利于计算,我们暂且用3!作为替代
 //举个例子:1!+2!+3! = 1+2+6 = 9。
    for(n = 1; n <= 3; n++){
    	for(i = 1; i <= n; i++){
			ret *= i;
	}
		sum += ret;
	}
    printf("%d ", sum);
    //打印结果为15.
	return 0;
}

上面这段代码犯了一个经典的错误,ret没有赋初值,导致每次进入循环后,它的值都还保留着。

正确的写法应该是

求1!+2!+3!+…+10!(修正后代码)
#include <stdio.h>
	int main() {
    int i = 0;
    int n = 0;
    int ret = 1;
    int sum = 0;
 //由于这里10!的数太大不利于计算,我们暂且用3!作为替代
 //举个例子:1!+2!+3! = 1+2+6 = 9。
 //3! = 3*2*1
 //2! = 2*1
    for(n = 1; n <= 3; n++){
    	ret = 1;
    	for(i = 1; i <= n; i++){
			ret *= i;
	}
		sum += ret;
	}
    printf("%d ", sum);
    //打印结果为9.
	return 0;
}

但其实这里我们没必要嵌套多一个for循环这么麻烦,此时对代码进行优化。

优化思路:

n的阶乘的阶乘就是, 1 1 1 ⋅ 2 \cdot 2 2 ⋅ 3 \cdot 3 3 ⋅ 4 \cdot 4 4 ⋅ 5 \cdot 5 5 ⋅ . . . . n \cdot ....n ....n
求的是1到10各阶层之间的和。
而每个阶层又等于前面所有项相乘的结果乘以当前阶层。
这时就可以利用ret每次循环后不进行初始化的特点来优化代码。

求1!+2!+3!+…+10!(优化后代码)
#include <stdio.h>
	int main() {
    int n = 0;
    int ret = 1;
    int sum = 0;
    	for(n = 1; n <= 3; n++){
			ret *= n;
			sum += ret;
	}
    printf("%d ", sum);
	return 0;
}

以上就是优化后代码。


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

有序数组指的是已经排好序的数组。
思路:

1、由于是有序数组,即里面的数字都是按大小有序排列好的,虽然可以用遍历的办法来做,但这个效率太低。
2、这时我们就需要一个折半查找的思路,即每次查找都先从所有数字中间开始找起。
3、每次折半查找后再去比较想要查找的数字是否大于或者小于这个折半后的数,假如折半后的数大于想要查找的数,则不需要看右半部分的数字,直接从左半部分的一半开始继续查找,小于这个数则反过来。
4、如此反复并找到具体的某个数字n。

接下来我们看代码实现

有序数组中查找具体的某个数字n
#include<stdio.h>
int main(){
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int k = 7;//要查找的数字
	//在arr这个有序的数组中查找k(7)的值
	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){
				left = mid + 1;
			}
			else if(arr[mid] > k){
				right = mid - 1;
			} 
			else{
				printf("找到了,下标是:%d\n", mid);
				break;
			}
	}
	if(left > right){
		printf("找不到了\n");
	}
	return 0;
}

我们来解剖一下这段代码究竟是怎么回事

1、首先创建一个数组,里面包含数字1~10。
2、用sizeof(数组名)来计算整个数组的元素个数(整个数组的总大小除以一个数组的大小就是这个数组的元素个数)。
3、定义变量int left = 0(下标0)和变量int right = sz -1(数组的元素个数总数-1为最右的下标)
4、再定义一个变量int mid = (left + right) / 2
即:左边下标加右边下标加起来除以,折半取下标。
5、使用if else语句来判断折半后的下标所对应的数是否为k(7)的下标值。
6、如果下标对应的数小于k(7)时,使得下标+1赋值给left。
7、又如果下标对应的数大于k(7)时,使得下标-1赋值给right。
8、如果以上两个条件都不满足时,为找到下标数。
9、用while包裹住int mid变量和if else语句,判断左下标是否小于等于右下标。
10、假如出现交错的情况时,左下标一定大于右下标,此时在while循环外再加一个if语句来打印相应的内容(找不到了)。


4.编写代码,演示多个字符从两端移动,向中间汇聚

思路:

需要先创建两个数组,一个存放符号,另一个存放汇聚用的字符
同时需要给两个下标,同时往中间靠
两个下标重合或交叉时候停止循环

代码实现
#include<string.h>
#include<windows.h>
int main(){
    char arr1[] = "Are you ok??????";
    char arr2[] = "################";
	int left = 0;
	int right = strlen(arr1) - 1;
//这里strlen是计算数组总长度,字符串后面带\0,所以需要-1
	while(left<=right){
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		printf("%s\n", arr2);
		Sleep(1000);//睡眠1秒
		system("cls");//清空屏幕
		left++;
		right--;
	}
	return 0;
}

代码解剖:

1、先建立两个数组存储“welcome to bit”和“##############”。
2、起一个变量left = 0 (赋值0给left,为下标0),和一个变量right = strlen(arr1) - 1 (strlen是求字符串长度的,-1为最右下标)。
3、令arr2[ left ] = arr1[ left ];arr2[ right ]= arr1[ right ];即把arr1的left和right下标所指的字符赋值给arr2。
4、打印字符串%s,arr2。
5、输出完后令left++;right–;(左下标右移,右下标左移)。
6、最终发现是个循环,使用while(left <= right)。
7、strlen函数需要引用头文件#include<string.h>。
8、如果不想要一次性打印出来,可以使用sleep函数,但需要加入头文件#include<windows.h>。
9、看完之后想要清空屏幕可以使用,先system(“cls”);
10、再优化一下,可以在代码最后再放上一个打印。


5.编写代码,模拟用户登陆情景,并且只能登陆三次

限制条件:只允许输入三次密码,如果密码正确则提示登录成功,如果三次均输入错误,则退出程序。

思路:

需要先创建一个数组用作存放用户输入的密码
判断用户输入的密码是否正确
如果错误,重新输入,错误三次,退出程序。

用户登陆
#include<string.h>
int main(){
    int i = 0;
    //假设正确密码为123456
	char password[20] = { 0 };
	
	for(i = 0; i < 3; i++){
		printf("请输入密码:");
		scanf("%s", password);
//if(password == "123456")
//err - 两个字符串比较,不能使用==,应该使用strcmp
		if(strcmp(password, "123456") == 0){
			printf("登录成功\n");
			break;
		}
	}
 	if(i == 3)
 		printf("三次密码均输入错误,退出程序\n");
	return 0;
}

代码解剖:

1、创建一个变量i和一个数组password。
2、使用for循环令i=0; i<3;i++(最多输入3次)
3、printf打印请输入密码的提示,用scanf接收键盘输入的内容,并存放到password数组内。
4、使用if语句,注:这里用的是新函数strcmp,意思是比较两个字符串是否相等,如果对比后相等的话,这个函数会返回0,就有了后面判断的 == 0
5、如果输入密码正确则打印登陆成功且在后面加入break跳出循环,else否则打印密码错误,请重新输入。
6、再在for循环外加入一个if(i == 3),输入三次后,i此时值为3,所以输出三次密码均错误。


总结

这次的练习主要是加深对循环语句的理解,其中有循环内嵌循环以及循环在数组下标中的应用,同时认识了部分新函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值