函数与递归这边看大家有同学理解的不是很清晰,递归的时候参数传入也很不熟练,因此 lxl 又写了一波小小教程,希望对各位有帮助~~
首先函数定义是一组一起执行一个任务的语句。C 语言程序中至少有一个函数,就是主函数 main() 。对于其他的用户功能函数,都可以在 main() 函数前或后进行自定义,自定义函数的 声明 要包含有:函数的返回类型、名称、和形式参数,后部才是函数主体。
对于函数 返回类型,可以返回的类型包括任意参数、表达式等,但在参数 (无论形参还是实参) 返回之前必须被定义。
对于函数 名称,不可以和变量定义或已存在函数名称重复,C 语言中任意被引用头文件定义过的函数或任意定义变量都不允许相同。
对于函数 形式参数,形式参数就像函数内的其他局部变量,性质是 在进入函数时被创建,退出函数时被销毁。形式参数在函数定义句上定义,可以与实参或全局变量名称相同,但其作用域应用于函数块中。形参可选,即函数可以不定义形参。
对于函数 主体,可以使用形参、全局变量、或只属于函数块内部 static 关键字声明的变。static 关键字只在函数被调用的时候才可以使用,其余时无法访问。
函数块内语句展现函数功能,之后可以选择返回计算结果,使用 return 语句:
① 每次调用函数只能有一个 return 语句被执行,返回一个表达式数值。有判定条件下return 语句可以有多个,可以出现在函数体的任意位置。
② 函数一旦遇到 return 语句就立即返回,后面的所有语句都不会被执行。
③ 没有返回值的函数为空类型,用 void 表示。一旦函数的返回类型被定义为 void,就不不会有任何值被返回。
那么这样函数的介绍就讲述完成了,下面给一个函数参考 声明形式 :
return_type function_name( parameter list ){
……(function body) ……(function body)//函数主体 (return ());//return可选,return参数亦可选 }
return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void;function_name 是函数名称;parameter list 即形参定义位置,该部分可选;function body 即函数主体;return 部分可选,return 参数亦可选。
当程序调用函数时,程序控制权会转移给被调用的函数,被调用的函数执行已定义函数块内的语句。当函数的 return 语句被执行时,或者到达函数的结束括号时,会把程序控制权交还给主程序。
当调用函数时,有两种向函数传递参数的方式:
调用类型 | 描述 |
---|---|
传值调用 | 该方法把实参数值 复制 给函数的形参。修改函数块内形参不会影响实参。 |
引用调用 | 通过 指针传递 方式。形参为 指向实参地址的指针,关于形参的操作相当于对实参的操作。 |
一般调用函数时,使用传值调用(但对数值交换 swap 一类的自定义函数来讲,要使用引用调用)传递形参定义位置所需参数(如果没有就不需要),如果函数有返回值,则可用变量存储返回值。
递归最简单的话语讲解就是要用函数调用自身,但是这个调用自身的层数是有限制的,不然会爆栈。下面从程序运行的底层角度讲述递归调用的原理,有兴趣的你一定可以看懂的:
首先是 链接。每个程序都有头文件,这些头文件包含一系列的库函数,当我们链接程序时这些目标模块就会装配成一个完整的模块装入。每个模块都有自己的逻辑地址,链接完成后形成自己的从0开始的逻辑地址如图:
其次是 装载,load 入内存。程序一开始在磁盘上,需要装入内存才能运行。内存中低地址留给系统使用,高地址给用户区。将原地址直接装入内存,相对地址是不变的,结构如图:
计算机中的程序计数器 (Program Counter,PC) 部件来存放程序要执行的下一条指令。CPU 在 程序计数器 中取到下一条指令后就到内存中取这条指令,取到之后到 CPU 中解析执行。如此循环往复,程序得以执行。
函数 调用,即函数原本在主线上执行,遇到调用指令暂时到别的模块执行,执行结束后再回到主模块的过程。函数的调用指令指明了模块的首地址,执行过程先将指令传给 程序计数器(PC),此时中断了程序的顺序执行,指令之后的其他指令都被压入内存中的一块专门实现函数调用的 栈区,函数调用时入栈保护的不仅仅是指令地址,还有一些变量数据和局部变量,否则会丢失。当程序调用指令执行到 返回 指令时再出栈,将栈顶元素传给程序计数器(PC),程序因此回到了主模块。
递归的使用过程中,用来存放函数调用的 栈区 内存是有限的,如果递归太深,就会出现只入栈不出栈的情况,俗称 爆栈。通常程序运行后会 return 回来一个 几十亿大小的数字。程序中如果有递归,那么就要注意看自己的递归是否有问题了~
既然大家都已经会了,那么剩下的就是多多练习啦!下面展示一些代码供大家一起参考。
//E 龟速幂 Code Created by lxl #include #include int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } int get_phi(int n) {
int phi = n, i; for (i = 2; i * i <= n; i++) {
if (n % i == 0) {
while (n % i == 0) n /= i; phi -= phi / i; } } if (n > 1) phi -= phi / n; return phi; } int pow_mod(int a, int t, int p) {
int ans = 1; while (t--) ans = 1LL * ans * a % p; return ans; } int main() {
int n, i, a, t, p; scanf("%d", &n); while (n--) {
scanf("%d%d%d", &a, &t, &p); if (gcd(a, p) == 1) printf("Case #1: %d\n", pow_mod(a, (t % get_phi(p)) % p, p)); else if (t < get_phi(p)) printf("Case #2: %d\n", pow_mod(a, t, p) % p); else printf("Case #3: %d\n", pow_mod(a, (t % get_phi(p) + get_phi(p)) % p, p)); } return 0; }
//F AIR Is Recursive! Code Created by lxl #include int a, b, x; int air(int x) {
if (x <= a) return air(air(x + b + 1)); else return x - b; } int main() {
while (scanf("%d%d%d", &a, &b, &x) != EOF) {
printf("%d\n", air(x)); } return 0; }
//H 拆数字 Code Created by lxl #include #include void chai(int x) {
int i = 0; while (1) {
i++; if (pow(3, i) > x) break; } switch (x) {
case 0: return; case 1: printf("1"); break; case 2: printf("1+1"); break; case 3: printf("3"); break; case 4: printf("3+1"); break; case 5: printf("3+1+1"); break; case 6: printf("3+3"); break; case 7: printf("3+3+1"); break; case 8: printf("3+3+1+1"); break; default: {
printf("3("); chai(i - 1); if (x - pow(3, i - 1) != 0) {
printf(")+"); chai(x - pow(3, i - 1)); } else printf(")"); } } } int main() {
int n; scanf("%d", &n); chai(n); return 0; }
//I III Code Created by lxl #include int pos[9], cnt = 0; void Move(int x, int a, int b, int c) {
int i; for (i = x - 1; i > -1; i--) {
if (pos[i] == c) {
Move(i, c, a, b); } else if (pos[i] == a) {
Move(i, a, c, b); } } pos[x] = c; printf("%d:%d-->%d\n", x + 1, a, c); cnt++; } int main() {
int n, i, j; scanf("%d", &n); for (i = 0; i < n; i++) scanf("%d", &pos[i]); for (i = n - 1; i > -1; i--) {
if (pos[i] != 3) Move(i, pos[i], 3 - pos[i], 3); } printf("%d", cnt); return 0; }
到此本期教程就结束啦,各位有问题的话依然可以和老师或助教们联系,如果有帮助到你的话,不妨来个点赞转发加收藏
好啦,我们下期再见啦,lxl 爬去写 P2 了~~