目录
1 习题1:将输入的字符进行打印
#include <stdio.h>
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)
putchar(ch);
return 0;
}
函数运行结果:
getchar函数
基本介绍:
getchar的作用是从标准输入stdin(例如键盘)中得到一个字符。
函数返回值:int类型。
如果读到字符,返回值是ASCII码值,如果读取时候遇到错误或者文件结束,就会返回EOF,EOF是什么呢?EOF就是-1。EOF是end of file .它是文件的结束标志。
利用printf将getchar获取的字符进行打印:
还有一个与getchar对应的函数就是putchar,putchar是输出一个字符。
回归到代码
getchar读取的字符放到ch里,如果字符不等于EOF,就说明它不是遇到结束和错误了,这个时候就是正常读取一个字符,然后就把这个字符打印到屏幕上。
程序运行后,getchar是从缓冲区进行读取,一开始,因为键盘什么都没有输入进去,这个时候缓冲区是空的,getchar一看缓冲区是空的,它就会等待。这时输入A又按了回车,相当于把A和\n放入到缓冲区了。getchar读到第一个字符A后就放入到字符变量ch里了,就执行下面程序了,把字符A打印出来。打印出来后,又继续读取getchar,这时会读到\n,读到\n后,\n放到ch里,这时把\n再打印出来,\n打印出来后就是换行的效果。就会到下一行了,所以在输入下一个字符时,其实是输入到下一行去了。这个换行的动作是输入的回车\n。
2 getchar清理缓冲区
先看以下代码
代码中定义了字符数组password,scanf让其输入字符串,格式为%s,字符串需要用字符数组存起来,password前没有取地址符&是因为数组的数组名本来就是一个地址。
理论上上图中的代码执行的逻辑是输入密码后,紧接着是确认密码,输入Y或N。但实际上还没有输入Y,直接就打印出确认失败了。
因为getchar发现缓冲区里有东西,所以它直接拿走了,如果它发现缓冲区里没有东西,他必然会停下来。只要把缓冲区的\n清除掉,这个时候getchar就会等待让我们输入外部的N和Y。
如下图所示:在后面加上清理缓冲区语句getchar();来处理'\n'。
上图中加了一条getchar()语句,后当输入密码“123456 abcdef”后,还会直接打印“确认失败”。为什么会失败呢?
当scanf读取的时候,它会把空格前面的东西读取,这个时候它拿走的是123456,它把123456拿走后,缓冲区里还有很多东西。紧接着用getchar来读取字符,getchar只能消耗一个字符,消耗一个字符后,缓冲区还有好多字符。所以没有停下来。
当输入的信息里面,如果有很多东西放到缓冲区里的时候,可以放多个getchar让它读,一直读到当它把‘\n’都读走的时候,让它停下来。就说明把缓冲区的内容都读出来了,这个时候停下来就可以。
如下图所示,就是清理缓冲区中的多个字符。
;空语句,什么都不干。
3 计算1!+2!。。。+n!
用两层for循环来实现,内层for循环是产生n!,外层for循环是计算累加和
【注意】 在内层循环前要使得ret重置为1,每次开启执行内部循环时,每次求阶乘之前,要使得ret初始值为1。
用一层for循环来实现:
4 在有序数组中查找具体某个数字
折半查找/二分查找
算法思想:找出这一组元素中最中间那一个元素的下标,然后以这个元素和要查找的元素进行比较,看要找到元素在中间元素的左边还是右边,比较后,可以去掉另一半,然后将中间元素的下标变为左下标或右下标。
5 编写代码多个字符从两端向移动,向中间汇聚
思路:
程序:
(1) 求字符串长度:strlen(arr) 头文件是#include <string.h>
(2)打印字符串:printf(“%s”,arr)
(3)sleep( )功能睡眠一段时间。函数单位是毫秒,它的头文件是<windows.h>
(4)system(“cls”) 清空屏幕。它的头文件是<windows.h>
(5)求字符串长度:strlen(arr)
(6)求最后一个字符的下标:strlen(arr)-1
6 编写代码,模拟用户登录,用户登录三次
两个字符串比较时,不能用“==”来比较,以下代码是错误的:
两个字符串的比较不能使用==,而应该使用strcmp函数,字符串比较函数。
字符串比较函数strcmp:把两个字符串同时传递给strcmp函数,如果发现两个字符串相等,就说明密码输入对了,函数返回值就为0。
程序:
上面程序中,当字符串函数比较两个字符串相等后,用break跳出for循环,跳出for循环,来到了for循环下面,来到for循环下面有两种情况,一种是三次密码全输错了,也会来到这,所以到这个地方后要判断i的值是否为3,如果为3,说明三次密码都输入错了。就提示“三次密码都输入错误”。
【补充】
(1)strlen和strcmp函数是字符串函数,需要引用头文件<string.h>
strcmp的比较方法:比较对应位置上字符的ASCII码值。当出现不相等的情况下,大的字符所在的字符串大于另外一个字符串。
例如比较“abcdef”和“abccqqqqq”,是怎么比较的呢?a和a相等,接着往下比,b和b相等,接着往下,c和c相等,接着往下,d大于c,所以第一个字符串大于第二个字符串。这就是比较的方法
(2)scanf(“%s”,password),password前不用加取地址。因为password是一个数组,数组名本来就是地址,就不需要取地址了。
7 写一个猜字游戏
先梳理一下需求:
根据input值做出判断,用switch case来选择,不管进入到哪个case,switch语句走完后,整体框架如下所示
接下来才是猜数字的过程,将猜数字的过程封装到一个函数中game()
Game()游戏中,猜数字游戏,首先得先生成随机数,然后再猜数字。
生成随机数有一个库函数叫rand(),Rand函数需要包含<stdlib>头文件。
Rand()函数的用法:没有参数,返回类型是整形。返回的数字是随机数。
Rand()函数生成的随机数在0-RAND_MAX之间的数字。但这个数字不够随机。rand函数中写的在调用rand()函数之前,还要调用srand函数来设置随机数生成器。
Srand()函数用法:设置一个随机函数的起点。
当srand后的数字发生变化时,生成的随机数字也在发生变化。Srand后的数字是固定值的时候,生成的随机数字也是固定值。srand后面需要传递一个随时变化的值,电脑的时间一直在发生变化。时间发生变化时,就可以把时间传递过去。这个地方传递的是时间戳。时间戳就是时间转化过来的一个数字。
用time()函数来获取时间戳。Time函数传一个空指针进去,因为不想用这个参数,所以传一个空指针。Time函数的返回类型是time_t。time_t也是一个整形类型,只不过它是结构体定义的类型。本质上也是一个整形类型。利用强制类型转换,将time()函数的返回值转换为unsigned int 类型。Time函数需要的头文件是time.h。
通过上述方法生成的随机数不够随机。原因是srand确实要在rand函数之间调用,但是随机数起点的设置,但是随机数起点的设置srand函数只需要调用一次就可以了。所以把srand函数放到主函数里,起点只设置一次。
要求是生成1-100之间的随机数,而现在生成的随机数是0-32767,可以让生成的随机数模100,就可以产生0-100之间的随机数了。 模100的余数是0-99,然后加1,范围就变为了1-100了。对生成的随机数取模100,任何一个数字模100,余数肯定是0-99的范围。余数肯定不能超过100,超过100,模100后,还可以再商1。
生成后随机数后,就要求猜数字了。
8 求两个数的最大公约数
方法一:从两个数中的最大的数往下减1,找到第一个能够同时被两个数整除的数字,那就是最大公约数。
方法二:辗转相除法
思路:
程序:
或
举一反三:
求最小公倍数
方法一:从最大值开始加1
方法二:最小公倍数=m*n/最大公约数
9 打印1000-2000之间的闰年
判断规则:
代码一:
代码二:
10 打印100-200之间的素数
方法一:
break跳出内部for循环后,来到了内层for循环下面,而来到这里有两种情况:(1)一种是break跳到这个地方(2)j不再小于i的时候,会使内部for循环结束,来到这个地方,这种情况就是把2~i-1的数字都试除了一遍,发现i不能整除j的,这时i就是素数。所以到这里要判断(i==j),就说明是素数。
方法二:利用一个状态标志flag来判断是否是素数。
方法三:上面是拿2~i-1的数值来整除j的。这样试除次数减少很多,可以用2~平方根去整除。
计算开平方的库函数:sqrt(),用来计算开平方的。需要的头文件是<math.h>
方法四:进一步优化:偶数不能是素数,让i从101开始,让i每次+=2。把偶数都去掉了,只判断奇数。
11 关机程序
C语言提供了一个函数:system()——执行系统命令的。
把字符串存起来,用字符数组,字符数组里面可以放一系列的字符。
两个字符串的比较不能用==比较,应该使用strcmp函数。
用goto语句实现:
用循环来实现: