函数概论
函数(function)是用于完成特定任务的程序代码的自包含单元。函数具有执行某些动作,或者返回一个值以供程序使用的功能。当然,一个函数可同时具备以上两种功能。我们建议在头文件里面放入一些其他重要的函数和变量,并在主函数里面引入。
一个简单的函数
#include<stdio.h> #define NUM 50 void starbar(void); int main(void) { starbar(); printf(" It's OK!"); system("pause"); return 0; } void starbar(void) { int i; for (i = 1; i <= NUM;i++) printf("*"); }
void starbar(void); 中starbar是函数名,第一个void是表示没有返回值,第二个void表示该函数不接受任何参数。分号表示进行函数的申明而不是函数的定义。
形式参量
void func(char ch, int num) 中定义了ch和num这两个参数,形式参量是局部变量,可以在其他函数中使用同一个变量名。
不过,ANSI C要求在每一个变量前申明其类型,不能如 void func(int x,y,z) 这样定义。
实际参数
如 func(x,y) 这样调用函数,但是x,y必须是明确的,可以是字符、数字甚至是一个复杂的表达式(必须先计算出表达式)。
黑盒子观点
函数里面所定义的变量都是其私有的局部变量,如果在main()中也有相同名字的变量,它们相互独立,互不影响。如果在main()中存在一个和所定义函数一样的变量,其不会影响到所定义的函数,其余变量也是如此。因此可以认为,黑盒子内的一切操作对调用函数来说都是不可见的。
return返回值
#include<stdio.h> int min_num(int num1, int num2); int main(void) { int num_1, num_2; printf("Please two integer: "); while ((scanf_s("%d %d", &num_1, &num_2)) == 2) { printf("The lessen of those numbers is %d ", min_num(num_1, num_2)); printf("Enter anthor integer(any single to quit) "); } printf("Bye! "); return 0; } int min_num(int num1, int num2) { int res_num; if (num1 < num2) res_num = num1; else res_num = num2; return res_num; }
在定义函数的开头就用int申明了函数返回的是int类型,就相当于把res_num赋予给了一个int类型的变量。当然,return不仅仅可以返回变量,也可以用 return 表达式 来返回。我们可以把代码改成如下形式:
int min_num(int num1, int num2) { return (num1 < num2) ? num1 : num2; }
return还有一个作用就是终止执行函数,并把控制返回给调用函数的下一个语句。因此,也可以这样改写代码:
int min_num(int num1, int num2) { if (num1 < num2) return num1; else return num2; }
函数类型与申明
函数应该进行类型申明,同时其类型应该和返回值类型相同,而无返回值的函数应该被申明为void类型。
为正确的使用函数,程序在首次调用函数之前需要知道该函数的类型。第一种途径就是在调用函数之前进行完整的函数定义,另一种途径就是在函数调用之前预先申明被调用函数的类型。
ANSI C的函数原型
ANSI C标准使用函数原型来申明返回值类型、参数个数以及各参数的类型。我们可以通过下面的任意一个进行申明:
int func(int,int); int func(int a,int b); //当然,其中的a和b可以不用和定义函数时所用的一样。
递归
#include<stdio.h> void up_and_down(int); int main(void) { up_and_down(1); system("pause"); return 0; } void up_and_down(int n) { printf("Level %d: n location %p ", n, &n); if (n < 4) { up_and_down(n + 1); printf("LEVEL %d: n location %p ", n, &n); } }
/*result:
Level 1: n location 012FF8E8
Level 2: n location 012FF810
Level 3: n location 012FF738
Level 4: n location 012FF660
LEVEL 3: n location 012FF738
LEVEL 2: n location 012FF810
LEVEL 1: n location 012FF8E8
*/
尾递归
就是把递归调用的语句放在函数结尾即恰在return语句之前,就称为尾递归或结尾递归。
#include<stdio.h> long fact(int n); long rfact(int n); int main(void) { int num; printf("Enter a number(0-12):"); while (scanf_s("%d", &num) == 1) { if (num < 0) printf("Sorry,I can't accpet a negative number!"); else if (num > 12) printf("Keep input under 12"); else { printf("Loop: %d factorial = %ld ", num, fact(num)); printf("Recursion: %d factorial = %ld ", num, rfact(num)); } printf("Enter a number(0-12):"); } printf("Bye!"); return 0; } long fact(int n) //循环方式 { long ans; for (ans = 1; n > 1; n--) ans *= n; return ans; } long rfact(int n) //递归方式 { long ans; if (n > 0) ans = n*rfact(n - 1); else ans = 1; return ans; }
斐波拉契数列
该数列采用双重递归。
long Fibonacci(int n) { if (n > 2) return Fibonacci(n - 1)*Fibonacci(n - 2); else return 1; }
地址运算符:&
当需要改变调用函数中的某个数值时,任何被调用的无返回值的C函数都需要使用地址参数来完成该任务。在C语言中,每个函数里面的变量都使用自己的地址。
一元运算符&
一元运算符&可以取得变量的存储地址。
int n = 12; printf("%d %p", n, &n);
/*
12 00DCFD6C
*/
指针简介
指针是一个其数值为地址的变量(或更一般地说是一个数据对象)。如果将某个指针变量命令为ptr,就可以使用 ptr=&pooh; 并称其为ptr“指向”pooh。
间接运算符
想要把指针命令为可以存放一个int数值的地址,就需要使用该新的运算符。
years = 10; ptr = &years; /*指向years的指针*/ val = *ptr; /*将ptr指向的值赋给val*/
申明指针
int *pi; //pi是指向一个整数变量类型的指针 char *pc; //pc是指向一个字符变量类型的指针 float *pf,*pg; //pf和pg是指向浮点变量类型的指针
pc等的值是一个地址,在大多数情况下,它由一个无符号整数表示。但是,这并不能表示可以把整数看成整数类型。一些处理数据的方法不能用来处理指针。