for 循环与数组
配置 VS2019 快捷导入代码
- 准备快捷导入代码的脚本文件,保存在系统目录中(位置自定义)。
- 在 VS2019 中配置,使用上述目录中的脚本文件: 工具 —— 代码片段管理器 —— 修改 Basic 为 Visual C++ —— 选择上述自定义的目录位置(不需要选择到具体脚本文件)。
- 在程序中使用快捷导入代码:输入
#1后按tab键。
for 循环
语法
for (表达式1; 表达式2; 表达式3)
{
循环体
}
执行流程:循环从表达式1开始 ——> 表达式2(判别表达式)——> 真 ——> 执行循环体 ——> 表达式3 ——> 判断表达式2。
- 真:继续 ——> 循环体 ——> 表达式3 ——> 表达式2 ......
- 假:跳出循环。(正常情况下,for 循环的出口是表达式2)
练习:使用 for 循环求 1~100 的和
// 1~100 求和 1+2+3+4+5+。。。+100
int main(void)
{
// 定义循环因子
int i = 0; // 定义 i,给初值
// 定义变量记录累加值
int sum = 0; // 初值为 0
for (i = 1; i ≤ 100; i++)
{
sum = sum + i;
}
// 循环结束,打印累加结果
printf("sum = %d\n", sum);
return EXIT_SUCCESS;
}
for 循环的变换形式
循环因子 i:
- 在 for 循环之前定义:在 for 循环结束后依然能使用。
- 定义在 for 循环之内:for 循环结束后不能使用!
for 循环的 3 个表达式在使用时均可省略,但 2 个 ; 不允许省略。
将 i 的定义放到 for 内表达式1上:
for (int i = 1; i ≤ 100; i++) // 将 i 的定义放到 for 内表达式1上
{
sum = sum + i;
}
// 循环结束,打印累加结果
printf("sum = %d, i = %d\n", sum, i); // 编译器报错,"未定义标识符"
1. 省略表达式1:
int i = 1; // 定义循环因子
int sum = 0;
for (; i ≤ 100; i++) // 不写表达式1
{
sum = sum + i;
}
2. 省略表达式3:
int i = 1; // 定义循环因子
int sum = 0;
for ( ; i ≤ 100; ) // 不写表达式1,不写表达式3
{
sum = sum + i;
i++; // 将原来的表达式3写到循环体中
}
3. 省略表达式2(死循环):
int i = 1; // 定义循环因子
for ( ; ; ) // 不写表达式2,相当于 for ( ; 1 ; ) 表达式2为真(1),这是一个死循环
{
printf("i = %d\n", i);
i++;
}
// for ( ; ; ) 死循环 相当于 while(1) {};
for 每个表达式中可以含有多个算式:
int i = 0; // 定义循环因子
int a = 0;
for (i=1, a=3; a<20, i<10; i++, a+=3) // i<10, a<20 也可以写成 i<10 && a<20
{
printf("i = %d\n", i);
printf("a = %d\n", a);
}
死循环
// 方法1:
for(;;)
// 方法2:
while(1)
练习:猜数字游戏
产生一个随机数,用户键盘键入一个数据,程序提示用户输入的数据 >、< 或 == 随机数。用户根据提示不断变换输入,最终猜中。
生成随机数
- 添加一个随机数种子。作用:保证随机是真正的随机。
- 添加头文件。
- 生成随机数。
srand(time(NULL)); // 固定写法
// time(NULL): 获取系统当前时间,unsigned long long 类型
// srand() 函数用来播种随机数种子,使用系统时间作为算法的系数
// srand() --- <stdlib.h>
// time() --- <time.h>
生成指定范围的随机数:
int n = rand() % 100; // 随机数范围: 0 ~ 99
int n = rand() % 100 + 13; // 随机数范围: 13 ~ 112
int n = rand() % 63 + 17; // 随机数范围: 0+17 ~ 62+17
思路分析(伪代码)
// 伪代码
int main(void)
{
// 1. 生成随机数(3 步骤)
// 2. 创建死循环,供用户猜测 while(1)
int num;
while (1)
{
// 接收用户输入: scanf("%d", &num);
// if 判断用户输入的数据,与实际随机数比大小
// num > 随机数 提示用户,继续循环
// num < 随机数 提示用户,继续循环
// num == 随机数 提示用户猜中,结束循环
// break; 跳出循环
}
return 0;
}
编码实现
int main(void)
{
// 播种随机数种子
srand(time(NULL));
// 生成随机数 n
int n = rand() % 100; // 范围 0-99
// 定义 num 变量,存储用户输入的数据
int num;
// 创建死循环,给用户猜数字
for (;;) // 与 while(1) 等价
{
printf("请输入猜测的数字:");
// 获取用户输入数据
scanf("%d", &num);
// 提示用户,测试方向
if (num > n)
{
printf("猜大了!\n");
}
// 如果 if 分支、for、while 满足后,执行语句只有一条时,{} 可以省略
else if (num < n)
printf("猜小了!\n"); // 语法允许,不写 {}
else
{
printf("猜中了!!!\n");
break; // 不必再循环
}
}
printf("本尊数:%d\n", n);
return EXIT_SUCCESS;
}
嵌套 for 循环
结论:外层循环执行一次,内层循环执行一周。
int i = 0; // 外层循环的循环因子
int j = 0; // 内层循环的循环因子
for (i = 0; i < 10; i++)
{
for (j = 2; j < 10; j++)
{
// 循环体
}
}
练习:模拟电子表打印
分析(三层嵌套,时分秒):
// 最外层
for (i = 0; i < 24; i++)
{
for (j = 0; j < 60; j++)
{
for (k = 0; k < 60; k++)
{
// 打印时间
}
}
}
// 11:30:54
// 11:30:56
// ...
// 12:00:00
// 12:00:01
实现:
int main(void)
{
int i, j, k;
for (i = 0; i < 24; i++) // 小时
{
for (j = 0; j < 60; j++) // 分钟
{
for (k = 0; k < 60; k++) // 秒
{
printf("%02d:%02d:%02d\n", i, j, k);
Sleep(980);
system("cls"); // 清屏
}
}
}
return EXIT_SUCCESS;
}
练习:打印正序 9x9 乘法表
分析:第 i 行,打印 i 列,每项为 jxi。
1x1= 1 // 第1行,打印1列
1x2= 2 2x2= 4 // 第2行,打印2列
1x3= 3 2x3= 6 3x3= 9 // 第3行,打印3列
1x4= 4 2x4= 8 3x4=12 4x4=16 // 第4行,打印4列
...
1x9= 9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81 // 第9行,9列
实现:
for (i = 1; i ≤ 9; i++) // 外层,描述行
{
for (j = 1; j <= i; j++) // 内层,描述每一列
{
printf("%dx%d=%d\t", j, i, i*j);
}
printf("\n");
}
练习:打印倒序 9x9 乘法表
1x9= 9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81
1x8= 8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x7= 7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x6= 6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x5= 5 2x5=10 3x5=15 4x5=20 5x5=25
1x4= 4 2x4= 8 3x4=12 4x4=16
1x3= 3 2x3= 6 3x3= 9
1x2= 2 2x2= 4
1x1= 1
省略 {} 的写法(无误,但不推荐):
for (i = 9; i >= 1; i--) // i 控制行
{
for (j = 1; j <= i; j++)
printf("%dx%d=%d\t", j, i, i*j);
putchar('\n');
}
推荐写法:
int main(void)
{
int i, j;
for (i = 9; i >= 1; i--)
{
for (j = 1; j <= i; j++)
{
printf("%dx%d=%d\t", j, i, j * i);
}
putchar('\n'); // 等价于 printf("\n");
}
return EXIT_SUCCESS;
}
跳转语句
break
- 作用 1:一次 break 可以跳出一重循环(
for、while、do while)。 - 作用 2:防止 case 穿透,结束
switch()。
continue
作用:结束本次循环。continue 关键字之后的代码,在这次循环中不执行。
示例:
int main(void)
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 5; j++)
{
if (j == 2)
{
continue; // 只跳过(后续代码不执行)本次 j == 2 时的循环
}
printf("i = %d, j = %d\n", i, j);
}
printf("\n");
}
return EXIT_SUCCESS;
}
goto
语法:
- 设定一个标签。标签名自定义,一般大写,如
ABC、LABLE、AAA。 - 使用
goto 标签名跳转到标签的位置(只在函数内生效)。
示例:
int main(void)
{
printf("==========1=========\n");
printf("==========2=========\n");
printf("==========3=========\n");
goto LABLE;
printf("==========4=========\n");
printf("==========5=========\n");
printf("==========6=========\n");
printf("==========7=========\n");
LABLE:
printf("==========8=========\n");
printf("==========9=========\n");
return EXIT_SUCCESS;
}
goto 语法过于灵活,会打乱程序的执行逻辑,降低代码的可读性,后续编程中尽量少用。C 程序中,简单的逻辑依然可以使用 goto。
数组
什么是数组:数组是相同数据类型有序的、连续的存储集合。
%p:用来打印变量内存地址的专用格式匹配符(占位符)。
基本特性
- 各个元素连续存储。
- 数组名为地址,是数组首个元素的地址。
arr == &arr[0] - 求数组的总大小:
printf("数组的大小:%u\n", sizeof(arr));
- 求数组每一个元素的大小:
printf("数组元素的大小:%u\n", sizeof(arr[0]));
- 求数组元素的个数:
printf("数组元素的个数:%d\n", sizeof(arr) / sizeof(arr[0]));
- 数组第一个元素的下标:
0 - 数组最后一个元素的下标:
sizeof(arr) / sizeof(arr[0]) - 1
数组初始化
// 初始化方法1
int arr[5] = {3, 7, 2, 1, 9};
// 初始化方法2【多用】
int arr[5] = {3, 7}; // 剩余未初始化的元素,默认值 0
// 初始化方法3【多用】
int arr[5] = {0}; // 初始化一个全部元素为 0 的数组 --- 清 0 常用
// 初始化方法4【多用】
int arr[] = {3, 7, 2, 1, 6, 9, 13}; // 编译器会自动求取数组元素个数
// 初始化方法5
int arr[] = {0}; // 定义了只有一个元素的数组,值为 0
// 初始化方法6【多用】
int arr[10]; // 声明了一个有 10 个元素的数组
arr[0] = 5;
arr[1] = 6;
arr[2] = 7; // 剩余未初始化的元素,默认值 —— 随机数
练习:数组元素逆序
// 数组元素逆序
int main(void)
{
int arr[] = {1, 6, 8, 0, 4, 3, 9, 2}; // 变为:{2, 9, 3, 4, 0, 8, 6, 1}
// 获取数组的元素个数
int n = sizeof(arr) / sizeof(arr[0]);
int i = 0; // 从前向后
int j = n - 1; // 从后向前
int tmp = 0; // 定义临时变量
// 交换数组元素之前,打印数组的所有元素
for (int i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
putchar('\n');
// 循环交换数组元素
while (i < j)
{
tmp = arr[i]; // 三杯水变量交换法
arr[i] = arr[j];
arr[j] = tmp;
i++; // 不断后移
j--; // 不断前移
}
// 交换数组元素之后,打印数组的所有元素
for (int i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
putchar('\n');
return 0;
}
冒泡排序
int main(void)
{
int i, j, tmp;
int xjp[] = {12, 2, 32, 14, 62, 54, 27, 89, 9, 10, 3};
// 求取数组元素个数
int n = sizeof(xjp) / sizeof(xjp[0]);
// 开始排序
for (i = 0; i < n - 1; i++) // 外层控制行
{
for (j = 0; j < n - 1 - i; j++) // 内层控制列
{
// 相邻两两比较,三杯水交换
if (xjp[j] > xjp[j + 1])
{
tmp = xjp[j];
xjp[j] = xjp[j + 1];
xjp[j + 1] = tmp;
}
}
}
// 打印排序结果
for (i = 0; i < n; i++)
{
printf("%d ", xjp[i]);
}
printf("\n");
return EXIT_SUCCESS;
}