文章目录
循环
经过初识C语言(二)我们已经知道循环语句包含了
while
do…while
for
仔细想一想,在现实生活当中,我们每个人总要在同一件事情上反复完成很多次,比如睡觉前闭眼,早上醒来后第一件事情睁眼。
while
//while语法结构
while(表达式)
{
语句; //循环体
}
while流程图:
执行while语句时,首先计算控制表达式的值,如果值为真,则执行语句(循环体),然后判定是否满足表达式。重复执行,直至控制表达式为零则停止循环。
在大学,每次到达指定教室后,在正式上课前,老师都会发起一个签到,来监督学生是否到达教室进行听课,以此记录学生的出勤率并将其纳入平时成绩。
假设该班共有十名同学,老师发起签到后,每个同学都到达课堂并签到。
#include <stdio.h>
int main()
{
int stu = 1;
while (10 >= stu)
{
printf("学生%d,签到成功!\n", stu);
stu++;
}
return 0;
}
运行结果:
若控制表达式的值始终为真,则while语句将无限循环
突然老师有一天不下心将签到发到了她所任教的全部班课中,于是会出现这种情况。
#include <stdio.h>
int main()
{
int stu = 1;
while (1)
{
printf("学生%d,签到成功!\n", stu);
stu++;
}
运行结果:
while语句中的break和continue
通过上面的代码,已经了解了while语句的基本语法和使用
在分支语句中,已经浅浅的介绍过break语句在switch语句中的使用方法
在这里再介绍一下循环语句中break和continue在while中的使用方法
在课堂上,老师通常会选择一种抢答的方式来让学生主动回答问题。
break
那我们只选择前三名抢到的同学来回答问题,可以用如下代码:
#include <stdio.h>
int main()
{
int i = 0;
while (10 >= i)
{
i++;
if (4 == i)
{
break;
}
printf("第 %d 个同学已抢答! \n", i);
}
return 0;
}
运行结果:
其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。所以:while中的break是用于永久终止循环的
continue
其他同学因为上课抢不到前三很沮丧,老师为了能让他们也有参与感,于是就规定了抢到偶数前三名同学才可以回答问题
#include <stdio.h>
int main()
{
int i = 0;
int t = 0;
while (10 >= i)
{
i++;
if (i%2!=0)
{
t++;
continue;
}
printf("第 %d 个同学已抢答! \n", i);
if (t == 3)
{
break;
}
}
return 0;
}
运行结果:
continue是用于终止本次循环的
也就是本次循环中,continue后边的代码不会再执行,而是直接跳转到while语句的判断部分。进行下一次循环的入口判断
输入一堆字符,只打印数字字符,跳过其他字符
#include <stdio.h>
int main()
{
char ch = '\0';
while ((ch = getchar()) != EOF)
{
if (ch < '0' || ch > '9')
continue;
putchar(ch);
}
return 0;
}
运行结果:
do…while
do语句的本质就是while语句,其控制表达式是在每次执行完循环体之后进行判定。
while语句中的循环体可一次不执行,而do…while语句中的循环体最少执行一次
//do...while语法结构
do
{
语句; //循环体 可为一条语句或复合语句
}while(表达式);
do…while语句流程图:
执行do…while语句时,先执行语句(循环体),再计算控制表达式的值。若表达式值非零,则再次执行语句(循环体),当表达式的值为零时,则终止do…while语句的循环。
do…while语句中的break和continue
do…while循环中也可以出现break和continue,他们的意义和在while循环中是一样的。沿用while循环中的例子,我们可以使用do…while循环这么写。
break
#include <stdio.h>
int main()
{
int i = 0;
do
{
i++;
if (4 == i)
{
break;
}
printf("第 %d 个同学已抢答! \n", i);
}while (10 >= i);
return 0;
运行结果:
continue
#include <stdio.h>
int main()
{
int i = 0;
int t = 0;
do
{
i++;
if (i % 2 != 0)
{
t++;
continue;
}
printf("第 %d 个同学已抢答! \n", i);
if (t == 3)
{
break;
}
} while (10 >= i);
return 0;
}
运行结果:
for
for循环与while相比更优渥
//for语句语法结构
for(表达式1; 表达式2; 表达式3)
{
循环语句;
}
for语句流程图:
表达式1为初始化部分,用于初始化循环变量的。
表达式2为条件判断部分,用于判断循环时候终止。
表达式3为调整部分,用于循环条件的调整 。
先计算表达式1,然后判断是否满足表达式2,若满足则执行循环语句,再计算表达式3,判断是否满足表达式2,若满足则继续,若不慢则表达式2则终止for循环。
//for循环可用等价的while循环替代
表达式1;
while(表达式2)
{
语句;
表达式3;
}
例如:
int i = 0;
//使用while
i=1;//初始化部分
while(i<=10)//判断部分
{
printf("hehe\n");
i = i+1;//调整部分
}
//使用for
for(i=1; i<=10; i++)
{
printf("hehe\n");
}
for语句中的break和continue
for循环中也可以出现break和continue,他们的意义和在while循环中是一样的。
break
沿用while循环中的例子,我们可以使用for循环这么写
#include <stdio.h>
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
printf("第 %d 个同学已抢答! \n", i);
if (i == 3)
{
break;
}
}
return 0;
}
运行结果:
continue
#include <stdio.h>
int main()
{
int i = 0;
int t = 0;
for (i = 1; i <= 10; i++)
{
if (i % 2 == 0)
{
if (t == 3)
{
continue;
}
printf("第 %d 个同学已抢答! \n", i);
t++;
}
}
return 0;
}
运行结果:
for语句变种
#include <stdio.h>
int main()
{
//代码1(死循环)
for (;;)
{
printf("hehe\n");
}
//for循环中的初始化部分,判断部分,调整部分是可以省略的,但是不建议初学时省略,容易导致问题。
//代码2
int i = 0;
int j = 0;
//这里打印多少个hehe?
for (i = 0; i < 10; i++)
{
for (j = 0; j < 10; j++)
{
printf("hehe\n");
}
}
//代码3
int i = 0;
int j = 0;
//如果省略掉初始化部分,这里打印多少个hehe?
for (; i < 10; i++)
{
for (; j < 10; j++)
{
printf("hehe\n");
}
}
//代码4-使用多余一个变量控制循环
int x, y;
for (x = 0, y = 0; x < 2 && y < 5; ++x, y++)
{
printf("hehe\n");
}
return 0;
}
goto语句
C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。
从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。
但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过
程。
例如:一次跳出两层或多层循环。
多层循环这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环
C 语言中的 goto 语句允许把控制无条件转移到同一函数内的被标记的语句。
注意: 在任何编程语言中,都不建议使用 goto 语句。因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改。任何使用 goto 语句的程序可以改写成不需要使用 goto 语句的写法。
//goto语句语法
goto label;
..
.
label: statement;
//label 可以是任何除 C 关键字以外的纯文本,它可以设置在 C 程序中 goto 语句的前面或者后面
goto语句流程图
scanf
scanf 类型说明符:
类型 | 合格的输入 |
---|---|
%a、%A | 读入一个浮点值(仅 C99 有效)。 |
%c | 单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符。 |
%d | 十进制整数:数字前面的 + 或 - 号是可选的。 |
%e、%E、%f、%F、%g、%G | 浮点数:包含了一个小数点、一个可选的前置符号 + 或 -、一个可选的后置字符 e 或 E,以及一个十进制数字。两个有效的实例 -732.103 和 7.12e4 |
%i | 读入十进制,八进制,十六进制整数 。 |
%o | 八进制整数。 |
%s | 字符串。这将读取连续字符,直到遇到一个空格字符(空格字符可以是空白、换行和制表符)。 |
%u | 无符号的十进制整数。 |
%x、%X | 十六进制整数。 |
//%d %d是按十进值格式输入数值。输入时,在两个数据之间可以用一个或多个空格、tab 键、回车键分隔。
//&a,&b中的 & 是地址运算符,分别获得变量的内存地址。
//3,4
//3 4
//3
//4
scanf("%d %d",&a,&b);
//如果使用 , 来分隔输入的 %d, 相应的输入时也需要添加,
//3,4
scanf("%d,%d",&a,&b);
//这里没有使用&是因为arr是一个数组,而数组的首元素就是地址
scanf("%s",arr);,
getchar
getchar(获取字符),存放在int类型内。
//getchar函数的基本原型
int ch = getchar(void);
- getchar返回字符的ASCII码值,ASCII码值是整数,存放在整型变量中。
- getchar函数读取失败的时候返回EOF,EOF的本质是-1,是一个整型值,在一个char类型的变量中,是无法存储的。
- 结合getchar函数的原型,getchar的返回类型被定义为int,那么返回的数据就应该存放在int变量中。
putchar
//putchar函数声明
int putchar(int char)
字符以其对应的 int 值进行传递
该函数将指定的表达式的值所对应的字符输出到标准输出终端上。表达式可以是字符型或整型,它每次只能输出一个字符。
//putchar函数的基本格式为:
putchar(ch);
实例
//单个输入输出
#include <stdio.h>
int main()
{
int ch = getchar(); //接收字符
putchar(ch); //输出字符
return 0;
}
运行结果:
//循环输入输出
#include <stdio.h>
int main()
{
int ch = 0;
//EOF end of file 文件结束标志
while ((ch = getchar()) != EOF)
{
putchar(ch);
}
return 0;
}
运行结果:
//getchar与scanf
#include <stdio.h>
int main()
{
char password[20] = { 0 };
printf("请输入密码:>");
scanf("%s", password);
printf("请确认密码(Y/N):");
int ch = getchar();
if (ch == 'Y')
{
printf("密码正确\n");
}
else
{
printf("密码错误\n");
}
return 0;
}
运行结果:
???还没确认就没了???why???
#include <stdio.h>
int main()
{
char password[20] = { 0 };
printf("请输入密码:>");
scanf("%s", password);
getchar(); //消除\n
printf("请确认密码(Y/N):");
int ch = getchar();
if (ch == 'Y')
{
printf("密码正确\n");
}
else
{
printf("密码错误\n");
}
return 0;
}
运行结果1:
运行结果2:多个字符便会失败
过程演示:
像这种该咋办?
#include <stdio.h>
int main()
{
char password[20] = { 0 };
printf("请输入密码:>");
scanf("%s", password);
int tmp = 0;
while (tmp=getchar()!='\n')
{
; //空语句
}
printf("请确认密码(Y/N):");
int ch = getchar();
if (ch == 'Y')
{
printf("密码正确\n");
}
else
{
printf("密码错误\n");
}
return 0;
}
运行结果:
可通过while循环实现多次读入字符
scanf() 可输入不包含空格的字符串,不读取回车,空格和回车表示输入完毕。
getchar() 只能读取用户输入缓存区的一个字符,包括回车。
实例补知识
- 计算 n 的阶乘。
#include <stdio.h>
int main()
{
int n = 0, i;
int sum = 1;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
sum = sum * i; //1*2*3*4*5*...*n
}
printf("%d", sum);
return 0;
}
运行结果:
- 计算 1!+2!+3!+……+10!
#include <stdio.h>
int main()
{
int n = 0, i = 0;
int sum = 1;
for (i = 1; i <= 10; i++)
{
sum = sum * i;
n = n + sum;
}
printf("%d\n", n);
return 0;
}
运行结果:
- 在一个有序数组中查找具体的某个数字n。(二分查找/折半查找)
二分查找/折半查找,要求是有序数组
什么是二分查找/折半查找?
例如:我们要在1-10之间查找一个数字7
怎么找呢?
1.挨个找,从1开始往后挨个查找,最坏找10次
2.折半查找,每次取中间那个数比较,如下图
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]); //计算数组个数
int left = 0; //左下标
int right = sz - 1; //右下标
int k = 7; //要查找的数
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;
}
- 编写代码,演示多个字符从两端移动,向中间汇聚
#include <stdio.h>
#include <string.h>
#include <Windows.h>
int main()
{
char arr[] = "Happy New Year!";
char brr[] = "###############";
int left = 0;
int right = strlen(arr) - 1; //strlen 计算数组大小,是string.h头文件内命令
while (left <= right)
{
brr[left] = arr[left];
brr[right] = arr[right];
printf("%s\n", brr);
Sleep(1000); //将目前动作延迟一段时间,是Windows.h头文件内命令
left++;
right--;
}
return 0;
}
运行结果:
同一行多个字符从两端移动,向中间汇聚
#include <stdio.h>
#include <string.h>
#include <Windows.h>
#include <stdlib.h>
int main()
{
char arr[] = "Happy New Year!";
char brr[] = "###############";
int left = 0;
int right = strlen(arr) - 1; //strlen 计算字符串长度.
while (left <= right)
{
brr[left] = arr[left];
brr[right] = arr[right];
printf("%s\n", brr);
Sleep(1000); //将目前动作延迟一段时间,单位是毫米,是Windows.h头文件内命令
system("cls"); //清理屏幕,是stdlib.h头文件内命令
left++;
right--;
}
printf("%s\n", brr);
return 0;
}
strlen(str),是string.h头文件内命令
str – 要计算长度的字符串
该函数返回字符串的长度
直到空结束字符,但不包括空结束字符
运行结果:
- 编写代码实现,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则提示登录成功,如果三次均输入错误,则退出程序)。
#include <stdio.h>
#include <string.h>
int main()
{
//正确密码为ayw123456
char password[20] = { 0 };
int i = 0;
for (i = 0; i < 3; i++)
{
scanf("%s", password);
if (strcmp(password, "ayw123456") == 0)
{
printf("密码正确,登录成功!\n");
break;
}
else
{
printf("密码错误,请重新输入!\n");
}
}
if(i == 3)
{
printf("连续三次输入错误,登录失败!\n");
}
return 0;
}
strcmp(str1,str2),是string.h头文件内命令
str1 – 要进行比较的第一个字符串。
str2 – 要进行比较的第二个字符串。
该函数返回值如下:
如果返回值小于 0,则表示 str1 小于 str2。
如果返回值大于 0,则表示 str1 大于 str2。
如果返回值等于 0,则表示 str1 等于 str2。
只能比较字符串,即可用于比较两个字符串常量,或比较数组和字符串常量,不能比较数字等其他形式的参数。
- 猜数字小游戏
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("**********************************\n");
printf("************* 1.play *************\n");
printf("************* 0.exit *************\n");
printf("**********************************\n");
}
//RAND_MAX--rand函数能返回随机数的最大值。
void game()
{
int random_num = rand() % 100 + 1;
int input = 0;
while (1)
{
printf("请输入猜的数字>:");
scanf("%d", &input);
if (input > random_num)
{
printf("猜大了\n");
}
else if (input < random_num)
{
printf("猜小了\n");
}
else
{
printf("恭喜你,猜对了\n");
break;
}
}
}
int main()
{
int input = 0;
srand((unsigned)time(NULL));
do
{
menu();
printf("请选择>:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("选择错误,请重新输入!\n");
break;
}
} while (input);
return 0;
}
rand( ),随机数发生器,所在头文件 stdlib.h
rand( ),该函数返回一个范围在 0 到 RAND_MAX 之间的整数值。
要取得 [a,b) 的随机整数,使用 (rand() % (b-a))+ a;
要取得 [a,b] 的随机整数,使用 (rand() % (b-a+1))+ a;
要取得 (a,b] 的随机整数,使用 (rand() % (b-a))+ a + 1;
通用公式: a + rand() % n;其中的 a 是起始值,n 是整数的范围。
要取得 a 到 b 之间的随机整数,另一种表示:a + (int)b * rand() / (RAND_MAX + 1)。
要取得 0~1 之间的浮点数,可以使用 rand() / double(RAND_MAX)。
srand( ),初始化随机数发生器,所在头文件 stdlib.h
srand( ) 用来设置 rand() 产生随机数时的随机数。参数 seed 必须是个整数,如果每次 seed 都设相同值,rand( ) 所产生的随机数值每次就会一样。
rand( ) 产生的随机数在每次运行的时候都是与上一次相同的。若要不同, 用函数 srand() 初始化它。可以利用 srand((unsigned int)(time(NULL)) 的方法,产生不同的随机数,因为每一次运行程序的时间是不同的。
给srand( )提供一个数,它是一个unsigned int类型;
以上rand与srand来源于 RUNOOB.com
运行结果: