《啊哈C语言——逻辑的挑战》学习笔记
第一章 梦想启航
第1节 让计算机开口说话
1、基础知识
1)计算机“说话”的两种方式
显示在屏幕上
通过喇叭发出声音
2)计算机“说话”之显示在屏幕上
格式:printf("");
注意:
printf要加“f”
printf后要加括号()
双引号""内是要计算机“说的内容”
所有符号全在英文符号环境下输入
分号;表示语句的结束
3)语言框架
框架:
#include<stdio.h>
#include<stdlib.h>
int main()
{
return 0;
}
4)让计算机“暂停一下”
语句:
system("pause");
1
形式:
“请按任意键继续…”是system(“pause”);输出的一个提示。
5)换行
语句:"\n"
第2节 多彩一点
1、设置命令行的背景颜色与文字颜色
格式:
system(“color 背景颜色数字+文字颜色数字/文字颜色数字”);
详细用法:
color + 两个一位数字 —— 第一个数字:背景色 —— 第二个数字:文字颜色
color + 一个一位数字 —— 只设置文字颜色 —— 背景色仍为默认颜色
注意:
一位数字是16进制——0、1、2、3、4、5、6、7、8、9、a、b、c、d、e、f
示例
#include<stdio.h>
#include<stdlib.h>
int main()
{
system("color f5");
printf("wa wa wa");
system("pause");
return 0;
}
2、相关颜色代码
0=黑色 8=灰色
1=蓝色 9=淡蓝色
2=绿色 a=淡绿色
3=湖蓝色 b=淡浅绿色
4=红色 c=淡红色
5=紫色 d=淡紫色
6=黄色 e=淡黄色
7=白色 f=亮白色
第3节 让计算机做加法
1、过程
输入——存储——计算——输出
2、基础知识
1)赋值号
符号:=
作用:将右边内容赋给左边
2)“小房子”
格式:
int a,b,c;
作用:
存储数值。
作用:
存储数值。
3)代码展示
int a,b,c;
a=1;
b=2;
c=a+b;
过程:
①先将a+b算出来;
②将a+b的值赋给“=”左边的c。
4)“讨债的”
代码:
printf("%d",c);
作用:
将逗号右边“小房子”c中的数值“索取”出来。
5)加法的完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a,b,c;
a = 1;
b = 2;
c = a + b;
printf("%d", c);
system("pause");
return 0;
第4节 数字的家——变量
1、基础知识
1)小数=浮点数
2)变量
“小房子”又叫变量。
3)变量类型/数据类型
int:用来存放整数的类型;
float:用来存放小数的类型。
4)赋值规则
变量中有且仅能存放一个值
变量中存放的始终是最后一次赋的值
5)“=+”两个操作符
a = a + 1;
1
作用:把变量a中的值在原来的基础上增加1。
第5节 数据输出——我说咋地就咋地
1、基础知识
1)将整个算数等式输出
代码展示:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a,b,c;
a-1;
b=2;
c=a+b;
printf("%d+%d=%d",a,b,c);//相当于a+b=c
system("pause");
return 0;
}
分析:
%d按顺序依此向引号后面的变量“讨债”。
2)注意
- printf语句只会输出双引号里面的部分,双引号之外的部分只是对双引号内的部分起到补充说明的作用。
- 通常双引号内部“%d“的个数,和后面变量的个数是相等的。
第6节 数据输入——我说算啥就算啥
1、基础知识
1)让计算机“听”你说
输入语句:scanf("%d%f",变量);
2)取地址符,简称“取址符”
符号:&
为什么输入语句有&,而输出语句没有
答:读入数据时,计算机需要把读入的值存放在小房子a(变量a)中,此时需要知道这个小房子的地址,才能把值准确放入;但输出时,值已经在a中,所以可以直接输出到屏幕上。
3)输入语句的两种写法
写法一:
scanf("%d",&a);
scanf("%d",&b);
写法二:
scanf("%d%d",&a,&b);
注意:
第二种写法更简便,两个“%d”之间不需要空格,“&a”和“&b”之间用逗号隔开。
4)从键盘读入两个数,输出这两个数之和的完整代码
#include<stdio.h>.
#include<stdlib.h>
int main()
{
int a,b,c;
scanf("%d%d",&a,&b);
c=a+b;
printf("%d+%d=%d",a,b,c);
system("pause");
return 0;
}
第7节 究竟有多少种房子
1、基础知识
1)C语言常用的数据类型
数据类型名称 | 用来存放哪种数据 |
---|---|
int | 整数 |
float | 浮点数 |
double | 极大和极小的浮点数 |
char | 字符 |
2)float和double的区别
scanf读入float类型数据用“%f”,读入double类型数据用“%lf”
double可以比float表示的更精确
注意:
printf("%.15f", a);
代码中“%”和“f”之间的“.15”表示保留小数点后15位(四舍五入)。
3)字符数据类型——char
格式:
char a = 'x';
作用:
存放一个字符。
注意:
是单引号而非双引号。
逻辑挑战1:交换小房子中的数
方法一:(临时变量法)
Key:
t = a;
a = b;
b = t;
完整代码:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b, t;
scanf("%d%d", &a, &b):
t = a;
a = b;
b = t;
printf("%d %d", a, b);
system("pause");
return 0;
}
通过创建一个临时变量t,将变量a的值暂时存储起来,然后将b的值赋给a,再将t的值(原a的值)赋给b,从而完成交换。
方法二:(差值法)
Key:
a = b - a;//a与b的差值
b = b - a;//b = a;b减去差值就为a
a = a + b;//a再加上差值就为b,然后将b的值赋给a
完整代码:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b;
scanf("%d%d", &a, &b);
a = b - a;
b = b - a;
a = b + a;
printf("%d %d", a, b);
return 0;
}
第8节 天哪!这怎么能看懂
1、代码规范
- 使用Tab来调整代码格式
2、注释的种类及作用
- “//”——单行注释
- “/**/”——多行注释
- 解释说明本行代码的作用
- 暂时不需要
第二章 较量才刚刚开始
第1节 大于、小于还是相等
1、关系运算符
== | 相等 |
---|---|
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
!= | 不等于 |
第2节 判断正数
1、算法
本质:
解决问题的方法和步骤。
2、条件语句(if语句)
问题:
如何判断一个数是否为正数,负数,0,满足条件分别输出"yes",“no”,“0”
if语句的三种表示方法:
//1
if (a>0) {printf("yes");}
//2
if (a>0) printf("yes");//当且仅当条件成立时只需执行一条语句才可省略{}
//3
if (a>0)
printf("yes");
3、完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a;//第一步,创建一个变量用来存储将要判断的整数
scanf("%d", &a);//第二步,输入一个整数
if(a > 0) printf("yes");//第三步,判断输入的整数是否为正数,若是,则输出yes
if(a < 0) printf("no");//第四步,判断输入的整数是否为负数,若是,则输出no
if(a == 0) printf("0");//第五步,判断输入的整数是否为0,若是,则输出0
return 0;
}
第3节 偶数判断
1、基础知识
1)问题
判断一个数是否是偶数
2)分析
偶数就是能够被2整除的数,如果一个数除以2的余数为0,那么这个数就是偶数。
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a;
scanf("%d", &a);
if(a % 2 == 0) printf("yes");
if(a % 2 != 0) printf("no");
return 0;
}
2、一起来找茬
1)问题
判断一个数是否为7的倍数
2)分析
7的倍数就是能够被7整除的数,如果一个数除以7的余数为0,那么这个数就是7的倍数
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a;
scanf("%d", &a);
if(a % 7 == 0) printf("yes");
if(a % 7 != 0) printf("no");
return 0;
}
3、更进一步,动手试一试
1)问题
如何判断一个数的末尾是不是0呢?如果是则输出yes(例如120),不是则输出no(例如1234)。
2)分析
如果一个数除以10的余数为0,则这个数的末尾是0。
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a;
scanf("%d", &a);
if(a % 10 == 0) printf("yes");
if(a % 10 != 0) printf("no");
return 0;
}
4)拓展
想知道一个数的个位数为多少,只需用这个数%10,余数为多少,这个数的个位数就为多少。(从后往前取)
例:
1234的个位数等于:
1234 % 10 == 4
第4节 神器else
1、基础知识
1)语法格式
if (条件)
{
语句 1;
语句 2;
语句 ……;
}
else
{
语句 1;
语句 2;
语句 ……;
}
当条件为真的时候执行if后面的语句;当条件为假的时候执行else后面的语句。
2、一起来找茬
1)问题
判断一个数的末尾是否为7
2)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a;
scanf("%d", &a);
if(a % 10 == 7) printf("yes");
else printf("no");
return 0;
}
3、更进一步,动手试一试
1)问题
从键盘键入一个正整数,让计算机判断这个数是否为一位数(1~9)。如果是则输出yes,否则输出no。
2)分析
如果一个数是一位数,则这个数除以10恒为0。否则,这个数不是一位数。
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a;
scanf("%d", &a);
if(a / 10 == 0) printf("yes");
else printf("no");
return 0;
}
第5节 请告诉我谁大
1、基础知识
1)问题
如何让计算机判断两个数中,谁更大?
2)分析
定义3个变量,a和b用来存放输入的两个数,c用来存放a和b中较大的那个。
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b, c;
scanf("%d%d", &a, &b);
if(a > b)
{
c = a;
}
else
{
c = b;
}
printf("%d", c);
return 0;
}
2、更进一步,动手试一试
1)问题
从键盘输入两个正整数,让计算机判断第2个数是不是第1个数的约数。如果是则输出yes,不是则输出no。
2)分析
约数,又称因数。整数a除以整数b(b≠0) 除得的商正好是整数而没有余数,我们就说a能被b整除,或b能整除a。a称为b的倍数,b称为a的约数。
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b;//定义两个变量
scanf("%d%d", &a, &b);//输入两个数
if(a % b == 0)//如果a能被b整除,则a是b的倍数,b是a的约数,输出yes
{
printf("yes");
}
else
{
printf("no");
}
return 0;
}
逻辑挑战2:3个数怎么办
1、基础知识
1)问题
比较三个数的大小,并输出最大的那个数
2)方法
//方法一:创建新变量存储较大的值
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b, c, d;//a,b,c用来存放输入的值,d用来存放较大的值
scanf("%d%d%d", &a, &b, &c);
if(a > b)
{
d = a;
}
else
{
d = b;
}
if(c > d)
{
d = c;
}
printf("%d", d);//输出d——最大的值
return 0;
}
//方法二:先分别比较a和b,以及a和c的关系,再b,再c……
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if(a >= b && a >= c) printf("%d", a);
if(b >= a && b >= c) printf("%d", b);
if(c > a && c > b) printf("%d", c);//若 if(c >= a && c >= b) printf("%d", c);则会输出两次值
return 0;
}
2、更进一步,动手试一试
1)问题
从键盘输入一个年份(整数),判断这个年份是否为闰年,是则输出yes,不是则输出no。
2)分析
闰年的判定
能被4整除,但不能被100整除。
能被4整除,也能被400整除。
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a;
scanf("%d", &a);
if((a % 4 == 0 && a % 100 != 0) || (a % 4 == 0 && a % 400 == 0))
{
printf("yes");
}
else
{
printf("no");
}
return 0;
}
逻辑挑战3:我要排序
1、基础知识
问题:
如何从键盘输入任意3个数,并将这3个数从大到小排序呢?
完整代码:
1)方法一:直接法
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b, c;
scanf("%d%d%d", a, b, c);
if(a >= b && a >= c) printf("%d %d %d", a, b, c);
if(a >= c && c > b) printf("%d %d %d", a, c, b);
if(b > a && a >= c) printf("%d %d %d", b, a, c);
if(b >= c && c > a) printf("%d %d %d", b, c, a);
if(c > a && a >= b) printf("%d %d %d", c, a, b);
if(c > b && b > a) printf("%d %d %d", c, b, a);
return 0;
}
2)方法二:换位法
分析:先将变量a与变量b和变量c以此比较,若b和c中的值大于a中的值,则与a进行交换,经过两次比较后,变量a中的值最大。然后将b和c进行比较,若b<c,则交换,确保b为次大。最终将最大的数放在小房子a中,次大的数放在小房子b中,最小的数放在小房子c中
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b, c, t;
scanf("%d%d%d", &a, &b, &c);
if(a < b)
{
t = a;
a = b;
b = t;
}
if(a < c)
{
t = a;
a = c;
c = t;
}
if(b < c)
{
t = b;
b = c;
c = t;
}
printf("%d %d %d", a, b, c);
return 0;
}
2、一起来找茬
奇数a的两种判断方法:
- a % 2 != 0
- a % 2 == 1
第6节 运算符总结
基础运算符
名称 | 作用 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
> | 大于 |
< | 小于 |
== | 等于 |
>= | 大于等于 |
<= | 小于等于 |
!= | 不等于 |
&& | 与 |
或 | |
! | 非 |
第7节 1 > 2 究竟对不对
if (1)
{
printf("yes");
}
else
{
printf("no");
}//输出yes
if (-5)
{
printf("yes");
}
else
{
printf("no");
}//输出yes
if (0)
{
printf("yes");
}
else
{
printf("no");
}//输出no
总结:
在C语言中,对于某一个数讨论真假时,只有0是假的,其余都被认为是真的。
第8节 讨厌的嵌套
问题:
如何从三个数中找出最大的一个数
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if(a >= b)
{
if(a >= c)
{
printf("%d", a);
}
else
{
printf("%d", c);
}
}
else//a < b
{
if(b >= c)
{
printf("%d", b);
}
else
{
printf("%d", c);
}
}
return 0;
}
简化版本:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if(a >= b)
if(a >= c)
printf("%d", a);
else
printf("%d", c);
else//a >= b 不成立的情况
if(b >= c)
printf("%d", b);
else
printf("%d", c);
return 0;
}
总结:
- else的匹配采用就近原则
- if-else“复合语句”在外层看来本质上就是一条if-else语句
第9节 if-else语法总结
总结:
1、当if()括号内的关系表达式成立的时候,就执行if()后面的{}中的内容,不成立的时候则执行else后面{}中的内容。
if (关系表达式)
{
语句;
语句;
……
}
else
{
语句;
语句;
……
}
2、当{}内的语句只有一条的时候,{}可以省略
if (关系表达式)
语句;
else
语句;
第4章 重量级选手登场
第1节 永不停止的哭声
1、基础知识
1)问题
如何让计算机做重复的事情。
2)while语句
#include<stdio.h>
#include<stdlib.h>
int main()
{
system("color 2");
while(1)
{
printf("wa");
}
return 0;
}
该程序会永无止境的输出“wa”。
3)语法
当while后面()中的关系表达式为真时,即关系表达式成立时才执行{}中的内容
如果{}中只有一条语句,那么{}可以省略
如果对某个数字判断真假,只要这个数不为0就是真的
第2节 我说几遍就几遍
1、基础知识
1)问题
如何让计算机重复指定的次数。
假设让计算机打印1~100,我们要让关系表达式在前100次是成立的,然后在第101次时就不成立了。
2)分析
创建一个新的“变量”来恒定现已循环次数。
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a = 1;
while(a <= 100)
{
printf("%d ", a);
a = a + 1;
}
return 0;
}
第3节 if对while说:我对你很重要
1、基础知识
1)问题
如何让计算机输出1~100中所有不能被3整除的数?
2)分析
如果想每次遇到3的倍数就不打印的话,只需在每次打印之前对变量a的值进行判断就好了。
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a = 1;
while(a <= 100)
{
if (a % 3 != 0)
printf("%d ", a);
a = a + 1;
}
return 0;
}
2、更进一步
1)问题
大家围成一圈,从1开始报数,但是每逢遇到7的倍数或者末尾含7的数,就要拍手并且不能报出,谁出错了,谁就要受到惩罚。
2)分析
- 两个if条件判断——7的倍数——末尾含7的数
- 末尾含7的数其实就是这个数的个位为7,也就是这个数除以10的余数为7
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a = 1;
while(a <= 100)
{
if (a % 7 == 0 || a % 10 == 7)
printf("%d ", a);
a = a + 1;
}
return 0;
}
第4节 求和!求和!!求和!!!
1、基础知识
1)问题
如何让计算机求1~100中所有数的和呢?
2)分析
创建新变量i——搬运苹果的工人——刚开始只拿1个苹果,之后拿2个苹果,再之后又拿3个苹果……
变量a——很大很大的水果篮子——第一次放1个苹果进去,第二次放2个,第三次放3个进去……
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a = 0;//初始值为0,刚开始水果篮子里什么都没有
int i = 1;
while(i <= 100)
{
a = a + i;//装苹果的a
i = i + 1; //搬运苹果的i
}
printf("%d", a);
return 0;
}
2、一起来找茬
1)问题
求1×2×3×4×5×6×7×8×9×10的值
2)分析
累乘。
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a = 1;//a的初始值要为1,不然0乘以任何数还是0
int i = 1;
while(i <= 10)
{
a = a * i;
i = i + 1;
}
printf("%d", a);
return 0;
}
3、更进一步,动手试一试
1)问题
输入一个整数n(1<=n<=9),求n的阶乘。
2)分析
正整数阶乘:从1乘以2乘以3乘以4一直乘到所要求的数。
3)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a = 1;
int i = 1;
int n;
scanf("%d", &n);
while(i <= n)
{
a = a * i;
i = i + 1;
}
printf("%d", a);
return 0;
}
注意:
scanf语句中不能输入提示性文字,例如 scanf(“请输入n的阶乘数:%d”, &n); 是错误的!
逻辑挑战4:60秒倒计时开始
1、基础知识
1)问题
如何设置一个60s的倒计时?
2)基础语法
Sleep():
前提:在代码开头加上#include<windows.h>
格式:Sleep——“等待”的意思;()——“等待”的时间,单位是毫秒。
system(“cls”):
作用:“清屏”语句,把现在屏幕上所有的内容清除干净。
3)完整代码
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
int main()
{
int a = 60;
system("color 0a");//设置成黑底绿字
while(a >= 1)
{
system("cls");//每次显示之前先清一次屏
printf("%d", a);//输出倒计时时间
Sleep(1000);//“等待”1s
a = a - 1;
}
return 0;
}
2、更进一步,动手试一试
1)问题
请尝试编写一个两分钟的倒计时。形如:2:00 1:59 …… 1:00 0:59 0:58 …… 0:02 0:01 0:00
2)分析
设计两个循环体,第一个循环1:时的倒计时,第二个循环0:时的倒计时。并且首先把2:00单独表现出来
3)完整代码
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
int main()
{
system("color f5");//白底紫字
int a = 59;
printf("2:00");
Sleep(1000);
while(a >= 0)//第一次1:59~1:00之间的循环
{
system("cls");
if(a < 10)
{
printf("1:0%d", a);
}
else
{
printf("1:%d", a);
}
Sleep(1000);
a = a - 1;
}
a = 59;//初始化a的值
while(a >= 0)//第二次0:59~0:00之间的循环
{
system("cls");
if(a < 10)
{
printf("0:0%d", a);
}
else
{
printf("0:%d", a);
}
Sleep(1000);
a = a - 1;
}
return 0;
}
第6节 这个有点晕——循环嵌套来了
1、问题1——打印3行5列星号
1)分析
一共要输出15个星号,每打印5个星号就需要换一行。
2)方法
方法一:通过if语句控制打印换行
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
int main()
{
int a = 1;
while(a <= 15)
{
printf("*");
if(a % 5 == 0)//如果变量a的值恰好是5的倍数,换行
printf("\n");
a = a + 1;
}
return 0;
}
方法二:循环嵌套
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a = 1;
while(a <= 3)
{
int b = 1;//每行开始都要初始化b的值
while(b <= 5)
{
printf("*");
b = b + 1;
}
printf("\n");//每一行输入完5个星号后,换行
a = a + 1;
}
return 0;
}
分析:
有两个while循环,一个是外循环,一个是内循环,内循环嵌套在外循环中
内循环是外循环的一部分,外循环每循环一次,内循环就会从头到尾循环一遍
控制外循环的循环次数的变量是a,称外循环为while a循环
控制内循环的循环次数的变量是b,称内循环为while b循环
2、问题2——打印阶梯状星号
1)分析
打印到第几行就打印几个星号,将内循环条件改为b <= a即可。
2)完整代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a = 1;
while(a <= 5)
{
int b = 1;//每行开始都要初始化b的值
while(b <= a)
{
printf("*");
b = b + 1;
}
printf("\n");//每一行输入完a个星号后,换行
a = a + 1;
}
return 0;
}
1)请尝试用while循环打印下面的图形
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n, a = 1;
scanf("%d", &n);
while(a <= n)
{
int b = 1;
while(b <= a)
{
printf("%d ", a);//每行输出的是当前行数
b = b + 1;
}
printf("\n");
a = a + 1;
}
return 0;
}
请尝试用while循环打印下面的图形
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n, a = 1, cnt = 1;//用来统计目前已输出的数字个数
scanf("%d", &n);
while(a <= n)
{
int b = 1;
while(b <= a)
{
printf("%d ", cnt);//输出目前是第几个数字
b = b + 1;
cnt = cnt + 1;
}
printf("\n");
a = a + 1;
}
return 0;
}
分析:
输出的是当前输出的数字的个数,所以可以新建一个统计次数的变量cnt。
像前面输出变量a一样,变量a代表的是行数,题目要求输出的列数和行数一致,故可以直接输出变量a。
亦像之前倒计时60s时的情况,循环次数正好与倒计时60s重合,所以可以通过输出循环次数来输出60s。(循环变量a的作用:①统计循环次数;②代表倒计时60s输出)
逻辑挑战5:奔跑的数字
1)问题
如果希望一个字母(假设这个字母是H)从屏幕的左边往右边跑,即第一秒时字母H在屏幕的第一行的最左边(也就是第一行第一列),第二秒时字母H在屏幕的第一行的第二列,第三秒时字母H在屏幕第一行的第三列,以此类推。
2)方法
方法一:初尝试
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
int main()
{
system("cls");
printf("H");
Sleep(1000);
system("cls");
printf(" H");
Sleep(1000);
system("cls");
printf(" H");
system("pause");
return 0;
}
分析:
要是50次的话,需要复制粘贴50次,太麻烦!
方法二:嵌套循环
分析:
每次循环空格的变化规律时0、1、2,这恰好和变量a的变化规律是一样的。第1次循环时变量a的值为0,第2次循环时变量a的值为1,第3次循环时变量a的值为2。也就是说每次循环时,在打印字母“H”前,打印a个空格就可以了。
完整代码
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
int main()
{
int a = 0;
while(a <= 2)
{
system("cls");
int b = 1;//若b = 0,则会导致第一个字母前会出现空格
while(b <= a)//循环开始前,打印相应循环次数个空格数
{
printf(" ");
b = b + 1;
}
printf("H");
Sleep(1000);
a = a + 1;
}
return 0;
}
利用while a循环来控制字母H一共需要走多少步,利用while b循环来控制字母H每走一步需要在字母H前面打印多少个空格
第7节 究竟循环了多少次
1、基础知识
1)代码
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
int main()
{
int a = 1;
while(a <= 2)
{
int b = 1;
while(b <= 3)
{
printf("OK ");
b = b + 1;
}
a = a + 1;
}
return 0;
}
分析:
两个while循环,即while a循环和while b循环,并且while b循环嵌套在while a循环里面。
这里while a循环每循环一次,while b循环就会被完整地从头到尾执行一遍(循环3次,打印3个“OK”)。这里的while a循环会循环2次,所以while b循环就会被完整地执行两边(每遍打印3个“OK”)。循环次数:2×3=6。
逻辑挑战6:奔跑的小人
1、基础知识
1)问题
让小人从左到右奔跑起来,并可以控制小人的速度
2)完整代码
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
int main()
{
int a = 0;//统计循环的次数,即奔跑的次数,也是打印空格的数量
int b;
while(a <= 2)
{
system("cls");//每次输出前先进行“清屏”
b = 1;
while(b <= a)//第一个小人的头打印0次空格,第二个小人的头打印1次空格,第三个小人的头打印2次空格
{
printf(" ");
b = b + 1;
}
printf(" O\n");
b = 1;
while(b <= a)//第一个小人的身体打印0次空格,第二个小人的身体打印1次空格,第三个小人的身体打印2次空格
{
printf(" ");
b = b + 1;
}
printf("<H>\n");
b = 1;
while(b <= a)//第一个小人的脚打印0次空格,第二个小人的脚打印1次空格,第三个小人的脚打印2次空格
{
printf(" ");
b = b + 1;
}
printf("I I\n");
Sleep(1000);//打印完一个小人整体后,“等待”1s——控制小人奔跑的速度
a = a + 1;
}
return 0;
}
分析:
让小人往右移动主要通过在小人的左边不停地打印空格来实现。所以第1行、第2行、第3行,即小人的头、小人的身、小人的腿,都要打印空格。因此小人的身体三部分之前都要加while循环打印空格。
拓展:
如果希望小人跑得更远,只需把while(a<=2)改为while(a<=80)。跑的更快只需改为Sleep(100)即可。
2、更进一步,动手试一试
1)问题
你可以设计一个“小人”并让它从右边向左边奔跑吗?
2)完整代码
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
int main()
{
int a = 20;//统计循环的次数,即奔跑的次数,也是打印空格的数量
int b;
while(a >= 0)
{
system("cls");//每次输出前先进行“清屏”
b = 1;
while(b <= a)//第一个小人的头打印20次空格,第二个小人的头打印19次空格,第三个小人的头打印18次空格
{
printf(" ");
b = b + 1;
}
printf(" O\n");
b = 1;
while(b <= a)//第一个小人的身体打印20次空格,第二个小人的身体打印19次空格,第三个小人的身体打印18次空格
{
printf(" ");
b = b + 1;
}
printf("<H>\n");
b = 1;
while(b <= a)//第一个小人的脚打印20次空格,第二个小人的脚打印19次空格,第三个小人的脚打印18次空格
{
printf(" ");
b = b + 1;//不断地减少打印的空格数量
}
printf("I I\n");
Sleep(100);//打印完一个小人整体后,“等待”1s——控制小人奔跑的速度
a = a - 1;
}
return 0;
}
3)分析
想要小人从右向左奔跑,一开始就要指定多个空格,然后后面的循环不断减少空格的数量,以达到从右向左的效果。
上面代码中,变量a控制小人一共走多少步,以及每次奔跑后剩余的空格数,变量b控制每次奔跑后小人左边应打印的空格数量。
第八节 for隆重登场
1、基础知识
1) 语法
//以打印数字1~10为例
for(int a = 1;i <= 10;a++)
{
printf("%d", a);
}
2)特点
- 已知循环次数用for
- 未知循环次数用while
2、更进一步,动手试一试
1)请尝试用for循环打印下面的图形
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
int main()
{
for(int i = 1;i <= 5;i++)//菱形的上半部分
{
for(int k = 4;k >= i;k--)//在打印星号之前打印的空格数(与行数的关系)
{
printf(" ");
}
for(int j = 1;j <= 2 * i - 1;j++)//行数与列数的关系:列数=2*行数-1
{
printf("*");
}
printf("\n");
}
int t = 7;//创建一个变量,用来控制菱形下部分的循环次数
for(int i = 1;i <= 4;i++)//菱形的下半部分
{
for(int j = 1;j <= i;j++)
{
printf(" ");
}
for(int j = 1;j <= t;j++)
{
printf("*");
}
t = t - 2;//打印完一行星号后,下一行打印星号数量减2
printf("\n");
}
return 0;
}
分析:
- 图形整体无法找出规律,可拆分成几部分
- 找出行与列的关系
- 可引入新变量来满足规律
2、请尝试用for循环来打印一个九九乘法表
#include<stdio.h>
#include<stdlib.h>
int main()
{
for(int i = 1;i <= 9;i++)
{
for(int j = 1;j <= i;j++)//列数与行数相等
{
printf("%d ×%d = %d\t", j, i, (i * j));
}
printf("\n");
}
return 0;
}
第5章 好戏在后面
第1节 程序的3种结构
3种结构 | 特点 |
---|---|
顺序执行 | 一行一行顺序地从上向下执行每条语句 |
选择执行 | 根据条件来选择需要执行的语句 |
循环执行 | 当条件满足时反复执行一段语句直到不满足条件时退出 |
第2节 啰嗦一下
第一:
a++ == a=a+1 —— 将变量a的值在原有的基础之上增加1
a-- == a=a-1 —— 将变量a的值在原有的基础之上减少1
第二:
a+=2 == a=a+2 —— 将变量a的值在原有的基础之上增加2
a-=2 == a=a–2 —— 将变量a的值在原有的基础之上减少2
a=2 == a=a2 —— 将变量a的值在原有的基础之上乘以2
a/=2 == a=a/2 —— 将变量a的值在原有的基础之上除以2
a%=2 == a=a%2 —— 将变量a的值在原有的基础之上取余2
逻辑挑战7:判断质数很简单
1)问题
判断质数
2)分析
质数(素数):
大于1的自然数
除了1和该整数自身外,无法被其他自然数整除(只有1和它本身两个约数的数)
3)思路
判断一个正整数a是否为质数,需要用a分别去除以2、3、4、5……a-2、a-1。如果从2到a-1中的所有整数都不能被a整除,即找不到除了1和a本身以外的任何约数,那么a就为质数,否则为合数。
4)完整代码
//#define _CRT_SECURE_NO_WARNINGS//在VS下需加入
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, count;
scanf("%d", &a);
count = 0;//用来统计有几个约数
for(int i = 2;i <= (a-1);i++)//从2~a-1寻找a的约数
{
if(a % i == 0)//如果a被i整除
{
count++;
printf("%d ", i);//打印出约数
}
}
printf("\n");
printf("a有%d个约数\n", count);
if(count == 0)//从2~a-1均没有a的约数
{
printf("a为质数\n");
}
else//2~a-1之间有a的约数
{
printf("a为合数\n");
}
return 0;
}
第3节 更快一点:break
作用:
- 提前结束当前循环
- break是用来提前终止for、while或者do-while循环的
代码:优化判断质数
#define _CRT_SECURE_NO_WARNINGS//在VS下需加入
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, count;
scanf("%d", &a);
count = 0;//用来统计有几个约数
for (int i = 2; i <= (a - 1); i++)//从2~a-1寻找a的约数
{
if (a % i == 0)//如果i被a整除
{
count++;
break;
}
}
if (count == 0)//从2~a-1均没有a的约数
{
printf("%d为质数\n", a);
}
else//2~a-1之间有a的约数
{
printf("%d为合数\n", a);
}
return 0;
}
第4节 continue
问题:
打印偶数。
代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
for (int i = 1; i <= 100; i++)
{
if (i % 2 == 1)//i为奇数
{
continue;//为奇数则跳过之后的语句,提前进入下一次循环
}
printf("%d ", i);
}
return 0;
}
分析:
- i%2 == 1,表示i为奇数
- 当i为奇数时,跳过之后的打印语句,提前进入下一次循环
总结:
- break使循环提前跳出
- continue强迫程序提前进入下一轮循环
逻辑挑战8:验证哥德巴赫猜想
哥德巴赫猜想:
“任一大于2的偶数都可写成两个质数之和”。
问题:
验证4~100内所有偶数都可写成两个质数之和。
分析:
- 将每一个数k拆分为a+b的形式,且a的范围是2~k/2
- 判断a和b是否为质数
代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
for (int k = 4; k <= 100; k = k + 2)//4~100之间的偶数
{
for (int a = 2; a <= k / 2; a++)//找出其中一个质数
{
//判断a是否为质数
int count1 = 0;
for (int i = 2; i <= a - 1; i++)
{
if (a % i == 0)//i能被a整除,则a不是质数
{
count1++;
break;//a在2~a-1之间有约数,a不是质数,提前结束当前循环,继续寻找下一个a
}
}
if (count1 == 0)//如果a是质数
{
int b = k - a;//寻找另一个质数b
//判断b是否为质数
int count2 = 0;
for (int i = 2; i <= b - 1; i++)
{
if (b % i == 0)//i能被b整除,则b不是质数
{
count2++;
break;//b在2~b-1之间有约数,b不是质数,提前结束当前循环,继续寻找下一个a
}
}
if (count2 == 0)//如果b也是质数
{
printf("%d = %d + %d\n", k, a, b);//a和b均为质数,打印出这个解
break;//打印这个解并跳出循环
//若想输出每一个偶数的所有可能的拆分方法,则注释掉break
}
}
}
}
return 0;
}
逻辑挑战9:水仙花数
水仙花数:
"个位数的立方 + 十位数的立方 + 百位数的立方"恰好等于这个数。例如:153=1×1×1 + 5×5×5 + 3×3×3。
方法一:拼接法
分析:
三位数,则必然是100~999中的数
百位上是1-9,十位上是0-9,个位上是0-9
代码
//#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
for (int i = 1; i <= 9; i++)//百位1~9
{
for (int j = 0; j <= 9; j++)//十位0~9
{
for (int k = 0; k <= 9; k++)//个位0~9
{
if (i * 100 + j * 10 + k * 1 == i * i * i + j * j * j + k * k * k)//如果"个位数的立方 + 十位数的立方 + 百位数的立方"恰好等于这个数
{
printf("%d\n", i * 100 + j * 10 + k);
}
}
}
}
return 0;
}
拼接法”,即分别枚举百位、十位、个位上的数的所有可能,然后再拼接成一个3位数(百位×100+十位×10+个位)
方法二:分割法
分析:
- 如何将一个数拆分成三部分
- 获取一个数个位、百位、十位上的数
重点:
- 三位数获取个位上的数、十位上的数、百位上的数
//a,b,c分别为x百位、十位、个位上的数
a = x / 100 % 10;//让原来的百位变成个位再取个位
b = x / 10 % 10;//让原来的十位变成个位再取个位
c = x / 1 % 10;//取个位
代码:
//#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
int x, a, b, c;
for (x = 100; x <= 999; x++)
{
a = x / 100 % 10;//百位数
b = x / 10 % 10;//十位数
c = x / 1 % 10;//个位数
if (x == a * a * a + b * b * b + c * c * c)//如果"个位数的立方 + 十位数的立方 + 百位数的立方"恰好等于这个数
{
printf("%d ", x);
}
}
return 0;
}
“分割法”,将一个三位数x拆分成3部分,即a、b、c,分别用来存放百位、十位、个位上的数。
逻辑挑战10:解决奥数难题
问题一:请在两个()内填入相同的数字使得等式成立:
()3×6528 = 3()×8256
分析:
- 让变量i从1到9循环
- 每次循环只需判断一下当前的i是否符合这个等式的条件
- 如果符合就输出其值
代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
for (int i = 1; i <= 9; i++)//让变量i从1到9循环
{
if ((i * 10 + 3) * 6528 == (3 * 10 + i) * 8256)//如果符合等式
{
printf("%d\n", i);
}
}
return 0;
}
问题二:在上面的算式中,A、B、C、D、E分别代表5个互不相同的整数,请问A、B、C、D、E分别为多少时算是才会成立?请输出这个算式。
分析:
- ABCD×E = DCBA成立则输出
- ABCDE取值范围只可能是0~9
- 五个嵌套循环可以解决
代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
//遍历ABCDE五个数的所有组合
for (int a = 0; a <= 9; a++)
{
for (int b = 0; b <= 9; b++)
{
for (int c = 0; c <= 9; c++)
{
for (int d = 0; d <= 9; d++)
{
for (int e = 0; e <= 9; e++)
{
if(a != b && a != c && a != d && a != e
&& b != c && b != d && b != e
&& c != d && c != e
&& d != e)//如果ABCDE互不相等
if ((a * 1000 + b * 100 + c * 10 + d) * e == (d * 1000 + c * 100 + b * 10 + a))//如果符合等式
{
//满足两个条件则按格式输出
printf("%d%d%d%d\n", a, b, c, d);
printf("× %d\n", e);
printf("——\n");
printf("%d%d%d%d\n", d, c, b, a);
}
}
}
}
}
}
return 0;
}
逻辑挑战11:猜数游戏
问题:
计算机会随机地给出0~99之间的一个整数,每猜一次,计算机都会告诉你猜大了还是小了,要求在限定的次数内猜出来。
获取随机数
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
srand((unsigned)time(NULL));//初始化随机数种子,通过当前时间获得这个随机种子
int a = rand();//根据srand()提供的种子值,返回一个随机数
printf("%d", a);
return 0;
}
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int a, b, sum;
sum = 6;//表示有6次猜的机会
srand((unsigned)time(NULL));
a = rand() % 100;//随机生成一个0~99之间的数
while (1)
{
sum--;//开始猜数时,首先要消耗一次机会
scanf("%d", &b);
if (b > a)
printf("大了,还剩下%d次机会,请继续\n", sum);
else if (b < a)
printf("小了,还剩下%d次机会,请继续\n", sum);
else//b == a
{
printf("恭喜你,答对了!\n");
break;
}
if (sum == 0)//猜数机会用完
{
printf("已经没有机会了,请重新开始吧!\n");
break;
}
}
return 0;
}
逻辑挑战12:你好坏,关机啦
语法:
system("shutdown -s -t 50");
“shutdown"表示令计算机关机或者重新启动的命令,”-s"表示关机,"-r"表示重启,"-t 50"表示的是在50秒后关机。
注意——本节介绍的关机程序只能在Windows操作系统上实现关机
system("shutdown -a");
取消关机的命令。
第6章 天啊!一大串数正在接近
第1节 借用数组逆序输出
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a[5];//声明一个元素个数为5的数组
//输入0~4号元素到数组a中
for (int i = 0; i <= 4; i++)
{
scanf("%d", &a[i]);
}
//逆序输出
for (int i = 4; i >= 0; i--)
{
printf("%d ", a[i]);
}
return 0;
}
逻辑挑战13:淘淘摘苹果
问题:
陶陶家的院子里有一棵苹果树,每到秋天书上就会结出10个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个30cm的板凳,当她不能直接用手摘到苹果时,就会踩到板凳上再试试。
现已知10个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目。假设她碰到苹果,苹果就会掉下来。
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
//输入10个苹果到地面的高度(100~200)
int appleHigh[10];//声明一个长度为10的数组
printf("请分别输入10个苹果距离地面的高度:\n");
for (int i = 0; i < 10; i++)
{
scanf("%d", &appleHigh[i]);//分别输入10个苹果距离地面的高度
}
//输入陶陶把手伸直时能够达到的最大高度(100~120)
int handHigh, bench = 30;//30cm高的板凳
printf("请输入陶陶把手伸直时能够达到的最大高度:\n");
scanf("%d", &handHigh);
int cnt = 0;//用来记录陶陶所摘的苹果数量
for (int i = 0; i < 10; i++)
{
if (appleHigh[i] <= (handHigh + bench))
cnt++;
}
printf("陶陶能够摘到的苹果的数目是:%d\n", cnt);
return 0;
}
逻辑挑战14:一个萝卜一个坑
问题一:
从键盘输入5个0-9的数,然后输出0-9中那些没有出现过的数。
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a[10], t;//先创建10个“小房间”
//1、将10个小房间中的值初始化为0
for (int i = 0; i <= 9; i++)
a[i] = 0;
//2、将输入的数字对应小房间里的值改为1
for (int i = 1; i <= 5; i++)
{
scanf("%d,", &t);//以此读入5个数
a[t] = 1;//把对应的小房间改为1
}
//3、输出没有出现过的数
for (int i = 0; i <= 9; i++)
{
if (a[i] == 0)
printf("%d ", i);
}
return 0;
}
核心:
- 出现过的数,它们所对应的小房间中的值都为1
- 没有出现过的数,所对应的小房间中的值都为0
问题二:
如果现在需要将输入的5个数(范围时0~9)从小到大排序,该怎么办?例如,输入2 5 2 1 8,则输出1 2 2 5 8。
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a[10], t;//先创建10个“小房间”
//1、将10个小房间中的值初始化为0
for (int i = 0; i <= 9; i++)
a[i] = 0;
//2、将输入的数字对应小房间里的值增加1,用来统计该数出现的次数
for (int i = 1; i <= 5; i++)//循环读入5个数
{
scanf("%d,", &t);//把每一个数读到变量t中
a[t]++;//t所对应的小房间中的值增加1,以此作为出现次数
}
//3、从小到大依照出现的次数输出对应的序号,从而实现将输入的数从小到大排序
for (int i = 0; i <= 9; i++)//依次判断0~9这10个小房子
{
for (int j = 1; j <= a[i]; j++)//出现了几次就打印几次
printf("%d ", i);
}
return 0;
}
- 用a[i]来记录数字出现的次数
- 从小到大输出输入的数字,从而实现从小到大排序
逻辑挑战15:选择排序
问题:
将77、45、26、86、9这5个数从小到大排序。
完整排序过程:
初始数据 | [77 45 26 86 9] |
---|---|
第1轮排序后 | 9 [77 45 86 26] |
第2轮排序后 | 9 26 [77 86 45] |
第3轮排序后 | 9 26 45 [86 77] |
第4轮排序后 | 9 26 45 77 [86] |
第5轮排序后 | 9 26 45 77 86 |
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a[1000];//创建一个长度为1000的数组
//1、输入要排序的数
int n;
scanf("%d", &n);//输入n个数
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
//2、将5个数进行选择比较
for (int i = 0; i < (n-1); i++)//5个数只需比较4次
{
for (int j = i + 1; j <= (n-1); j++)//a[i]分别与a[i+1]、a[i+2]……a[5]比较
{
if (a[i] > a[j])//若前面的数比后面的数大,则交换两数位置
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
//3、输出排好序的数
for (int i = 0; i < n; i++)
printf("%d ", a[i]);
return 0;
}
- a[i]依次与a[i+1]、a[i+2]……a[5]比较
第2节 二维数组
1、创建及打印二维数组
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a[3][4];
int x = 0;
for (int i = 0; i <= 2; i++)
{
for (int j = 0; j <= 3; j++)
{
a[i][j] = x;
x++;
}
}
for (int i = 0; i <= 2; i++)
{
for (int j = 0; j <= 3; j++)
{
printf("%d\t", a[i][j]);
}
printf("\n");//一行打印完毕需要换行
}
return 0;
}
2、数组的初始化
将数组中所有元素初始化为0:
int a[10] = {0};
要点:
- 编译器会从a[0]开始按顺序赋值,后面没有具体值得将默认为0
- 只定义一个数组而不进行任何初始化,则每一个数组元素的默认值都将是随机值
二维数组的初始化:
int a[3][5] = {{1,2,3}, {4,5}};
每一个括号代表一行。
第7章 有了它你能做更多的事
第1节 字符的妙用
简易计算器:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b;
char c;
scanf("%d%c%d", &a, &c, &b);
if (c == '+')
printf("%d", a + b);
if (c == '-')
printf("%d", a - b);
if (c == '*')
printf("%d", a * b);
if (c == '/')
printf("%d", a / b);
return 0;
}
第2节 多余的回车键
getchar():
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
char a;
a = getchar();
printf("你刚才输入的字符是:%c\n", a);
return 0;
}
getchar();与scanf("%c", &a);的作用是完全一样的。
用scanf()和getchar()来读取一个字符时,首先是将输入的字符接收到缓冲区,缓冲区是一块为用户的输入预留的内存区域。缓冲区不会自动释放,直到用户按下"Enter"键,缓冲区内的字符才会被释放,让我们的程序接收到。
也就是:
第一,只要用户还没有按下“Enter”键,用户就可以用“Backspace”键(退格键)或者“Delete”键(删除键)来纠正错误的字符输入
第二,如果用户没有按下“Enter”键,输入的字符就会一直逗留在缓冲区中,不会被我们所写的程序接收到,直到用户按下“Enter”键
getche():
作用:
按下一个键后,计算机能立马反应,而无需按下多余的“Enter”键。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include <conio.h>
int main()
{
char a;
a = _getche();
printf("你刚才输入的字符是:%c\n", a);
return 0;
}
总结:
getchar()读取一个字符,输入后等待用户按“Enter”键结束(带回显)
getche()读取一个字符,输入后立即获取字符,不用按“Enter”键结束(带回显)
getch()读取一个字符,输入后立即获取字符,不用按“Enter”键来结束(不带回显)
注意:在VS2019中需要加头文件#include <conio.h>,且将getche()改为_getche()才能达到同样的效果。
第3节 字符的本质
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
int i;
for (int i = 0; i <= 127; i++)
{
printf("%d %c\n", i, i);
}
return 0;
}
计算机本质上只能存储0和1,任意整数都可以通过进制转换的方式变化成0和1的序列。所以表示字符最简单的方法就是把字符用整数来代替。字符所对应的整数就是该字符的ASCII码。
第4节 人名怎么存储呢
如何读取一行字符串:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
char a[10];
scanf("%s", a);
printf("%s", a);
return 0;
}
此处的字符数组a(或者称作字符串a)只申请了10个空间,但只能存9个有效字符,因为最后一个需要用来存储字符串的结束标记‘\0’。
注意,a前面没有取址符“&”。(只有与“%s”配合使用来读取一行字符串时,才不需要在变量前加取址符“&”。)
问题:
第1行先输入1个人的名字,空1格后输入这个人的分数,第2行还是先输入1个人的名字,空1格后输入这个人的分数。
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
char a[101], b[101];
int x, y;
scanf("%s", a);
scanf("%d", &x);
scanf("%s", b);
scanf("%d", &y);
if (x > y)
printf("%s", a);
else
{
if (x < y)
printf("%s", b);
else
printf("%s和%s的分数相同", a, b);
}
return 0;
}
gets:
代码1:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
char a[10];
scanf("%s", a);
printf("%s", a);
return 0;
}
代码2:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
char a[10];
gets_s(a);
printf("%s", a);
return 0;
}
由此可见,用scanf进行字符串读入时,遇到空格就提前终止了,但是用gets进行读入时却可以读入一整行。
注意: VS2019使用的是新C标准,也就是C11,而VC6.0用的是老标准。 在新标准中,应该是用gets_s代替gets。
输出字符puts:
puts(a);
使用puts(a)输出时,会在末尾自动换到下一行,相当于printf("%s\n", a)。
字符数组赋初始值:
char a[10] = {"hello"};
在字符串的两边加上双引号和花括号就可以了。
逻辑挑战16:字母的排序
问题:
读入1行小写字母,然后将这行字母从a到z进行排序。
分析:
字符的本质是整数。所以字符的排序和整数的排序是完全一样的。
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>//用strlen()函数的头文件
int main()
{
char a[101];//假设读入的字符不超过100个
int len;//存储字符串长度的整型变量
gets_s(a);//输入字符串
len = strlen(a);//通过strlen()函数获取字符串a的长度
for (int i = 0; i < len - 1; i++)
{
for (int j = i + 1; j <= len - 1; j++)
{
if (a[i] > a[j])
{
char t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
puts(a);//输出排完序的字符串
return 0;
}
逻辑挑战17:字典序
问题:
如何对字符串排序呢,例如apple和pear的排序。翻字典时,apple排在pear的前面,这个就是字典序。
输入两个单词,然后按照字典序输出这两个单词。
分析:
字符的比较可以用“>、<、<=、>=、==”,但是字符串不可以。
两个字符串比较可以用函数strcmp()。strcmp(a,b)就是比较字符串a和字符串b在字典中的顺序。
如果字符串a和字符串b完全相同,返回值为0
如果字符串a在字典中比字符串b先出现,返回值小于0
如果字符串a在字典中比字符串b后出现,返回值大于0
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>//用strcmp函数需此头文件
int main()
{
char a[101], b[101];
gets_s(a);
gets_s(b);
if (strcmp(a, b) <= 0)//a在b前面或a和b是同一个字符串
{
puts(a);
puts(b);
}
else//a在b后面
{
puts(b);
puts(a);
}
return 0;
}
第7节 多行字符
问题一:
读入5行字符串,然后将这5行字符串原封不动的输出。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>//用strcpy()、strcmp()函数必须包含
int main()
{
char a[5][11];
//输入5行字符串
for (int i = 0; i <= 4; i++)
{
gets_s(a[i]);
}
//输出5行字符串
for (int i = 0; i <= 4; i++)
{
puts(a[i]);
}
return 0;
}
问题二:
输入5个单词,然后把这些单词按照字典序输出。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>//用strcpy()、strcmp()函数必须包含
int main()
{
char a[5][11], t[11];
//输入字符串(0~4行)
for (int i = 0; i <= 4; i++)
{
gets_s(a[i]);
}
//选择排序
for (int i = 0; i <= 3; i++)
{
for (int j = i + 1; j <= 4; j++)
{
if (strcmp(a[i], a[j]) > 0)//如果按字典顺序字符串a[i]在a[j]的后面
{
//互换顺序
strcpy(t, a[i]);
strcpy(a[i], a[j]);
strcpy(a[j], t);
}
}
}
//输出排序后的字符串(0~4行)
for (int i = 0; i <= 4; i++)
{
puts(a[i]);
}
return 0;
}
- 字符串比较函数strcmp()
- 字符串复制函数strcpy()
- 头文件#include<string.h>
第8节 存储一个迷宫
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>//用strcpy()、strcmp()函数必须包含
int main()
{
char maze[7][12] = {"###########",
"#O # ###",
"# ## ## #",
"# # # #",
"# #### ## #",
"# # ",
"###########" };
//循环输出第0行到第6行
for (int i = 0; i <= 6; i++)
puts(maze[i]);
return 0;
}
第8章 游戏时间到了
第1节 走迷宫
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include <conio.h>//用_getche()函数需包含
int main()
{
system("color f5");//变色
//定义迷宫
char a[50][50] = {"##############################",
"#O # ## # ### ####",
"# ###### # # # # # ### ####",
"# # ## # # #### # ### ##",
"# # ## ### # # ## ####",
"##### # # ##### ## ####",
"# # ##### # # # # # #",
"# # # ## # #### ## # # ####",
"# # # ## ## # # ####",
"# # # ####### ## ###### # ##",
"# # ## # ## ###### ### #",
"# ###### # ##### # # #",
"# # # ##### ### # ",
"# ######## ##### # ### ### # #",
"# # ## ##### ### ###",
"##### # ## # ######## # #",
"# # ## ## ### # #",
"# # ### ###### ####### #",
"# # ### ## # #",
"##############################"
};
//定义小球初始位置和迷宫的出口
int x, y, p, q;
x = 1; y = 1; p = 12; q = 29;//x和y来存储小球的初始位置,p和q来存储迷宫的出口
//输出迷宫
for (int i = 0; i <= 19; i++)
puts(a[i]);
//定义上下左右按键
while (x != p || y != q)
{
//S:向下移动
char ch = _getche();
if (ch == 's')
{
if (a[x + 1][y] != '#')//只有下一步不是栅栏“#”时小球才能移动
{
a[x][y] = ' ';//让小球当前位置变为空格
x++;//更改小球的位置
a[x][y] = 'O';//将小球新位置上的内容替换为小球“O”
}
}
//W:向上移动
if (ch == 'w')
{
if (a[x - 1][y] != '#')
{
a[x][y] = ' ';
x--;
a[x][y] = 'O';
}
}
//A:向左移动
if (ch == 'a')
{
if (a[x][y - 1] != '#')
{
a[x][y] = ' ';
y--;
a[x][y] = 'O';
}
}
//D:向右移动
if (ch == 'd')
{
if (a[x][y + 1] != '#')
{
a[x][y] = ' ';
y++;
a[x][y] = '0';
}
}
//清屏并输出新迷宫的状态
system("cls");
for (int i = 0; i <= 19; i++)
puts(a[i]);
}
system("cls");
printf("恭喜你成功走出迷宫了!\n");
Sleep(5000);
return 0;
}
第2节 推箱子
问题:
在一个狭小的仓库中,要求把木箱从开始位置推到指定位置。仓库中有障碍物,稍不小心就会出现箱子无法移动或者通道被堵住的情况,而且箱子只能推、不能拉,需要巧妙地利用有限地空间和通道,合理安排移动地次序和位置,才能顺利完成任务。
分析:
四个终点被箱子填满后,退出循环
根据具体地图情况修改完善代码
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include <conio.h>//用_getche()函数需包含
int main()
{
//提示文字
system("color f5");//变色
printf("请通过WSAD(小写模式)键控制小人‘S’移动\n");
//按任意键清屏
system("pause");
system("cls");
//定义推箱子地图
char sokoban[50][50] = {"##########",
"## ###",
"##O### #",
"# S O O #",
"# **# O ##",
"##**# ##",
"##########"
};
//定义推箱人初始位置和箱子的位置
int x = 3, y = 2, p1 = 4, q1 = 2, p2 = 4, q2 = 3, p3 = 5, q3 = 2, p4 = 5, q4 = 3;
//输出推箱子地图
for (int i = 0; i <= 8; i++)
puts(sokoban[i]);
while (sokoban[p1][q1] != '@' || sokoban[p2][q2] != '@' || sokoban[p3][q3] != '@' || sokoban[p4][q4] != '@')
{
if (sokoban[p1][q1] == 'O')
sokoban[p1][q1] = '@';
if (sokoban[p2][q2] == 'O')
sokoban[p2][q2] = '@';
if (sokoban[p3][q3] == 'O')
sokoban[p3][q3] = '@';
if (sokoban[p4][q4] == 'O')
sokoban[p4][q4] = '@';
//定义上下左右按键
char ch = _getche();
//W
if (ch == 'w')
{
if (sokoban[x + 1][y] == '@' && sokoban[x+2][y] == '#' || sokoban[x][y + 1] == '@' && sokoban[x][y + 2] == '#' || sokoban[x + 1][y + 1] == '@' && sokoban[x + 1][y + 2] == '#' && sokoban[x][y + 2] == '#')
{
sokoban[x][y] = '*';
x--;
sokoban[x][y] = 'S';
}
else if (sokoban[x - 1][y] != 'O' && sokoban[x - 1][y] != '@')
{
if (sokoban[x - 1][y] != '#')
{
sokoban[x][y] = ' ';
x--;
sokoban[x][y] = 'S';
}
}
else
{
if (sokoban[x - 2][y] != '#' && sokoban[x - 2][y] != '@')//箱子的左边
{
sokoban[x][y] = ' ';//原来位置是空格
x--;
sokoban[x][y] = 'S';//新位置是S
sokoban[x - 1][y] = 'O';//新箱子位置
}
}
}
//S
if (ch == 's')
{
if (sokoban[x + 1][y] != 'O' && sokoban[x + 1][y] != '@')
{
if (sokoban[x + 1][y] != '#')
{
sokoban[x][y] = ' ';
x++;
sokoban[x][y] = 'S';
}
}
else
{
if (sokoban[x + 2][y] != '#' && sokoban[x + 2][y] != '@')//箱子的左边
{
sokoban[x][y] = ' ';//原来位置是空格
x++;
sokoban[x][y] = 'S';//新位置是S
sokoban[x + 1][y] = 'O';//新箱子位置
}
}
}
//A
if (ch == 'a')
{
if (sokoban[x][y + 1] == '@' && sokoban[x][y + 2] == '#' || sokoban[x + 1][y] == '@' && sokoban[x + 2][y] == '#')
{
sokoban[x][y] = '*';
y--;
sokoban[x][y] = 'S';
}
else if (sokoban[x][y - 1] != 'O' && sokoban[x][y - 1] != '@')
{
if (sokoban[x][y - 1] != '#')
{
sokoban[x][y] = ' ';
y--;
sokoban[x][y] = 'S';
}
}
else
{
if (sokoban[x][y - 2] != '#' && sokoban[x][y - 1] != '@')//箱子的左边
{
sokoban[x][y] = ' ';//原来位置是空格
y--;
sokoban[x][y] = 'S';//新位置是S
sokoban[x][y - 1] = 'O';//新箱子位置
}
}
}
//D
if (ch == 'd')
{
if (sokoban[x][y + 1] != 'O' && sokoban[x][y + 1] != '@')
{
if (sokoban[x][y + 1] != '#')
{
sokoban[x][y] = ' ';
y++;
sokoban[x][y] = 'S';
}
}
else
{
if (sokoban[x][y + 2] != '#' && sokoban[x][y + 2] != '@')//箱子的左边
{
sokoban[x][y] = ' ';//原来位置是空格
y++;
sokoban[x][y] = 'S';//新位置是S
sokoban[x][y + 1] = 'O';//新箱子位置
}
}
}
//清屏并输出
system("cls");
for (int i = 0; i <= 8; i++)
puts(sokoban[i]);
}
Sleep(1000);//等待1s
//提示成功
system("cls");
printf("恭喜你成功通关!\n");
return 0;
}
《啊哈C语言——逻辑的挑战》学习笔记的更多相关文章
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
- ucos实时操作系统学习笔记——任务间通信(消息)
ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox.为什么有了qu ...
随机推荐
- 文件上传 upload-labs Pass-18 条件竞争
Pass-18 条件竞争 审计源码 $is_upload = false; $msg = null; if(isset($_POST['submit'])){ $ext_arr = array('jp ...
- 脏牛-Linux内核提权
漏洞范围 下载地址:https://github.com/FireFart/dirtycow 有一点可以在意,dirty.c内置在了kali中,使用命令searchsploit dirty可以搜索 也 ...
- Github账户的注册
注册步骤 首先进入github官网界面(注意,只能用Chrome或者Firefox浏览器.这样保险性更强一些) 官网地址:https://github.com/ 映入眼帘的界面是这样的: 点击右上角的 ...
- operator简介
原理 operator 是一种 kubernetes 的扩展形式,利用自定义资源对象(Custom Resource)来管理应用和组件,允许用户以 Kubernetes 的声明式 API 风格来管理应 ...
- Linux设备驱动那些事
目的 初步了解 linux 设备驱动框架模型 初步了解设备驱动模型有哪些元素 设备驱动模型元素的说明及解释 设备驱动模型元素的工作原理 设备驱动模型的小例子 对整体有个粗略的了解,设备驱动类型种类太多 ...
- 主板芯片组驱动和Win系统版本互相关联
主板芯片组驱动和Win系统版本互相关联,过早的系统安装较新版的芯片组驱动,或者较新版本的操作系统安装旧版的芯片组驱动,都可能导致系统不稳定蓝屏.解决方案就是安装最新的芯片组驱动和最新版的操作系统.
- java 实现文件夹上传(springBoot 框架)
有时我们后台管理等服务可能会有这样一个简单需求,就是根据文件夹将整个文件夹下的所有资源都上传到我们的服务器上,本人也是搜索了大量资料,最终以最简单便捷的方式实现该功能,具体操作步骤如下 一.前端如何设 ...
- vue中新的状态管理器-pinia
背景 对于pinia的使用,可参考官方文档在这不做过多赘述.这边主要来讲讲pinia中 少用且好用的方法,为什么我们选择pinia而不用vuex ps: 以下写法全部基于组合式API 使用方式: 先下 ...
- CPU内部的奥秘:代码是如何被执行的?
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:景明 我们以一段 C 代码为例,来看一下代码被编译成二进制 ...
- [Python]PyCharm中出现unresolved reference的解决方法
1 问题描述 2 解决方法 将你的目录添加sources root,即可解决此问题 (工程目录)>右键>Mark Directory As > Sources Root X 参考文献 ...