目录
1.1 计算n!
当我们看到n!时会想到n!=1*2*3*……*n 这个计算的本质就是循环!
我们可以先定义一个字母i=1或者i=0也行,反正循环里面是要重新定义的
然后定义一个字母n,让n可以手动输入任意数字
使用for循环
代码如下:
int main()
{
int i = 0;
int n = 0;
scanf("%d", &n);
int ret = 1;//创建一个数字产生乘积让前一个i可以与后一个i相乘
for (i = 1; i <= n; i++)
{
ret = ret * i;//当i进入循环,ret会随i的变化而变化
}
printf("%d", &ret);
return 0;
}
1.2 计算1! + 2! +……+ 10!
上一题中我们已经能算出一个n!,这题我们要将这些n!相加
我们可以新定义一个字母来存放累加的数
使用两次for循环可以解决
有小伙伴看到这里就迫不及待的去写了,不就是两个for循环吗,于是给大家演示一个错误代码:
int main()
{
int i = 0;
int n = 0;
int ret = 1;//定义一个字母,当数字产生乘积时,让前一个i可以与后一个i相乘
int sum = 0;//定义一个字母,使得每次算出的结果相加
for (n = 1; n <= 10; n++)
{
for (i = 1; i <= n; i++)
{
ret = ret * i;//当i进入循环,ret会随i的变化而变化
}
sum = sum + ret;
}
printf("%d", sum);
return 0;
}
细心的小伙伴调试一下会发现,当n=3时,3!的数字就不对了,怎么回事呢?
我们可以看到当n=3时,ret≠1而是ret=2,原来是刚刚的操作使ret叠加了,我们现在只需要强制的将ret在每次循环的开始改为ret=1就能解决。
int main()
{
int i = 0;
int n = 0;
int ret = 1;
int sum = 0;
for (n = 1; n <= 10; n++)
{
ret = 1;//强制将ret=1
for (i = 1; i <= n; i++)
{
ret = ret * i;
}
sum = sum + ret;
}
printf("%d", sum);
return 0;
}
虽然这样可以计算了,但是还是有些啰嗦,能不能只用一个循环呢?我们从数学公式的本质入手:
1! =1
1! +2! =3
1! +2! +3! =9
观察一下,你就能够发现:
1! +2! +3!=( 1! +2! ) * 3
也就是说3! =2! * 3
这就好办了,我们只需要在算完一次后先存下结果,再用结果乘以下一个数字
代码如下:
int main()
{
int i = 0;
int n = 10;
int ret = 1;
int sum = 0;
for (i = 1; i <= n; i++)
{
ret = ret * i;
sum = sum + ret;
}
printf("%d", sum);
return 0;
}
2.1 在有序数组中查找某个具体的数字
看到这个题目的第一想法是什么?——内心想:不就是查找吗?判断有没有相等的就行了,然后咔咔一顿写。
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//一个有序数组
int k = 7;//要查找的数字
int i = 0;
int flag = 0;
for (i = 0; i < 10; i++)
{
if (arr[i] == k)
{
printf("找到了,下标是:%d\n", i);
flag = 1;
break;
}
}
if (flag == 0)
{
printf("没找到\n");
}
return 0;
}
这个代码本质上是没什么问题,就是太慢了。如果在1~100内,查找78,我们怎么查?是不是先猜50?然后我们查找的范围是不是就变成了50~100,比刚才一个个按顺序查找快了很多。这种方式我们称之为“二分查找”或者是“折半查找”。
2.2 二分查找
首先我们是直接找数组的中间数,只需要用下标来查找,那么数组中间的下标就是(左下标+右下标)/2
我们可以用left表示左下标,right表示右下标,mid表示中间下标
我们要找的数字肯定是在左右下标中间的,当left>right时肯定是找不到任何数的,所以循环的条件就是left>=right
当要查找的数字>mid时,我们的 left 右移到mid+1的地方
当要查找的数字<mid时,我们的right左移到mid- 1的地方
(这里不理解的可以画图分析一下)
搞定了这些后你就会发现有两种情况会导致程序结束:1是找到了,2是没找到
这时我们就可以定义一个标记flag,一开始定义flag=0;当“找到了”时,flag=1
在程序的最后再判断flag
代码如下:
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 7;//要查找的数字
int left = 0;//左下标
int right = 9;//右下标
int flag = 0;
while (left<=right)
{
int mid = (left + right) / 2;//求出中间下标
if (arr[mid] > k)
{
right = mid - 1;
}
else if (arr[mid] < k)
{
left = mid + 1;
}
else
{
printf("找到了,下标为:%d\n",mid);
flag = 1;
break;
}
}
if (flag == 0)
{
printf("找不到\n");
}
return 0;
}
3.1 字符从两端移动,向中间汇聚
比如说,我想在屏幕上打印一段字幕“welcome to CSND !!!”并且这个句子从两端移动,向中间汇聚:
1.创建一个字符串里面存放“welcome to CSDN !!!”
2.为了有汇聚这个效果,我们可以再创建一个字符串使得两个字符串中的元素可以替换,当然替换的前提条件是两个字符串的长度相同。
3.因为是从两端开始汇聚,所以我们需要知道如何替换左右两边的元素。下标是每个元素都有的,我们定义左下标为left,右下标为right,因此最左边的下标为0,最右边的下标就是字符串长度-1。
(这里 “最右边的下标就是字符串长度-1” 是因为字符串的最后结尾是“\n”)
(字符串的长度可以用“strlen”求出,他的头文件是#include<string.h>)
4.显然我们一次次替换不可能停留在第一个,左下标要右移:left++; 右下标要左移:right - -;
再使用一个循环就搞定,循环的条件就是 左下标<=右下标 。代码如下:
int main()
{
char arr1[] = "welcome to CSDN !!!";
char arr2[] = "*******************";
int left = 0;
int right = strlen(arr1)-1;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
left++;
right--;
}
return 0;
}
然后就可以看到:
完成是完成了,但是不够美观。我想要的是只有一排,然后不断往中间变化的。
3.2 字符从两边向中间一个一个跳出来
在上一题的基础上,我们加一点东西进去:
这时就给大家介绍一个新的库函数:
system("cls")
头文件是#include<string.h>。这个函数有清屏的效果,可以再每一次循环后清屏以便形成我想要的结果。
值得注意的是:当我们的句子完全显示出来后,应为有这个函数存在,他依然是会清屏的,我们要想保留住这个句子,还需要在循环结束后打印出来。
新的问题出现了:他变化的太快了,我都没有反应过来,他就已经结束了。
哈哈,没关系,在介绍一个新函数给你:
sleep函数
单位是毫秒,头文件是#include<windows.h>。
在这道题中,我想他一秒跳出一个,只用加上Sleep(1000); 就行啦
最终代码如下:
int main()
{
char arr1[] = "welcome to csdn!!!!!";
char arr2[] = "*******************";
int left = 0;
int right = strlen(arr1)-1;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
Sleep(1000);
system("cls");
left++;
right--;
}
printf("%s\n", arr2);
return 0;
4.模拟用户登录情景
只允许输入三次密码,若三次密码均输入错误,则退出程序。
既然只允许输入三次密码,for循环可以解决
有登录成功和密码错误两个结果,if语句可以解决
为了区别是登录成功退出程序还是密码错误退出程序,可以有一个记号flag
*重点*
strcmp函数
判断两个字符串是否相等不能直接使用“==”,应该使用 strcmp函数,头文件是#include<string.h>,strcmp函数有返回值
int ret = strcmp(password,"123456");
如果第一个字符串小于第二个字符串,返回<0的数字
如果第一个字符串大于第二个字符串,返回>0的数字
如果第一个字符串等于第二个字符串,返回0
int main()
{
int i=0;
char password[] = { 0 };
int flag = 0;
for (i = 1; i <= 3; i++)
{
printf("请输入密码:_\n");
scanf("%s", password);//数组名本质上就是地址,所以这里不需要取地址
if (0==strcmp(password,"123456"))
{
printf("登陆成功!");
int flag = 1;
break;
}
else
{
printf("第%d次密码错误\n", i);
}
}
if (flag == 0)
{
printf("三次密码均输入错误,退出程序!");
}
return 0;
}