函数
一、初见函数
//素数
int isPrime(int i)
{
int ret = 1;
int k;
for ( k = 2 ; k < i - 1 ; k++){
if (i % k == 0){
ret = 0;
break;
}
}
return ret;
}
- 代码复制是程序质量不良的表现
//求和
void sum(int begin, int end)
{
int i;
int sum = 0;
for ( i = begin ; i <= end ; i++){
sum += i;
}
printf("%d到%d的和是%d\n",begin, end, sum);
}
int main(){
sum(1,10);
sum(20,30);
sum(35,45);
return 0;
}
- 函数的定义和调用
-
定义:函数是一块代码,接受零个或多个参数,做一件事情,并返回零个或一个值
-
调用函数:
- 语句形式:
max(a,b)
- 表达式形式:
c = max(a,b)*2
- 函数参数:
c = max(a,max(b,d))
- 语句形式:
- 函数中的返回值
- 可以赋值给变量
- 可以再次传递给函数
- 如果没有return语句,由最后一个“}”返回一个不确定的值
- 返回值的类型与函数的类型一致,如不一致,以函数类型为准
- 没有返回值的函数(如下的代码)
- void
- 不能使用带值的return
- 可以没有return
- 调用时不能做返回值的赋值
//求和
void/*返回类型*/ sum(int begin, int end)/*函数名*/ //函数头
{
int i;
int sum = 0;
for ( i = begin ; i <= end ; i++){
sum += i;
}
printf("%d到%d的和是%d\n",begin, end, sum);
} //函数体
int main(){
sum(1,10);
sum(20,30);
sum(35,45);
return 0;
}
二、函数
- 函数原型
-
函数的先后关系
- C的编译器逐行分析代码
- 可以先声明(以;结尾)后定义(无;)
-
参数传递
-
C语言在调用函数时,永远只能传值给函数
- 每个函数有自己的变量空间,与其他函数无关
-
每一次的运行都无关
-
内联函数
- 适用于1-5句的小函数;
-
不能使用循环及switch,否则被译为一般函数
-
函数的重载
-
同名函数通过不同参数、类型、顺序、个数,实现同名不同功能函数的调用
- 如各种多边形面积的运算
-
本地变量的规则
-
本地变量是定义在块内的
- 可以是定义在函数块里
- 可以是定义在语句块里
- 甚至是任意的大括号
- 在块外,这个变量不存在
- 离开块后,这个变量不存在
- 快外定义的变量在块内有效
- 块内的变量掩盖块外的同名变量
- 同一个块中不能出现同名变量
-
本地变量不会被默认初始化
-
void
-
参数未知,但不是没有
-
函数内没有参数时可用
-
逗号运算符
-
调用函数时首个圆括号内的逗号是标点符号
-
若要用都好运算符,则再加一个括号
-
main 函数
三、变量的四种存储类型
-
局部变量
-
定义在复合语句开始处
- 块内生存,块内有效
- 与全局变量冲突时,局部变量优先
-
寄存器类型(register)
-
作用域与前者相同,但若CPU内部的寄存器空闲,则使用寄存器作为变量的存储单元可以提高程序运行速度
-
静态类型
-
作用域:在说明的复合语句内引用,出了复合语句不可用
-
生存期:从程序开始到程序结束
-
外部类型
-
定义在任何模块之外的变量,也称为全局变量
- 作用域:从说明变量开始到程序结束
- 生存期:在程序的整个执行过程中,任何函数对外部变量的修改都会影响全局变量的值
- 注:不能用作函数参数
- 可以通过extern来改变其作用域
四、函数间的数据传递
- 函数见数据传递方式
- 通过函数参数传值或传地址
- 传值:形参与实参
- 传地址:形参定义为指针,实参为变量的地址
- 通过返回值传递结果
- 函数参数为引用
- 通过全局变量传递参数或结果
五、数组与函数参数
- 数组作为函数参数定义的三种方式
- 形参作为指针:
int ave(int *p);
- 形参为无下表数组:
int ave(int p[])
; - 形参为有下标数组:
int ave(int p[10]);
六、返回指针的函数
- 概念:函数结束时候返回一个地址
- 注意:定义函数时候要加上“ * ”(返回值的类型与函数类型一致)
七、指向函数的指针
-
函数在内存中的首地址为函数的入口地址
-
使用过程
-
定义函数和指向函数的指针:
int (*p)(int, int);
- 指针指向函数:
p = Max; //max是函数名
-
通过指针引用函数:
maxval = (*p)(x,y);
-
示例:
#include <iostream>
using namespace std;
int Imax(int, int);
int main(){
int a,b,c;
int(*funp)(int, int);
funp = Imax;
cin >> a >> b;
c = (*funp)(a,b);
cout << "The max is :" << c;
return 0;
}
int Imax(int x, int y){
return (x>y?x:y);
}
#include <iostream>
using namespace std;
int Add(int,int);
int Sub(int,int);
int funa(int, int, int(*)(int,int));
int main(){
int a,b,c;
cin >> a >> b;
c = funa(a, b, Add);
cout << c;
c = funa(a, b, Sub);
cout << c;
return 0;
}
int funa(int a, int b, int(*fun)(int,int)){
return (*fun)(a,b);
}
int Add(int a,int b){
return (a + b);
}
int Sub(int a, int b){
return (a - b);
}
八、递归函数
- 概念:函数直接或间接地自我调用称为递归函数
- 通过控制条件,使递归终止
#include <iostream>
using namespace std;
long ifac(long);
int main(void){
long i, x;
cin >> i;
x = ifac(i);
cout << x << endl;
return 0;
}
long ifac(long n){
if(n == 0 || n == 1){
return 1;
}
else{
return n * ifac(n - 1);
}
}
九、命令行参数
十、编译预处理
宏
# 关键词 参数表
- 禁止' ; '
- 宏定义预处理
- 不属于C语言
- 不带参数的宏定义
- 提高程序可读性,便于修改
#define PI 3.1415926
- 宏名一般使用大写
- 可以通过
#undef
限制宏的使用范围 - 不影响字符串的使用
- 提高程序可读性,便于修改
- 带参数的宏定义
#define 宏名(参数表) 含参数的字符串
#define s(a,b) a*b
#define cube(x) ((x)*(x)*(x))
- 严格按照格式书写
- 功能类似函数
- 参数有可能用上表达式时加上括号(确保正确的运算顺序)
- 通过
\
实现隔行预处理 - 预先定义的宏
__LINE__
源代码的行号__FILE__
源代码的文件名__DATE__
编译的日期__TIME__
编译的时间__STDC__
文件包含
- 作用:将指定文件的内容与当前文件一起编译
- 说明
- 一个#include只能包含一个文件
- 被包含的文件可以嵌套文件
- 一般来说,原型声明及宏定义放在包含文件中
- 被包含的文件一般拓展名为.h,称为头文件
条件编译
-
通过控制程序,使程序编译不同的程序段
-
三种形式
//1
#ifdef 标识符
program
#else
program
#endif
//2
#ifndef 标识符
program
#else
program
#endif
//3
#if 表达式
program
#else
program
#endif
实例