C语言之三种循环结构与递归函数的对比
一种好的编程语言应该能够提供以下三种形式的程序流:
1.顺序执行语句(顺序结构);
2.在满足某个条件的情况下反复执行一块语句(循环结构);
3.通过进行条件判断可以在多个可选的语句块之间选择执行(分支结构).
接下来,我来谈谈我对C语言中三种循环结构域递归函数的异同点的理解.
使用循环可以多次执行多条语句(称为循环体语句).在C语言中,有三种循环结构,分别是:
while,do-while,for;以及一种有循环作用的函数:递归函数.
所有的循环都可以扩展为具有四种语句组成,分别是:初始化语句,判断条件语句,控制条件语句,循环体语句;
在这些语句中,循环体语句被反复执行的次数由循环条件控制,称为"判断条件语句".这是一个数量类型的表达式,
如果判断条件的值不等于0,循环条件为true;反之,循环条件为false.
一. for循环
1.格式
for(初始化语句;判断条件语句;控制条件语句){循环体语句;
}
执行流程:
a:执行初始化语句;
b:执行判断条件语句;
如果这里是true,就继续
如果这里是false,循环就结束
c:执行循环体语句;
d:执行控制条件语句;
e:回到b.
2.注意事项
a:判断条件语句无论简单还是复杂,结果是BOOL类型;b:循环体语句如果是一条,可以省略大括号,但是不建议省略;
c:有分号就没有左大括号,有左大括号就没有分号.
3.案例:用for循环结构实现1至100之间的和
#include <stdio.h>int main () {
int sum = 0;
/*
int i = 1 : 初始化语句
i <= 100 : 判断条件语句
i ++ : 控制条件语句
sum += i : 循环体语句
*/
for (int i = 1; i <= 100; i ++) {
sum += i;
}
printf("for循环:sum = %d\n",sum);
return 0;
}
二.while循环
1.格式
(1)基本格式
while(判断条件语句) {循环体语句;
}
(2)扩展格式:
初始化语句;while(判断条件语句){
循环体语句;
控制条件语句;
}
2.for和while的区别
a:使用上的区别while循环与for循环可以互换,区别在于for为了循环而定义的变量在for循环结束就是在内存中释放。
而while循环使用的变量在循环结束后还可以继续使用。这是因为for循环中定义的变量是局部变量,
而while循环的初始化变量定义在while循环体外,是一个全局变量.
b:理解上的区别
for循环适合于一个范围的判断;
while循环适合次数不明确的.
3.案例:用while循环结构实现1至100之间的和
#include <stdio.h>int main () {
/*
int i = 1 : 初始化语句
i <= 100 : 判断条件语句
sum += i : 循环体语句
i ++ : 控制条件语句
*/
int i = 1, sum = 0;
while(i <= 100){
sum += i;
i ++;
}
printf("while循环:sum = %d\n",sum);
return 0;
}
三.do...while循环
1.格式
(1)基本格式
do {循环体语句;
}while(判断条件语句);
(2)扩展格式:
初始化语句;do {
循环体语句;
控制条件语句;
}while(判断条件语句);
2.案例:用do...while循环结构实现1至100之间的和
#include <stdio.h>int main () {
/*
int i = 1 : 初始化语句
sum += i : 循环体语句
i ++ : 控制条件语句
i <= 100 : 判断条件语句
*/
int i = 1, sum = 0;
do {
sum += i;
i ++;
} while(i <= 100);
printf("do...while循环:sum = %d\n",sum);
return 0;
}
四.三种循环的对比
1.通过查看for循环的基本格式和while及do...while循环的扩展格式,可知三种循环的格式是可以统一的,都需要满足四个条件(有时可省略其中几个条件).2.三种循环的区别
a:do...while循环至少执行一次循环体;
b:for和while必须先判断条件是否是true,然后后才能决定是否执行循环体.
3.循环使用的注意事项(死循环)
A:一定要注意修改控制条件,否则容易出现死循环;
B:最简单的死循环格式
a:while(true){...}
b:for( ; ; ){ }
五.递归函数
1.格式
函数类型 函数名(参数列表) {判断条件语句;
控制条件语句;
循环条件语句;
函数名(参数列表);
}
调用递归函数:函数名(初始化参数);
2.递归函数的底层实现
因为递归函数是函数自己调用自己,所以在每次调用函数时,都会重新创建新的变量,这些变量,以及调用者的地址(返回时需要),都存储在堆栈中,递归函数每递归一次都会造成堆栈上新增加一块数据,即不断的增大内存空间的使用量.
所以程序员要确保堆栈的空间够大,能够容纳递归函数在递归的时候产生的中间结果.
3.案例:
/*使用递归遍历下面的数组
int array[] = {9,3,42,23,5,7,67,23,12,65,27,28,34,1,8,43};
*/
#include <stdio.h>
// 递归函数
void arr(int array[], int index) {
/* 判断条件语句 */
if(index <= 0) {
return;
}
/* 控制条件语句 */
index --;
/* 函数名(参数列表)--->递归函数本身 */
arr(array,index);
/* 循环条件语句 */
printf("%d ",array[index]);
}
int main () {
int array[] = {9,3,42,23,5,7,67,23,12,65,27,28,34,1,8,43};
// 获取数组的长度
int count = sizeof(array) / sizeof(int);
/* 调用递归函数:函数名(初始化参数) */
arr(array,count);
printf("\n");
return 0;
}
六.递归函数和三种循环在使用时的选择
即使递归函数可以对某些问题提供优雅和紧致的解决方案,但是简单的循环同时也是可以实现的.另一方面递归函数在递归的过程中,不断开辟空间,对内存的消耗过大,但是简单的循环却没有这样的问题,所以能使用循环解决的问题,
最好不要使用递归函数解决.
七.三种循环和递归函数对同一题目的解法对比
题目:有6个人坐在一起,问第6个人有多少岁,他说比第5个人大3岁;问第5个人有多少岁,他说比第4个人大3岁;问第4个人有多少岁,他说比第3个人大3岁;问第3个人有多少岁,他说比第2个人大3岁;
问第2个人有多少岁,他说比第2个人大3岁;问最后1个人,他说是15岁.那么,第6个人多少岁?
1.for循环
#include <stdio.h>int main () {
int age = 15;
/*
int i = 1 : 初始化语句
i < 6 : 判断条件语句
age += 3 : 循环体语句
i ++ : 控制条件语句
*/
for(int i = 1; i < 6; i ++) {
age += 3;
}
printf("第6个人%d岁.\n",age);
return 0;
}
2.while循环
#include <stdio.h>
int main () {
int age = 15;
/*
int i = 1 : 初始化语句
i < 6 : 判断条件语句
age += 3 : 循环体语句
i ++ : 控制条件语句
*/
int i = 1;
while(i < 6) {
age += 3;
i ++;
}
printf("第6个人%d岁.\n",age);
return 0;
}
3.do...while循环
#include <stdio.h>int main () {
int age = 15;
/*
int i = 1 : 初始化语句
age += 3 : 循环体语句
i ++ : 控制条件语句
i < 6 : 判断条件语句
*/
int i = 1;
do {
age += 3;
i ++;
}while(i < 6);
printf("第6个人%d岁.\n",age);
return 0;
}
4.递归函数
#include <stdio.h>// 递归函数
int age(int a) {
/* 判断条件语句 */
if(a == 1) {
return 15;
}
/* 这一句集中了循环体语句和控制条件语句 */
return 3 + age(a - 1);
}
int main () {
int count = 6;
/* 调用递归函数:函数名(初始化参数) */
int ageNumber = age(count);
printf("第6个人%d岁\n",ageNumber);
return 0;
}