7022 字
35 分钟
C语言考查笔记
NOTE考查目标:
- 掌握 C 语言程序结构
- 掌握 C 语言的基本数据类型及数据运算
- 掌握基本语句的使用
- 掌握选择结构编程
- 掌握循环结构编程
- 掌握数组存储与处理批量数据.
- 了解模块化程序设计思想, 学会使用函数进行简单编程.
1、C 语言程序的结构
1.1 程序的构成, main 函数和其他函数
- 程序的构成: 一个 C 语言源程序由一个或多个源文件组成. 每个源文件可以由一个或多个函数组成.
- 主函数 (
main函数): 一个源程序有且只能有一个main函数, 它是主函数. 程序执行从main开始, 并在main中结束. - 函数组成: 函数由两部分组成: 声明 (Declaration) 和定义 (Definition, 即函数体, 要执行的代码).
示例代码: main 函数结构
# include <stdio.h> // 预处理命令, 载入头文件int main() // 主函数
{ printf("Hello World!"); // 标准输出 return 0;}1.2 头文件, 数据说明, 程序注释
- 头文件: 预处理命令 (以
#开头) 通常应放在源文件或源程序的最前面.- 例如, 使用
#include <stdio.h>来获取标准输入输出函数. - 系统库中的头文件使用尖括号
< >引用; 本地目录中的头文件使用双引号""引用.
- 例如, 使用
- 数据说明(变量定义):
- 变量在使用前必须声明. 声明方式为
类型标识符 变量名列表;. - 可以在声明时同时初始化变量.
- 变量在使用前必须声明. 声明方式为
- 程序注释:
- 单行注释: 使用
//. - 多行注释(段注释符): 使用
/* ... */. - 注意事项: 多行注释不能嵌套, 否则会导致编译错误.
- 单行注释: 使用
示例代码: 变量定义与注释
#include <stdio.h> // 包含头文件
// 这是一个单行注释/*多行注释:用于注释跨多行的内容*/
const int MAX_LENGTH = 100; // 符号常量声明
int main(){ int myNum = 15; // 定义并初始化变量 myNum float myFloatNum; // 声明变量 myFloatNum = 5.99; // 初始化变量
return 0;}1.3 源程序的书写格式
- 语句结束符: 每条语句以分号
;结尾. 但预处理命令、函数头和右花括号}之后不需要加分号 (结构除外). - 大小写: C 语言区分大小写.
- 书写规范: 常用锯齿形书写格式. 建议花括号
{}对齐, 一行写一个语句, 使用 TAB 缩进, 有合适的空行, 以提升程序可读性.
2、数据类型及其运算
2.1 C 语言的基本数据类型及定义方法
C 语言的数据类型可分为基本数据类型和派生 (扩展) 数据类型.
- 基本数据类型:
- 整型:
int,short,long.int: 整型, 4 个字节 (32 位), 范围约为 -2,147,483,648 到 2,147,483,647.short: 短整型, 2 个字节 (16 位), 范围约为 -32,768 到 32,767.long: 长整型, 4 个字节 (32 位), 范围约为 -2,147,483,648 到 2,147,483,647.
- 实型(浮点型):
float(单精度浮点型),double(双精度浮点型),long double.float: 4 个字节 (32 位), 精度约为 7 位十进制数.double: 8 个字节 (64 位), 精度约为 15-16 位十进制数.long double: 10、12 或 16 个字节, 具体取决于编译器, 精度更高.
- 字符型:
char.char: 1 个字节 (8 位), 用于存储字符 (如字母、数字、标点符号等).- 字符型变量可以直接赋值字符常量 (如
'A','1','!'), 也可以赋值对应的 ASCII 码值 (如65,49,33).
- 布尔型:
_Bool(0表示false,1表示true)._Bool类型占用 1 个字节 (8 位), 只能存储0或1.- 布尔型变量通常用于条件判断和循环控制.
- 整型:
- 派生/扩展类型: 数组、指针、枚举 (
enum), 结构 (struct), 联合 (union) 等. - 字符串: 不是一种独立的数据类型, 通过字符数组或字符指针来实现. 以 \0 (空字符) 为结束标志.
示例代码: 基本数据类型定义
// 定义并初始化整数变量int myNum = 5;// 定义并初始化浮点数变量float myFloatNum = 5.99;// 定义并初始化字符变量char myLetter = 'D';// 定义双精度浮点数double myDouble = 3.2325467;// 定义布尔型变量_Bool myBool = 1;// 定义并初始化字符串变量char myString[] = "Hello World!";// 定义并初始化字符数组变量char myCharArray[] = {'H', 'e', 'l', 'l', 'o', '\0'};// 定义并初始化指针变量char *myPointer = "Hello World!";2.2 C 语言运算符的种类、运算优先级和结合性
C 语言运算符的种类包括:
- 算术运算符:
+(加),-(减),*(乘),/(除),%(取模),++(增量),--(乘量/减量). - 赋值运算符:
=(赋值),+=,-=,*=,/=,%=等. (a += b → a = a + b)- 自增运算符前置与后置的区别:
++和--运算符放在变量前面 (如++i,--i) 称为前置, 先进行自增/自减操作, 再使用变量的值++和--运算符放在变量后面 (如i++,i--) 称为后置, 先使用变量的当前值, 再进行自增/自减操作
- 关系运算符(比较运算符):
==(等于),!=(不等于),>(大于),<(小于),>=(大于或等于),<=(小于或等于). - 逻辑运算符:
&&(逻辑与),||(逻辑或),!(逻辑非). 优先级为!优于&&优于||. - 条件运算符:
? :, 是 C 语言中唯一的三目运算符. - 位运算符:
&(按位与),|(按位或),^(异或),~(取反),<<(左移),>>(右移). - 指针运算符:
*(取内容/解引用),&(取地址). - 求字节数运算符:
sizeof.
示例代码: 重要运算符的使用
// 算术运算符和前置/后置int a = 5, b = 3;int sum = a + b; // 加法
// 前置和后置自增int x = 10;int y = ++x; // x 先自增为 11, 然后赋值给 y, y = 11int z = x++; // x 的当前值 11 赋值给 z, 然后 x 自增为 12, z = 11
// 关系运算符int result1 = (a > b); // result1 = 1 (true)int result2 = (a == b); // result2 = 0 (false)
// 逻辑运算符// 可以对表达式、单个数字或变量进行逻辑运算int result3 = (a > 0 && b < 10); // result3 = 1 (true)int result4 = (a < 0 || b > 10); // result4 = 0 (false)int result5 = !(a == b); // result5 = 1 (true)int result6 = !a || b; // result6 = 1 (true)
// 条件运算符int max = (a > b) ? a : b; // 条件为真返回 a, max = 5
// 位运算符int bitwise_and = a & b; // 按位与: 对应位都为 1 时结果为 1, 否则为 0, 这里 5 & 3 = 1 (二进制: 101 & 011 = 001)int bitwise_or = a | b; // 按位或: 对应位有一个为 1 时结果为 1, 否则为 0, 这里 5 | 3 = 7 (二进制: 101 | 011 = 111)int left_shift = a << 1; // 左移 1 位: 相当于乘以 2, 例如 5 << 1 = 10 (二进制: 101 << 1 = 1010)
// 指针运算符int *ptr = &a; // ptr 是一个指针变量, 它存储了变量 a 的内存地址int value = *ptr; // 通过指针获取 a 的值, value = 5
// sizeof 运算符int size = sizeof(int); // size = 42.3 不同类型数据间的转换与运算
- 自动转换(隐式转换):
- 不同类型的数据进行运算时, 需要先转换成同一数据类型, 然后再进行运算.
- 转换按数据长度增加的方向进行, 以尽可能保证精度不降低.
- 例:
char型数据和short型数据进行运算时, 需转换成int型. - 转换方向示例 (部分):
char --> short --> int --> unsigned --> long --> unsigned long --> double <-- float. - 浮点型转整型: 直接丢掉小数部分.
- 强制转换(显式转换):
- 语法:
(类型标识符)表达式. - 类型转换是临时性的, 不会改变变量本身的数据类型.
- 运算过程中, 自动类型提升: 低精度数据类型向高精度数据类型转换.
- 语法:
示例代码: 类型转换
int a = 2, b = 5;double x, y, z;
x = b / a; // 隐式转换: b/a 先进行整型除法 (2), 然后赋值给 double 型 x, x = 2.0y = (double)b / a; // 强制转换: 先将 b 转化为 double 型 (5.0), 然后进行浮点数除法, y = 2.5z = (double)(b / a); // 强制转换: 先计算整型除法 (2), 然后将结果 2 转化为 double 型, z = 2.02.4 C 语言表达式类型和求值规则
- 赋值表达式: 将右侧的值赋给左侧的变量, 例如
x = 5. 赋值号具有结合性, 如x=y=3等价于y=3; x=y;. - 算术表达式: 使用算术运算符连接常量和变量, 例如
sum = x + y. - 关系表达式: 使用关系运算符进行比较, 返回 1 (真) 或 0 (假).
- 逻辑表达式: 使用逻辑运算符连接表达式.
- 短路求值: 对于
&&, 如果左侧为假, 则不再计算右侧; 对于||, 如果左侧为真, 则不再计算右侧.
- 短路求值: 对于
- 条件表达式(三元运算符):
- 语法:
(条件表达式) ? 表达式1 : 表达式2. - 求值规则: 如果条件表达式为真, 返回表达式 1 的值, 否则返回表达式 2 的值.
- 语法:
- 逗号表达式:
- 语法:
表达式1, 表达式2. - 求值规则: 先计算表达式 1, 再计算表达式 2, 并将表达式 2 的值作为整个表达式的结果.
- 语法:
示例代码: 条件表达式(三元运算符)
int time = 20;
int main() { (time < 18) ? printf("再会!") : printf("晚上好!"); // 输出 -> "晚上好!" return 0;}示例代码: 逗号表达式
int a = 2, b;
int main() { a = 3 * 5, a + 10; // a=15, 整个表达式结果是 15+10=25, 但后面的 a+10 未赋值, 丢弃 b = (3 * 5, a + 10); // 使用括号, 3*5=15 (未赋值, 丢弃), 然后 a+10=25, b=25 printf("a = %d, b = %d\n", a, b); return 0;}3、基本语句
3.1 表达式语句, 空语句, 复合语句
- 表达式语句: 由表达式 (如赋值表达式、函数调用) 后跟分号组成.
- 空语句: 只有分号
;. - 复合语句: 将多个语句用花括号
{}括起来组成的一个语句. 通常用于if,for,while等结构中, 作为循环体或条件体.
3.2 输入输出函数的调用, 正确输入数据并正确设计输出格式
- 输出函数的调用: 使用
printf().- 语法:
printf("格式控制字符串", 输出变量列表);.
- 语法:
- 输入函数的调用: 使用
scanf().- 语法:
scanf("格式控制字符串", 输入变量地址列表);. 注意最后一个参数是变量的地址列表.
- 语法:
- 格式说明符 (作用): 充当变量输出时的占位符, 用于指定变量的输出格式.
%d或%i:int整数 (10 进制).%u: 无符号十进制整数%f:float浮点数 (小数形式).%.2f: 浮点数保留2位小数%lf:double高精度浮点数据.%c:char字符.%s: 字符串.%.5s: 字符串最多输出5个字符
- 输出格式设计(宽度控制):
- 使用
%md或%-md控制输出宽度m.%md: 最少占m个字符宽度, 默认右对齐.%-md: 最少占m个字符宽度, 左对齐.
- 使用
示例代码: 输入输出及格式控制
#include <stdio.h>
int main(){ int myNum; float f = 5.99;
// 输出 printf("Number = %d\n", (int)f); // 输出整数, 5 printf("Value = %.2f\n", f); // 输出浮点数, 保留两位小数, 5.99
// 输出格式控制(左对齐, 宽度为 9) int a1 = 20; printf("%-9d\n", a1); // 输出 20, 左对齐, 宽度为 9
// 输入 printf("请输入一个数字: \n"); scanf("%d", &myNum); // 获取并保存用户输入的号码, 需要使用 & 引用运算符 printf("您输入的数字: %d\n", myNum);
return 0;}4、选择结构程序设计
4.1 用 if 语句实现选择结构
- if 语句: 用于根据条件执行代码块.
- if…else 语句: 在
if条件不满足时执行else代码块. - else if 语句: 用于检查多个条件.
示例代码: if-else if-else 结构
int time = 22;if (time < 10) { printf("早上好!");} else if (time < 20) { printf("再会!");} else { printf("晚上好!"); // 输出 -> "晚上好!"}4.2 用 switch 语句实现多分支选择结构
- switch 语句: 根据表达式的值跳转到匹配的
case标签. - 表达式类型:
switch表达式可以是整型、字符型和枚举型. break语句: 匹配到case后执行相应代码, 并通过break跳出switch.default语句: 如果没有匹配到任何case, 则执行default语句 (如果存在).default不是必需的.- 贯穿现象: 如果没有
break, 程序会继续执行下一个case的代码.
示例代码: switch 结构
int day = 4;switch (day) { case 3: printf("周三"); break; case 4: printf("周四"); // 匹配到 case 4 break; // 跳出 switch default: printf("期待周末");}// 输出 -> "周四"4.3 选择结构的嵌套
if语句可以嵌套.- 嵌套时, 每一层
if都要和else配套, 若没有else, 则需要将该层if语句用{}括起来.
示例代码: if 嵌套
int time = 10;if (time > 8) { // 嵌套一个 if if (time < 12) { printf("中午好!"); // 输出 -> "中午好!" }}5、循环结构程序设计
5.1 for 循环结构
for循环结构包含三个表达式: 初始化语句 (表达式 1, 只执行一次), 循环条件表达式 (表达式 2, 每次循环前检查), 调整操作 (表达式 3, 循环体执行后执行).- 当条件表达式 (表达式 2) 为假时,
for循环结束. - 三个表达式都不是必须的, 但分号不能省略. 如果表达式 2 为空, 则表示无限循环.
示例代码: for 循环
int i;for (i = 0; i < 5; i++) { // i=0 (初始化), i<5 (循环条件), i++ (调整操作) printf("%d\n", i);}// 输出 -> 0 1 2 3 4
// 省略表达式1(初始化在外部进行)int i = 0;for (; i < 5; i++) { printf("%d\n", i);}
// 省略表达式3(调整操作在循环体内进行)for (i = 0; i < 5;) { printf("%d\n", i); i++;}
// 省略表达式2(无限循环)for (i = 0; ; i++) { if (i >= 5) break; // 需要用break来跳出循环 printf("%d\n", i);}
// 三个都省略(必须有办法跳出循环)for (;;) { printf("无限循环"); break; // 必须有退出条件}5.2 while 和 do-while 循环结构
| 特征 | while 循环 | do-while 循环 |
|---|---|---|
| 控制类型 | 入口控制循环 (Entry-Controlled) | 出口控制循环 (Exit-Controlled) |
| 条件检查 | 在循环体执行前检查 | 在循环体执行后检查 |
| 执行保证 | 可能执行 0 次或多次 | 至少执行 1 次 |
| 语法结尾 | } 后无分号 | while(条件) 后有分号 |
示例代码: while 循环
int i = 0;while (i < 5) { printf("%d\n", i); // 初始条件为假时,循环体不执行 i++;}// 输出 -> 0 1 2 3 4示例代码: do-while 循环
int i = 0;do { printf("%d\n", i); i++;} while (i < 5); // ← 注意:分号不能省略,这是必须的// 输出 -> 0 1 2 3 45.3 continue 语句和 break 语句
break语句: 跳出当前循环或switch语句, 执行后续代码.continue语句: 跳过当前循环的剩余语句, 直接进入下一次循环.- 通常与
if语句配合使用.
示例代码: break 语句
int i;for (i = 0; i < 10; i++) { if (i == 4) { break; // 当 i=4 时跳出循环 } printf("%d\n", i);}// 输出 -> 0 1 2 3示例代码: continue 语句
int i;for (i = 0; i < 10; i++) { if (i == 4) { continue; // 当 i=4 时跳过本次循环的剩余部分 (即跳过 printf) } printf("%d\n", i);}// 输出 -> 0 1 2 3 5 6 7 8 95.4 循环的嵌套
- 循环可以嵌套.
- 嵌套循环的核心在于执行顺序, 外部循环每执行一次, 内部循环都要完整地执行完所有轮次.
- 总的循环体执行次数是: 外循环次数 × 内循环次数.
示例代码: 循环嵌套 (遍历二维数组)
int N = 5;// 假设 A 是一个 N x N 的二维数组, 外部循环控制行, 内部循环控制列for(int i = 0; i < N; i++){ for(int j = 0; j < N; j++) { printf("%d ", A[i][j]); // 循环体语句, 访问 A[i][j] }}示例代码: 循环嵌套 (九九乘法表)
for (int i = 1; i <= 9; i++) { // 外层循环控制行 for (int j = 1; j <= i; j++) { // 内层循环控制列 printf("%d*%d=%-2d ", j, i, i*j); // %-2d 表示左对齐,占两个宽度 } printf("");}6、数组的定义和引用
6.1 一维数组的定义、初始化和数组元素的引用
- 定义: 一维数组的声明格式为
类型标识符 数组名[n], 其中n是一个正整数常量, 表示数组的长度. (声明时指定长度不可省略, 但初始化时可省略长度由编译器自动推断.) - 引用: 通过
数组名[k]引用数组元素, 下标k的合法取值范围是从0到n-1. - 初始化: 可以在声明时同时赋初值.
- 当在定义时对所有元素都进行初始化时, 可以省略数组长度
[n], 编译器会根据初始化列表的元素个数自动确定数组长度. - 可以只初始化部分元素, 未被初始化的元素将被自动赋值为 0.
- 当在定义时对所有元素都进行初始化时, 可以省略数组长度
示例代码: 一维数组的定义和引用
#include <stdio.h>
int main() { // 定义并完全初始化 int nums1[] = {10, 20, 30, 40}; // 自动推断长度为4
// 定义固定长度数组(部分初始化) int nums2[5] = {1, 2}; // [1,2,0,0,0]
// 访问元素 printf("第一个元素: %d\n", nums1[0]); // 输出: 10 // 修改元素 nums1[0] = 100; printf("修改后: %d\n", nums1[0]); // 输出: 100
// 遍历数组(需获取长度) int length = sizeof(nums1) / sizeof(nums1[0]); printf("数组长度: %d\n", length); // 输出: 4
printf("遍历数组:"); for(int i = 0; i < length; i++) { printf(" %d", nums1[i]); // 输出: 100 20 30 40 }
return 0;}6.2 二维数组的定义、初始化和数组元素的引用
- 定义: 二维数组声明格式为
类型标识符 变量名[m][n], 声明一个 行 列的二维数组. - 引用: 通过
变量名[i][j]引用元素, 其中 为行下标 (0 到 ), 为列下标 (0 到 ). - 存储: 二维数组是按行顺序连续存储的. (一行一行)
- 初始化: 可以分组初始化, 也可以省略第一维 (行) 的大小 (但不能省略其他维数, 如列数).
示例代码: 二维数组的定义和引用
#include <stdio.h>
int main() { // 1. 定义并初始化二维数组(2行3列) int matrix[2][3] = { // 2. int matrix2[][3] 省略行数, 自动推断为2行 {1, 3, 5}, // 第一行 {2, 6, 10} // 第二行 };
// 3. 连续初始化方式 int matrix3[2][3] = {1, 2, 3, 4, 5, 6}; // 等价于{{1,2,3},{4,5,6}}
// 4. 访问元素:获取第二行第一列的元素(值为2) printf("matrix[1][0] = %d\n", matrix[1][0]); // 输出: 2
// 5. 修改元素:将第一行第二列的元素改为100 matrix[0][1] = 100; printf("修改后: matrix[0][1] = %d\n", matrix[0][1]); // 输出: 100
// 6. 遍历二维数组 int rows = sizeof(matrix) / sizeof(matrix[0]); // 计算行数 int cols = sizeof(matrix[0]) / sizeof(matrix[0][0]); // 计算列数
printf("遍历matrix数组:"); for(int i = 0; i < rows; i++) { for(int j = 0; j < cols; j++) { printf("%d\t", matrix[i][j]); // 使用制表符对齐 } printf(""); // 每行结束后换行 } /* 输出: 1 100 5 2 6 10 */
return 0;}6.3 字符串与字符数组
- 字符串本质: 在 C 语言中, 字符串是以
\0结尾的字符数组, 而不是一种单独的数据类型.\0是字符串结束标志符. - 定义: 可以通过字符数组来表示字符串.
示例代码: 字符串定义和引用
// 单引号定义并初始化字符char c = 'a';printf("%c\n", c); // 输出 'a'
// 双引号定义并初始化字符串 (会自动添加 \0)char greetings[] = "Hello World!";printf("%s\n", greetings);
// 字符数组初始化 (手动添加, 显式包含 \0)char greetings2[] = {'H', 'e', 'l', 'l', '\0'};printf("%s\n", greetings2); // 输出 "Hell"
// 访问/修改字符串中的字符char greetings3[] = "Hello";printf("%c\n", greetings3[0]); // 访问第一个字符 'H'greetings3[0] = 'J'; // 修改第一个字符为 'J'printf("%s\n", greetings3); // 输出 "Jello"6.4 使用一维数组解决批量数据查找或排序等问题
-
一维数组常用于批量数据的查找和排序
-
若数组无序, 采用顺序查找 ( 从头到尾依次比较 )
-
若数组有序, 采用折半查找 ( 二分查找 ), 效率更高
示例代码: 顺序查找
// a 为数组, n 为长度, num 为待查找元素int found = 0; // 标志变量, 是否找到for (int i = 0; i < n; i++) { // 从头到尾遍历数组if (a[i] == num) { // 如果找到found = 1;break; // 跳出循环}}// found==1 表示找到, 否则未找到示例代码: 折半查找 ( 数组有序 )
// a 为有序数组, n 为长度, num 为待查找元素int low = 0, high = n - 1, found = 0; // 初始化区间和标志while (low <= high) { // 只要区间不为空int mid = (low + high) / 2; // 取中间下标if (a[mid] == num) { // 找到found = 1;break;}else if (num > a[mid])low = mid + 1; // 在右半区间查找elsehigh = mid - 1; // 在左半区间查找}// found==1 表示找到, 否则未找到 -
排序常用选择排序、冒泡排序、插入排序, 都是基础算法, 适合小规模数据
-
三者核心思想都是通过循环比较和交换, 逐步将数组变为有序
示例代码: 选择排序:
// a 为数组, n 为长度for (int i = 0; i < n - 1; i++) { // 外层循环, 控制趟数for (int j = i + 1; j < n; j++) { // 内层循环, 找最小值if (a[j] < a[i]) { // 如果有更小的值int t = a[j]; a[j] = a[i]; a[i] = t; // 交换元素}}}// 排序后数组 a 升序排列示例代码: 冒泡排序:
// a 为数组, n 为长度for (int i = 0; i < n - 1; i++) { // 外层循环, 控制趟数for (int j = 0; j < n - 1 - i; j++) { // 内层循环, 相邻元素比较if (a[j] > a[j + 1]) { // 如果前面的比后面大int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t; // 交换元素}}}// 排序后数组 a 升序排列示例代码: 插入排序:
// a 为数组, n 为长度for (int i = 1; i < n; i++) { // 从第二个元素开始int k = a[i]; // 待插入元素int j = i - 1; // 比较的元素下标while (j >= 0 && k < a[j]) { // 向前查找插入位置a[j + 1] = a[j]; // 后移j--; // 继续向前比较}a[j + 1] = k; // 插入到合适位置}// 排序后数组 a 升序排列
7、函数定义与调用
7.1 库函数的正确调用
- C 语言的系统库中提供了几百个函数可供程序员直接使用.
- 使用库函数时, 要包含相应的头文件. 例如:
<stdio.h>:printf()(格式化输出),scanf()(格式化输入) .<math.h>:sqrt()(平方根),pow()(幂运算),fabs()(绝对值) .<stdlib.h>:rand()(伪随机整数),srand()(设置种子) .<string.h>:strlen()(字符串长度),strcpy()(字符串复制) .<time.h>:time()(获取当前时间),clock()(获取处理器时间) .
示例代码: 调用库函数
#include <stdio.h>#include <math.h> // 需要包含 math.h 头文件
int main(){ // 调用库函数 sqrt (平方根) printf("%f", sqrt(16)); // 输出 4.000000 return 0;}7.2 用户自定义函数的定义、类型与返回值
- 函数定义: 由函数头和函数体组成.
- 函数头:
类型标识符 函数名(形式参数列表). - 函数体: 包含要执行的代码.
- 函数头:
- 函数类型与返回值:
- 函数的类型 (即返回值的类型) 由函数头前的“类型标识符”指明.
- 若没有返回值, 则使用
void. - 函数返回值通过
return语句给出. 若函数无返回值, 可以不写return.
示例代码: 自定义函数定义与返回值
// 函数定义: 返回 int 类型, 接受两个 int 参数int myFunction(int x, int y){ return x + y; // 返回 x 和 y 的和}
// 无返回值函数定义 (使用 void)void greetUser(char name[]){ printf("Hello %s\n", name);}7.3 函数的正确调用、参数的值传递
- 函数调用: 语法为
函数名(实际参数列表). - 值传递: 将实参的值传递给对应的形参.
- 形参是局部变量, 在函数被调用时分配存储单元, 调用结束即被释放.
- 对形参的任何改变都不会对实参产生任何影响 (单向传递).
- 地址传递(数组): 将整个数组传递给被调函数时, 传递的是数组的首地址.
- 在函数中对形参数组的任何修改都会影响到实参数组.
示例代码: 函数调用与值传递
// 假设 myFunction 已定义为 int myFunction(int x, int y) { return x + y; }int main(){ // 调用函数并将结果打印 printf("结果: %d", myFunction(5, 3)); // 传递 5 和 3 的值作为实参
int result = myFunction(5, 3); // 将结果存储在变量中
return 0;}7.4 函数的嵌套调用、递归调用
- 嵌套调用: 函数可以嵌套调用, 但不能嵌套定义.
- 递归调用: 函数可以直接或间接调用自己.
示例代码: 嵌套调用(简单加法)
#include <stdio.h>
int add(int a, int b);
int main(){ printf("结果: %d", add(add(1, 2), 3)); // 嵌套调用 add 函数 return 0;}
int add(int a, int b){ return a + b;}示例代码: 递归调用(简单递归求和)
#include <stdio.h>
int sum(int n);
int main(){ printf("结果: %d", sum(5)); // 计算 1+2+3+4+5 return 0;}
int sum(int n){ if (n == 0) { return 0; // 基础情况 } else { return n + sum(n - 1); // 递归调用自身 }}7.5 局部变量与全局变量
- 局部变量: 在函数 (如形参和函数中定义的变量) 或语句块 (如循环体内定义的变量) 内有效 (可见).
- 形式参数 (形参): 在函数定义时列出的参数, 它们本质上是局部变量, 仅在函数体内有效. 例如
void fun(int k)中的k. - 实际参数 (实参): 在函数调用时传入的值或表达式, 例如
fun(i)中的i, 实参可以是局部变量、全局变量、常量/表达式. - 全局变量: 在所有函数外定义, 其作用域为整个程序; 在它后面定义的函数中均可使用.
- 同名变量的屏蔽: 若局部变量与全局变量同名, 则优先使用局部变量 (屏蔽全局变量) .
- 外部变量声明: 若要在其他文件中使用未定义的全局变量, 则需声明其为外部变量, 使用
extern 数据类型名 变量名.
示例代码: 局部变量与全局变量
#include <stdio.h>
int k_global = 2; // 全局变量
int main(){ int i = 5; // 局部变量 int x; x = i + k_global; printf("x=%d\n", x); // 使用全局变量 k_global, x = 7
{ int k_global = 16; // 语句块内的局部变量 (与全局变量同名) x = i + k_global; printf("x=%d\n", x); // 优先使用局部变量, x = 5 + 16 = 21 }
x = i + k_global; printf("x=%d\n", x); // 语句块结束后, 恢复使用全局变量 k_global, x = 7
return 0;}示例代码: 形参 (局部) 与实参的来源
// fun 的 k 是形参(局部变量)void fun(int k) { printf("fun received %d\n", k);}
int main() { int i = 5; // main 内部的局部变量 fun(i); // i 作为实参传入 fun(10); // 常量 10 作为实参传入 return 0;}示例代码: 外部变量声明
// 示例:// file1int globalVar = 10; // 定义全局变量
// file2#include <stdio.h>
extern int globalVar; // 声明外部变量void printGlobalVar() { printf("%d\n", globalVar);}