C语言-函数

为什么使用函数

使main函数变短,容易阅读。需要用的功能不用重复敲。(函数在OC里称为方法)


函数的定义

定义函数的方法

定义无参函数

类型名 函数名(void(可有可无)) {
函数体
}

定义有参函数,如:

int max(int x, int y) {
int z;
z = x > y ? x : y;
return z;
}

定义空函数

void dummy() {
}


函数调用

函数调用的形式

函数调用语句

把函数调用单独作为一个语句,如:printStar

函数调用出现在另一个表达式中,

如:c = 2 * max(a, b);

函数参数

函数调用时作为另一个函数调用时的实参,如:
m = max(c, max(a, b));
printf("%d", max(a, b));
printf为系统函数


函数调用时的数据传递

形参和实参

形参:自定义函数中的参数
实参:main函数调用自定义函数中的参数

实参和形参间的数据传递

实参——>形参,在函数调用过程中发生的实参和形参间的数据传递,常成为“虚实结合”。

例 输入两个整数,输出其中的较大者
说明:
a.实参可以是常量,变量或者表达式,但要求它们有确定的值
b.形参与实参的类型应相同或赋值兼容

int max(int x, int y) {
    int z;
    z = x > y ? x : y;
    return z;
}

int main(int argc, const char * argv[]) {
    printf("%d", max(3, 4));
    return 0;
}

函数调用的过程

  • 形参在未调用时,并不占内存的存储单元
  • 实参对应的值传给形参
    在执行MAX函数期间,由于形参已经有值,就可以利用形参进行有关运算, 通过return将函数值带回到主调函数,如果函数不需要返回值,则不需要return语句
  • 结束调用,形参单元被释放
    注意:实参单元仍保留并维持原值,并没有改变。如果在执行一个被调用函数时,形参的值发生改变,不会改变主调函数实参的值,实参向形参的传递是“值传递”,单向传递,只能实参到形参,而不能形参到实参,因为实参和形参占用存储单元不同,实参无法得到实参的值。

函数的返回值

  • 函数的返回值是通过函数中的return语句获得的
  • 函数值类型。既然函数有返回值,这个值当然属于某一个确定的类型,应当在定义函数时指定函数值得类型
  • 在定义函数时指定的函数类型一般应和return语句中表达式的值一致

对被调用的函数的声明和函数原型

函数的首行称为函数原型, 通常函数原型声明函数

例 输入两个实数,用一个函数求出它们的和

float add(float x, float y);

int main(int argc, const char * argv[]) {
    printf("%.2f", add(2.6, add(2.4, add(2.6, 2.4))));
    return 0;
}

float add(float x, float y) {
    float z;
    z = x + y;
    return z;
}

函数的嵌套调用

例 输入四个整数,找出其中最大数,用函数的嵌套调用来处理

int maxTwoNum(int a, int b);
int maxFourNum(int a, int b, int c, int d);

int main(int argc, const char * argv[]) {
    int a = 0, b = 0, c = 0, d = 0;
    printf("Please input 4 nums\n");
    scanf("%d%d%d%d", &a, &b, &c, &d);
    printf("MAX num is %d\n", maxFourNum(a, b, c, d));
    return 0;
}

int maxTwoNum(int a, int b) {
    return a > b ? a : b;
}

int maxFourNum(int a, int b, int c, int d) {
    return maxTwoNum(maxTwoNum(maxTwoNum(a, b), c), d);
}

递归

在调用函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用

例 有5个学生坐在一起,问第五个学生多少岁,他说比第 4个学生大2岁。问第4个学生,他说比第三个学生大2岁。问第3个学生,他说比第2个学生大2岁。问第二个学生,他说比第1个学生大2岁。最后问第一个学生,他说10岁。请问第五个学生多大。

int nianling(int x);
int main(int argc, const char * argv[]) {
    /*
     解题思路:
     age(5) = age(4) + 2;
     age(4) = age(3) + 2;
     age(3) = age(2) + 2;
     age(2) = age(1) + 2;
     age(1) = 10;
     用数学公式表示如下:
     age(n) = 10;             (n = 1)
     age(n) = age(n - 1) + 2; (n > 1)
     */
    int n = 0;
    printf("请输入第n个学生:\n");
    scanf("%d", &n);
    printf("第%d个学生的年龄是%d\n", n, nianling(n));
}

int nianling(int x) {   //x是第x个学生
    int a;
    if (x == 1) {
        a = 10;
    } else {
        a = nianling(x - 1) + 2;
    }
    return a;
}

例 用递归求n!

int factorial(int n);
int main(int argc, const char * argv[]) {
    /*
     n! = 1;           (n = 1)
     n! = n * (n - 1); (n > 1)
     */
    int n;
    printf("Please input a num:\n");
    scanf("%d", &n);
    printf("The result is %d\n", factorial(n));
    return 0;
}

int factorial(int n) {
    int f;
    if (n == 1) {
        f = 1;
    } else {
        f = n * factorial(n - 1);
    }
    return f;
}

数组作为函数参数

数组元素作函数实参

数组元素可以用作函数实参,不能用作形参。因为形参是在函数被调用时临时分配存储单元的,不可能为一个数组元素单独分配存储单元。在用数组元素作函数参数时,把实参的值传给形参,是“值传递”方式,单向传递。

例 输入十个数,要求输出其中值最大的元素和该数是第几个数。

int max(int x, int y);

