1.for循环
对于for循环的,其语法如下:
for(表达式1; 表达式2;表达式3)
{
执行的语句;
}
一般来说表达式1是循环的初始化条件,表达式2是一个判别表达式,当表达式的值为真的时候就执行循环中的语句,表达式3一般是循环因子改变的表达式。for循环执行的流程如下所示:
在for循环中,如果循环因子定义在for循环内的话,则for循环结束之后,循环因子不能使用;如果定义在for循环之外,则循环结束的时候循环因子仍可以使用。
在使用for循环的时候,for循环可以有多种写法,三个表达式都可以根据情况省略,如果三个表达式均省略,不使用break的情况下就是一个死循环。如果要在满足一定的条件下跳出循环的话,可以使用break语句,break的作用是跳出一重循环,用于for、while、do-while之中。当然在之前的switch语句也有break,那里的作用是防止case穿透。
关于for循环的一些基本示例代码如下:
#if 0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 基础for循环
void test1()
{
int i = 0; // 循环因子
int sum = 0;
for (i = 0; i <= 100; i++)
{
sum += i; // sum = sum + i;
}
printf("sum = %d\n", sum);
}
// 省略表达式1
void test2()
{
int i = 1;
int sum = 0;
for (; i <= 100; i++)
{
sum += i;
}
printf("sum = %d\n", sum);
}
// 省略表达式3
void test3()
{
int i = 1;
int sum = 0;
for (; i <= 100;)
{
sum += i;
i++;
}
printf("sum = %d\n", sum);
}
// 省略表达式123
void test4()
{
int i = 0;
// for(;1;) // 死循环
for (;;)
{
printf("i = %d\n", i);
i++;
}
}
// 表达式有多个
void test5()
{
int i = 0;
int a = 0;
for (i = 1, a = 2; i < 5, a < 20; i++, a += 2)
{
printf("i = %d\n", i);
printf("a = %d\n", a);
}
}
int main(int argc, char *argv[])
{
// test1();
// test2();
// test3();
// test4();
test5();
system("pause");
return 0;
}
#endif
为了提高能力,接下来做一个简单的猜数字游戏。
【猜数字游戏】:计算机随机生成一个0~99的数字,用户输入猜测的数字,计算机根据用户输入的数字给出提示猜大了或者是猜小了或者是猜中。代码如下:
#if 0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(int argc, char *argv[])
{
srand(time(NULL)); // 种随机数种子
int guess_number = 0;
int random_number = rand() % 100; // 生成随机数
for (;;)
{
printf("请输入猜测的数字: ");
scanf("%d", &guess_number);
if (guess_number > random_number) // for、while、if如果执行语句只有一条,{}可以省略不写
{
printf("猜大了\n");
}
else if (guess_number < random_number)
printf("猜小了\n");
else
{
printf("猜中了\n");
break;
}
}
printf("本尊是 %d\n", random_number);
system("pause");
return 0;
}
#endif
在上述代码中,我们使用了srand()函数,这个函数位于stdlib.h头文件中,主要作用是用于种随机数种子。在后面的代码中使用了rand()函数获取一个随机数。此处的srand()函数是必须种随机数种子的,此处传了一个time(NULL),主要作用是将随机数种子设置为当前的时间戳。如果不这样做,则rand()产生的随机数是一个伪随机数,也就是第一次会产生一个随机数N,而后续程序运行的时候产生的随机数也仍然是N,固定不变。而种了随机数种子之后就是真正的随机数,无论多少次运行,每次生成的随机数都不一样。
在for循环使用的时候,也可以嵌套其他的循环进行使用。比如生活中就有很多这样的例子,比如时间,秒针走六十个刻度分针才走一个刻度,分针走六十个刻度时针才走一个刻度。根据这个接下来给一个模拟电子表的案例,模拟上述的过程。代码如下:
#if 0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
int main(int argc, char *argv[])
{
int h, m, s;
// 小时
for (h = 0; h < 24; h ++)
// 分钟
for (m = 0; m < 60; m ++)
// 秒
for (s = 0; s < 60; s++)
{
printf("%02d:%02d:%02d\n", h, m, s);
Sleep(980);
system("cls"); // 清屏
}
system("pause");
return 0;
}
#endif
在代码中使用了一个Sleep()函数,该函数主要位于Windows.h头文件中,用于程序的睡眠。该函数的参数单位为ms。由于程序运行也会需要一些时间,所以此处传入的值不是1000,而是比1000要小一点。
下面给两个关于for循环嵌套的例子。
【九九乘法表】编写程序打印以下两个表的内容:
1*1= 1
1*2= 2 2*2= 4
1*3= 3 2*3= 6 3*3= 9
1*4= 4 2*4= 8 3*4=12 4*4=16
1*5= 5 2*5=10 3*5=15 4*5=20 5*5=25
1*6= 6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7= 7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8= 8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9= 9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
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
代码如下:
#if 1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 正序99乘法表
void test1()
{
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= i; j++)
printf("%d*%d=%2d\t", j, i, i * j);
printf("\n");
}
}
// 倒序99乘法表
void test2()
{
for (int i = 9; i >= 1; i--)
{
for (int j = 1; j <= i; j++)
printf("%d*%d=%2d\t", j, i, i * j);
printf("\n");
}
}
int main(int argc, char *argv[])
{
test1();
// test2();
system("pause");
return 0;
}
#endif
在使用循环的时候,有时候我们会遇到满足某个条件不执行后续的代码,而直接进入下一次循环,此时就需要用到continue
关键字。continue
的作用是结束本次循环,在continue之后的循环体,在本次循环执行中不执行。下面给一个关于continue代码的示例:
#if 0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
for (int i = 0; i < 5; i++)
{
if (i == 3)
{
continue;
}
printf("i = %d\n", i);
printf("==========1==========\n");
printf("==========2==========\n");
printf("==========3==========\n");
printf("==========4==========\n");
printf("==========5==========\n");
}
}
void test2()
{
int num = 5;
// while (num-- != 0)
while (num--)
{
printf("num = %d\n", num);
if (num == 3)
{
continue;
}
printf("=============1================\n");
printf("=============2================\n");
printf("=============3================\n");
printf("=============4================\n");
printf("=============5================\n");
}
}
int main(int argc, char *argv[])
{
// test1();
test2();
system("pause");
return 0;
}
#endif
2.goto语句
goto语句是一个跳转语句,主要是设置一个标签,然后使用goto就会跳转到标签处,只在函数内部的时候生效。由于goto太过于灵活会破坏程序的结构,所以通常不使用它。下面给出关于goto的一个代码示例:
#if 0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
printf("===============1================\n");
printf("===============2================\n");
goto LABLE;
printf("===============3================\n");
printf("===============4================\n");
printf("===============5================\n");
printf("===============6================\n");
printf("===============7================\n");
LABLE:
printf("===============8================\n");
printf("===============9================\n");
printf("===============10================\n");
}
void test2()
{
int i = 0, j = 0;
for (i = 0; i < 10; i++)
{
if (i == 5) goto LABLE1;
printf("i = %d\n", i);
}
for (j = 0; j < 20; j++)
{
LABLE1:
printf("j = %d\n", j);
}
}
int main(int argc, char *argv[])
{
// test1();
test2();
system("pause");
return 0;
}
#endif
3.数组
为了方便处理数据,把具有相同类型的若干变量有序形式组织起来称为数组。数组就是在内存中连续的相同类型的变量空间。数组的定义是数据类型 数组名[数组长度];
。定义的时候若长度为N,则访问数组的下标是0到N-1。数组的数组名是一个地址,它与数组首元素的地址是相同的。数组的初始化有很多方法,下面以int类型为例,初始化的方法如下:
// 初始化方法1: 初始化元素个数和数组长度一样
int arr[5] = {1, 2, 3, 4, 5};
// 初始化方法2: 初始化部分元素,剩余未初始化的元素默认为0值
int arr[5] = {1, 2, 3};
// 初始化方法3: 初始化全0数组
int arr[5] = {0};
// 初始化方法4: 不指定长度,编译器自动确定数组长度
int arr[] = {2, 3, 4, 5, 6};
// 初始化方法5: 对于其它未赋值的元素值为随机数
int arr[5];
arr[0] = 23;
arr[2] = 12;
下面给出关于数组操作的一些示例代码:
#if 0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <Windows.h>
// 数组的地址与数组首元素的地址一样
void test1()
{
int a = 5, b = 29, c = 10;
int arr[10] = { 1, 2, 4, 5, 7, 23, 54, 3, 4, 3 };
printf("&arr[0] = %p\n", &arr[0]); // 取数组首元素的地址
printf("arr = %p\n", arr); // 数组名
}
// 数组的一些基本信息
void test2()
{
int arr[12] = { 1, 43, 3, 4, 2, 4, 23, 6, 8, 34, 3, 5 };
printf("数组大小: %u\n", sizeof(arr));
printf("数组元素的大小: %u\n", sizeof(arr[0]));
printf("数组元素个数: %d\n", sizeof(arr) / sizeof(arr[0]));
}
// 数组的初始化
void test3()
{
int arr[10];
arr[0] = 5;
arr[1] = 4;
arr[3] = 56;
int n = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < n; i++)
{
printf("%d\n", arr[i]);
}
}
int main(int argc, char* argv[])
{
// test1();
// test2();
test3();
system("pause");
return 0;
}
#endif
【数组元素的逆转】给定一个数组,将数组的值倒序输出。代码如下:
#if 0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <Windows.h>
int main(int argc, char* argv[])
{
int arr[] = { 12, 234, 34, 23, 4, 324, 5, 34, 42, 54, 32 };
int len = sizeof(arr) / sizeof(arr[0]); // 求数组的长度
int i = 0; // 数组首元素的下标
int j = len - 1; // 数组最后一个元素的下标
int temp = 0;
while (i < j)
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
// 输出交换后的下标
for (i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
system("pause");
return 0;
}
#endif
【冒泡排序法】使用冒泡排序法将给定数组从小到大排序。代码如下:
#if 0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <Windows.h>
int main(int argc, char* argv[])
{
int arr[] = { 32, 4, 23, 54, 43, 65, 7};
int len = sizeof(arr) / sizeof(arr[0]); // 数组元素的个数
int temp = 0;
// 打印冒泡排序前的元素
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
putchar('\n');
// 冒泡排序法
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
// 输出冒泡排序后的元素
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
putchar('\n');
system("pause");
return 0;
}
#endif
冒泡排序的操作是数组从左到右两两依次比较,如果前者元素大于后面的元素,则交换两个元素的位置。直到数组有序即可。现在看第1趟排序。
初始转态:
32
,
4
,
23
,
54
,
43
,
65
,
7
32, 4, 23, 54, 43, 65, 7
32,4,23,54,43,65,7
第1次32和4比较,34比4大,所以34往后走,4往前走,得:
4
,
32
‾
,
23
,
54
,
43
,
65
,
7
\underline{4, 32}, 23, 54, 43, 65, 7
4,32,23,54,43,65,7
第2次32和23比较,32比23大,所以34往后走,23往前走,得:
4
,
23
,
32
‾
,
54
,
43
,
65
,
7
4, \underline{23, 32}, 54, 43, 65, 7
4,23,32,54,43,65,7
第3次32和54比较,32比54小,所以不变:
4
,
23
,
32
,
54
‾
,
43
,
65
,
7
4, 23, \underline{32, 54}, 43, 65, 7
4,23,32,54,43,65,7
第4次54和43比较,54比43大,所以54往后走,43往前走,得:
4
,
23
,
32
,
43
,
54
‾
,
65
,
7
4, 23, 32, \underline{43, 54}, 65, 7
4,23,32,43,54,65,7
第5次54和65比较,54比65小,所以不变:
4
,
23
,
32
,
43
,
54
,
65
‾
,
7
4, 23, 32, 43, \underline{54, 65}, 7
4,23,32,43,54,65,7
第6次65和7比较,65比7大,所以65往后走,7往前走,得:
4
,
23
,
32
,
43
,
54
,
7
,
65
‾
4, 23, 32, 43, 54, \underline{7,65}
4,23,32,43,54,7,65
七个数字,经过六次比较,第一趟使最大的数放在了数组的最右。由于最后一个数字是最大的,所以第二趟可以不参与比较,而每一趟都可以找到一个最大的数放在所比较的所有元素的最右边。每一趟结果如下所示。
第一趟
4
,
23
,
32
,
43
,
54
,
7
,
65
4, 23, 32, 43, 54, 7,\bold{65}
4,23,32,43,54,7,65
第2趟:
4
,
23
,
32
,
43
,
7
,
54
,
65
4,23,32,43,7,\bold{54,65}
4,23,32,43,7,54,65
第3趟:
4
,
23
,
32
,
7
,
43
,
54
,
65
4,23,32,7,\bold{43,54,65}
4,23,32,7,43,54,65
第4趟:
4
,
23
,
7
,
32
,
43
,
54
,
65
4,23,7,\bold{32,43,54,65}
4,23,7,32,43,54,65
第5趟:
4
,
7
,
23
,
32
,
43
,
54
,
65
4,7,\bold{23,32,43,54,65}
4,7,23,32,43,54,65
第6趟:
4
,
7
,
23
,
32
,
43
,
54
,
65
4,\bold{7,23,32,43,54,65}
4,7,23,32,43,54,65
最后得到的数组就是一个从小到大的有序序列。