跳转至

函数

一、初见函数

//素数
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;
}
  1. 函数的定义和调用
  2. 定义:函数是一块代码,接受零个或多个参数,做一件事情,并返回零个或一个值

  3. 调用函数:

    1. 语句形式:max(a,b)
    2. 表达式形式:c = max(a,b)*2
    3. 函数参数:c = max(a,max(b,d))
  4. 函数中的返回值
    1. 可以赋值给变量
    2. 可以再次传递给函数
    3. 如果没有return语句,由最后一个“}”返回一个不确定的值
    4. 返回值的类型与函数的类型一致,如不一致,以函数类型为准
  5. 没有返回值的函数(如下的代码)
    1. void
    2. 不能使用带值的return
      1. 可以没有return
    3. 调用时不能做返回值的赋值
//求和
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;
}   

二、函数

  1. 函数原型
  2. 函数的先后关系

    1. C的编译器逐行分析代码
    2. 可以先声明(以;结尾)后定义(无;)
  3. 参数传递

  4. C语言在调用函数时,永远只能传给函数

  5. 每个函数有自己的变量空间,与其他函数无关
  6. 每一次的运行都无关

  7. 内联函数

inline int iMax(int iVal1,int iVal2){
    return iVal1>iVal2?iVal1:iVal2;
}
  1. 适用于1-5句的小函数;
  2. 不能使用循环及switch,否则被译为一般函数

  3. 函数的重载

  4. 同名函数通过不同参数、类型、顺序、个数,实现同名不同功能函数的调用

    1. 如各种多边形面积的运算
  5. 本地变量的规则

  6. 本地变量是定义在块内的

    1. 可以是定义在函数块里
    2. 可以是定义在语句块里
    3. 甚至是任意的大括号
  7. 在块外,这个变量不存在
  8. 离开块后,这个变量不存在
  9. 快外定义的变量在块内有效
  10. 块内的变量掩盖块外的同名变量
  11. 同一个块中不能出现同名变量
  12. 本地变量不会被默认初始化

  13. void

  14. 参数未知,但不是没有

  15. 函数内没有参数时可用

  16. 逗号运算符

  17. 调用函数时首个圆括号内的逗号是标点符号

  18. 若要用都好运算符,则再加一个括号

  19. main 函数

三、变量的四种存储类型

  1. 局部变量

  2. 定义在复合语句开始处

    1. 块内生存,块内有效
    2. 与全局变量冲突时,局部变量优先
  3. 寄存器类型(register)

  4. 作用域与前者相同,但若CPU内部的寄存器空闲,则使用寄存器作为变量的存储单元可以提高程序运行速度

  5. 静态类型

  6. 作用域:在说明的复合语句内引用,出了复合语句不可用

  7. 生存期:从程序开始到程序结束

    #include <iostream>
    #include <iomanip>
    using namespace std;
    void row(void);
    
    int main(void){
        int b;
        for(b = 1;b <= 9;b++){
            row();
        }
        return 0;
    }
    void row(void){
        static int a = 1;     //static使a在函数内一直有效
        int b;
        for(b = 1;b <= 9;b++){
            cout << setw(4)<< a * b;
        }
        cout << endl;
        a++;
    }
    
  8. 外部类型

  9. 定义在任何模块之外的变量,也称为全局变量

  10. 作用域:从说明变量开始到程序结束
  11. 生存期:在程序的整个执行过程中,任何函数对外部变量的修改都会影响全局变量的值
  12. 注:不能用作函数参数
  13. 可以通过extern来改变其作用域

四、函数间的数据传递

  1. 函数见数据传递方式
  2. 通过函数参数传值或传地址
    1. 传值:形参与实参
    2. 传地址:形参定义为指针,实参为变量的地址
  3. 通过返回值传递结果
  4. 函数参数为引用
  5. 通过全局变量传递参数或结果

五、数组与函数参数

  1. 数组作为函数参数定义的三种方式
  2. 形参作为指针:int ave(int *p);
  3. 形参为无下表数组:int ave(int p[]);
  4. 形参为有下标数组:int ave(int p[10]);

六、返回指针的函数

  1. 概念:函数结束时候返回一个地址
  2. 注意:定义函数时候要加上“ * ”(返回值的类型与函数类型一致)

七、指向函数的指针

  1. 函数在内存中的首地址为函数的入口地址

  2. 使用过程

  3. 定义函数和指向函数的指针:int (*p)(int, int);

  4. 指针指向函数:p = Max; //max是函数名
  5. 通过指针引用函数:maxval = (*p)(x,y);

  6. 示例:

#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);
}

八、递归函数

  1. 概念:函数直接或间接地自我调用称为递归函数
  2. 通过控制条件,使递归终止
#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);
    }
}

九、命令行参数

十、编译预处理

  1. # 关键词 参数表
  2. 禁止' ; '
  3. 宏定义预处理
  4. 不属于C语言
  5. 不带参数的宏定义
    1. 提高程序可读性,便于修改
      1. #define PI 3.1415926
    2. 宏名一般使用大写
    3. 可以通过#undef限制宏的使用范围
    4. 不影响字符串的使用
  6. 带参数的宏定义
    1. #define 宏名(参数表) 含参数的字符串
      1. #define s(a,b) a*b
      2. #define cube(x) ((x)*(x)*(x))
    2. 严格按照格式书写
    3. 功能类似函数
    4. 参数有可能用上表达式时加上括号(确保正确的运算顺序
  7. 通过\实现隔行预处理
  8. 预先定义的宏
    1. __LINE__源代码的行号
    2. __FILE__源代码的文件名
    3. __DATE__ 编译的日期
    4. __TIME__编译的时间
    5. __STDC__

文件包含

#include <被包含的文件名>      //<>表示编译系统定义路径
#include "被包含的文件名"      //""表示用户指明路径
  1. 作用:将指定文件的内容与当前文件一起编译
  2. 说明
  3. 一个#include只能包含一个文件
  4. 被包含的文件可以嵌套文件
  5. 一般来说,原型声明及宏定义放在包含文件中
  6. 被包含的文件一般拓展名为.h,称为头文件

条件编译

  1. 通过控制程序,使程序编译不同的程序段

  2. 三种形式

//1
#ifdef 标识符
    program 
#else
    program
#endif

//2
#ifndef 标识符
    program
#else 
    program
#endif


//3
#if 表达式
    program
#else
    program
#endif        

实例

#define DEBUG
    .....
    .....
    .....
#ifdef DEBUG
    用于调试语句的程序
#endif