int main(int argc, const char * argv[]) {
    /*
     解题思路:可以定义一个数组a,长度为10,用来存放10个数。设计一个Max函数,用来求两数中的大者。在主函数中定义一个变量m,m的初值为a[0],每次调用m后的返回值存放在m中。依次将数组元素a[1]到[9]与m比较,最后得到的m值就是10个数中的最大者。
     */
    int a[10] = {18, 19, 1, 27, 6, 45, 99, 17, 65, 88};
    int m = a[0];
    int n = 0;
    for (int i = 0; i < 10; i++) {
        if (max(m, a[i]) > m) {
            m = max(m, a[i]);
            n = i;
        }
    }
    printf("%d %d", m, n);
    return 0;
}

int max(int x, int y) {
    return x > y ? x : y;
}

数组名作函数参数

除了可以用数组元素作为函数参数外,还可以用数组名作函数参数(包括实参和形参)
注意:用数组元素作实参时,向形参变量传递的是数组元素的值,而用数组名作函数实参时,向形参(数组名或指针变量)传递的是数组首元素地址。

例 有一个一维数组score,内放10个学生成绩,求平均成绩

float average(int array[10]);
int main(int argc, const char * argv[]) {
    /*
    解题思路:用一个函数average求平均成绩,不用数组元素作为函数实参,而用数组名作为函数实参,形参也用数组名,在average中引用各数组元素,求平均成绩并返回main函数。
     */
    int array[10], i = 0;
    for (i = 0; i < 10; i++) {
        array[i] = arc4random()%15;
        printf("%d ", array[i]);
    }
    printf("\n");
    printf("%0.2f", average(array));
    return 0;
}
float average(int array[10]) {
    int i = 0;
    float average = 0.0f, sum = 0.0f;
    for (i = 0; i < 10; i++) {
        sum += array[i];
    }
    average = sum / 10;
    return average;
}

例 有两个班,分别有35名和30名学生,调用一个average函数,分别求这两个班平均成绩

float average(float array[], int n);

int main(int argc, const char * argv[]) {
    float class1[30] = {0};
    float class2[35] = {0};
    for (int i = 0; i < 30; i++) {
        class1[i] = arc4random()%51 + 50;
        printf("%0.2f ", class1[i]);
    }
    printf("\n");
    for (int i = 0; i < 35; i++) {
        class2[i] = arc4random()%51 + 50;
        printf("%0.2f ", class1[i]);
    }
    printf("\n");
    printf("班级1平均成绩是:%0.2f\n", average(class1, 30));
    printf("班级2平均成绩是:%0.2f\n", average(class2, 35));
    return 0;
}

float average(float array[], int n) {
    float average = 0.0f;
    float sum = 0.0f;
    for (int i = 0; i < n; i++) {
        sum = sum + array[i];
    }
    average = sum / n;
    return average;
}

例 用选择法将数组中十个整数进行排序
选择法就是先将10个数中最小的数与a[0]对换,再将a[0]~a[9]中最小的数与a[1]对换。(冒泡排序)

void bubbleSort(int array[], int n);

int main(int argc, const char * argv[]) {
    int a[10] = {1, 5, 7, 0, 9, 3, 6, 4, 2, 8};
    bubbleSort(a, 10);
    for (int i = 0; i < 10; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
    return 0;
}

void bubbleSort(int array[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - 1 - i; j++) {
            if (array[j] > array[j + 1]) {
                int t = array[j];
                array[j] = array[j + 1];
                array[j + 1] = t;
            }
        }
    }
}

多维数组名作函数参数

注意:形参数组的第一维大小可以省略,第二维不可以,并且要和实参的相同。在主函数调用maxvalue函数时,把实参第一行起始地址传给arr,因此a与arr起始地址相同,由于两个数组列数相同,因此arr数组第二行起始地址与a也相同。arr与a同占一个存储单元,它们具有同一个值。实际上,arr就是a,在函数中对arr操作就是对a操作

例 有一个3*4的矩阵,求所有元素中最大值

int maxValue(int a[][4]);

int main(int argc, const char * argv[]){
    int a[3][4] = {{1, 3, 5, 7}, {2, 4, 6, 8}, {15, 17, 34, 12}};
    printf("MAX: %d", maxValue(a));
    return 0;
}

int maxValue(int arr[][4]) {
    int i, j, max;
    max = arr[0][0];
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 4; j++) {
            if (arr[i][j] > max) {
                max = arr[i][j];
            }
        }
    }
    return max;
}

局部变量和全局变量

局部变量

  • 主函数中定义的函数只在主函数中有效,不能使整个文件或程序中有效,其他函数定义的变量主函数也不能用
  • 不同函数中可以使用同名变量
  • 形参也是局部变量
  • 在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为“分程序”或“程序块”

全局变量

在函数外定义的称为全局变量,也称外部变量由于函数的调用只能带回一个函数返回值,因此有时可以利用全局变量来对增加函数间的联系渠道,通过函数调用能得到一个以上的值


变量的存储方式和生存期

动态存储方式和静态存储方式

内存空间可以分为三部分:程序区、静态存储区、动态存储区
全局变量全部存放在静态存储区
动态存储区存放以下数据:

  • 形参
  • 没有用static声明的变量
  • 函数调用时的现场保护和返回地址等

局部变量的存储类别

  • 自动变量(auto变量)
    在调用函数时,自动分配存储空间,函数调用结束,自动释放。
    auto int a = 0;
  • 静态局部变量(static局部变量)
    有时希望函数中的局部变量的值在调用后不消失并保留(上一次调用结束后的值),这时就指定其为静态局部变量,用关键字static声明。
    static a = 0;

内部函数和外部函数

内部函数

如果一个函数只能被本文件中其他函数所调用,它称为内部函数
在定义内部函数时,在函数名和函数类型前面加static,即:
static 类型名 函数名(形参表):
static int fun(int a, int b);


外部函数

extern int fun(int a, int b);

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值