跳到主要内容

for 循环与数组

配置 VS2019 快捷导入代码

  1. 准备快捷导入代码的脚本文件,保存在系统目录中(位置自定义)。
  2. 在 VS2019 中配置,使用上述目录中的脚本文件: 工具 —— 代码片段管理器 —— 修改 Basic 为 Visual C++ —— 选择上述自定义的目录位置(不需要选择到具体脚本文件)。
  3. 在程序中使用快捷导入代码:输入 #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)

练习:猜数字游戏

产生一个随机数,用户键盘键入一个数据,程序提示用户输入的数据 ><== 随机数。用户根据提示不断变换输入,最终猜中。

生成随机数

  1. 添加一个随机数种子。作用:保证随机是真正的随机。
  2. 添加头文件。
  3. 生成随机数。
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 可以跳出一重循环(forwhiledo 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

语法:

  1. 设定一个标签。标签名自定义,一般大写,如 ABCLABLEAAA
  2. 使用 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:用来打印变量内存地址的专用格式匹配符(占位符)。

基本特性

  1. 各个元素连续存储。
  2. 数组名为地址,是数组首个元素的地址。arr == &arr[0]
  3. 求数组的总大小:
    printf("数组的大小:%u\n", sizeof(arr));
  4. 求数组每一个元素的大小:
    printf("数组元素的大小:%u\n", sizeof(arr[0]));
  5. 求数组元素的个数:
    printf("数组元素的个数:%d\n", sizeof(arr) / sizeof(arr[0]));
  6. 数组第一个元素的下标:0
  7. 数组最后一个元素的下标:
    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;
}