循环结构有两种类型:for 循环和 while 循环,可根据实际情况选用(do - while 语句较少见,故不作介绍)。下面以遍历数组和遍历链表为例,分别介绍两种循环结构的用法。
1.for 循环 的示例代码如下:
cpp复制代码
const int N = 100;
int main() {
int arr[N]; //初始化一个长度为100的int型数组
// ++操作符使得变量的数值+1
for (int i = 0; i < N; ++i) { // 遍历数组中的每个元素
if (i < 10) arr[i] = i * i; // 对前10个元素赋值
else if (i < 50) continue; // 跳出当前循环,进入下一轮循环
else break; // 结束循环,执行for循环之后的代码
}
return 0;
}
for 循环包括以下三个组成部分:
(1) for 关键字,指明这是一个 for 循环;
(2) 循环控制条件,即 for 之后由小括号包裹的部分。它又包括三个部分,由两个 ";" 分隔,从左到右依次是:
循环初始设置,对应上述代码中的 "int i = 0",只在首次循环时执行。它通常用来设置循环对应的下标的初始值,如设置 i 的初始值为 0,即数组的第一个下标。
进入循环的判断条件,对应上述代码中的 "i < N"。每次执行代码块之前,先求这个表达式的值,如果为 true,则进入循环,否则跳出循环。
循环代码块结束后的更新操作,对应上述代码中的 "++i"。每次执行完循环代码块后,执行更新操作,通常用来设置下一个循环的状态,例如上述代码更新了下标 i 的值。
int i = 0;
while (i < 10) { // i大于或等于10时结束循环
printf("%d\n", i); // 打印输出当前值的i值
++i;
}
while 循环的功能与 for 循环相同。区别在于,while 的循环控制条件仅包含进入循环的判断条件,而循环初始设置通常在 while 语句之前,循环更新操作包含在循环代码块内部。continue 和 break 也可以用于 while 循环。
1.5 函数
1.5.1 函数定义
函数是 C 语言的基本模块,通过对函数模块的调用实现特定的功能。如果把函数比喻成一台机器,那么函数的参数就是机器所需的原材料,函数的返回值就是机器最终产出的产品。在一定程度上,函数的作用就是根据不同的参数产生不同的返回值 (对于不含返回值的函数,函数的作用就是对数据进行相应处理)。假如一个程序的很多地方需要对数组进行遍历操作,而每次执行的又都是同样的代码,可以把这段代码封装为一个函数,并在每次使用时进行调用。
提示:C 语言程序的执行总是从 main 函数开始,最后也是由 main 函数来结束整个程序。
图 1.8 以具体例子说明了函数的基本语法格式。其中 addArray 函数的功能是:对长度为 n 的数组中的各元素进行求和:
// max函数返回a、b中较大的一个
int c = max(a, b); // 1.函数作为表达式中的一项
printf("%d", c); // 2.直接作为一个单独的语句使用(调用printf函数)
printf("%d", max(a, b));// 3.函数的返回值作为另一个函数的实参
注意:当函数作为表达式中的一项被调用,或者作为函数实参被调用时,要求函数有返回值,否则会报错。
函数还可以进行嵌套调用和递归调用,下面给出两者的定义和举例说明。
1.嵌套调用
嵌套调用是指在一个函数中调用另一个函数,调用方式与在 main 函数中调用其他函数是一致的。举例说明如下:
cpp复制代码
int max2(int a, int b) { // 返回两个整数中较大的一个
return (a > b? a : b); //?:操作符含义见下面提示部分的解释
}
int max4(int a, int b, int c, int d) { // 返回四个整数中最大的一个
int ans;
ans = max2(a, b); // 嵌套调用max2函数
ans = max2(ans, c);
ans = max2(ans, d);
return ans;
}
int main() {
int a, b, c, d, maxNum;
// 接收来自键盘的四个值并赋给a, b, c, d
scanf("%d %d %d %d", &a, &b, &c, &d);
maxNum = max4(a, b, c, d);
printf("%d", maxNum); // 打印输出a,b,c,d中的最大值
}
上述代码中的 main 函数调用了 max4 函数,即发生了函数嵌套调用。
提示:max2 函数的定义中用到了三目运算符:"<表达式 1>? < 表达式 2>: < 表达式 3>",它的意思是先求表达式 1 的值,如果为真,则执行表达式 2,并返回表达式 2 的结果;如果表达式 1 的值为假,则执行表达式 3,并返回表达式 3 的结果。举个例子:对于条件表达式 a? x : y,先判断条件 a 的真假,如果 a 的值为 true,那么返回表达式 x 的计算结果;否则,计算 y 的值,返回表达式 y 的计算结果。
以上述函数 F 为例,当 n 为 4 时,图 1.9 给出了 F 函数的具体执行流程,其中实线箭头表示 "递" 的步骤,虚线箭头表示 "归" 的过程。
如果需要求出斐波那契数列中第 n 个位置上的数,也可以采用迭代的方法,即在循环中参与运算的变量也是保存结果的变量,从某个值开始,不断地由上一步的结果计算 (或推导) 出下一步的结果。用迭代方式求解的代码如下:
cpp复制代码
// 迭代法求斐波那契数列中第n个位置上的数的值
int fib(int n) {
int first = 1, second = 1, cur = 0;
if (n <= 1) { return 1; }
for (int i = 2; i <= n; ++i) {
cur = first + second;
first = second;
second = cur;
}
return cur;
}
在 C 语言中,参数传递的方式只有值传递。而在考试中,偶尔也会有 C++ 中的引用传递的情况,因此在这里也顺带介绍 C++ 中的引用传递。
注意:初学者在学习 C 语言时,可能会发现 C 语言有值传值和传指针的说法,这种说法也是正确的,传值和传指针的本质都是值传递。C 语言在传指针时,也只是把指针的值(即地址)传入。
如果要设计一个 swap 函数,用于交换两个 int 型整数 c 和 d 的值,该如何设计呢?下面用 swap 函数的例子,分别介绍传值、传指针(传地址)和传引用。
1.传值
初学者可能会写出这样的代码:
cpp复制代码
void swap(int a, int b) {
int temp; // temp用于暂存a的值
temp = a; // 暂存a的值
a = b; // 把b的值赋给a
b = temp; // 把temp中暂存的a的值赋给b
}
但不幸的是,这样的函数并不能真正完成交换两个变量的值的功能。考虑这样一种情况,初始情况下变量 c 的值为 100,变量 d 的值为 200。当在 main 函数中调用此函数来交换变量 c 和变量 d 的值时,会在函数内部重新创建两个变量 a 和 b 用于存储实参传递过来的值,这两个函数内部的变量只是外部实参的一个拷贝,而后的操作都是对这两个拷贝的操作,并不会影响到外部的实参。
2.传指针 (传地址)
传指针(传地址)指的是在参数传递时传递的不是欲交换的数值,而是其地址。在 swap 函数中,形参为两个指针变量 a 和 b,当函数被调用时,传递给形参 a 和 b 的值为实参 c 和 d 的地址,于是,a 和 b 就变成了分别指向 c 和 d 的指针变量。通过对指针变量执行解引用操作(如 * a),就可以直接影响到指针指向变量的值,这就是在传地址方式中调用函数对实参进行操作的本质所在。