栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

4.2 函数

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

4.2 函数

函数基本概念:

1.函数就是一系列语句的组合,包括函数名、返回值、形参表和函数体,例如:主main函数

2.三类:main函数、库函数printf和自定义函数

3.程序的全部工作由函数完成,函数式语言

4.函数不能嵌套定义,但可以互相调用

5.main函数可以调用其它函数,但不能被其它函数调用

6.函数之间通过参数和返回值交换数据

7.int main(void){}为主函数

8.函数也可以没有参数和(或)返回值

C语言函数相关内容(核心中的核心)
1.明确:任何C语言程序都是由两部分组成:一堆的变量(包括数组)和一堆的函数
              前者负责分配内存,后者负责操作访问内存
2.函数的概念:就是一堆语句的组合,一次写好,到处使用!printf
        本质目的:减少开发的工作量,提高代码的可维护性!

3.问:为何掌握函数这个技术呢?
          答:举例子
          需求:实现两个正数相加
          张三同学的代码:
          vim add.c
          int main(void) {
                    int a, b, sum = 0;
                    scanf("%d%d", &a, &b);
                    if(a < 0 || b <0) {
                                printf("请输入两个正数.n");
                                return -1;
                    }
                    sum = a + b;
                    printf("sum = %dn", sum);
                    return 0;
          }

  李四同学代码:
          vim add.c
          int main(void) {
                    int a, b, sum = 0;
                    scanf("%d%d", &a, &b);
                    if(a < 0 || b <0) {
                                printf("请输入两个正数.n");
                                return -1;
                    }
                    sum = a + b;
                    printf("sum = %dn", sum);
                    return 0;
  其余学生:
  vim add3.c,....add250.c ...
  结论:如果完成这些功能,所有人的代码很多地方都是重复的,写了一遍又一遍,无形增加开发的工作量和代码体积
  期望:只需将重复的代码写一次即可,其他人无需编写拿来直接使用即可,类似:大神写好的printf,scanf一样
        极大减少开发的工作量

  问:如何实现?
  答:采用大名鼎鼎的函数这个技术来解决
  大佬编写一个add函数
  vim add.c 
          void add(int x, int y) {
                if(x < 0 || y <0) {
                        printf("请输入两个正数.n");
                        return;
                 }
                 sum = x + y;
                 printf("sum = %dn", sum);
          }  
 张三同学的代码:
  vim add.c
          int main(void) {
                    int a, b;
                    scanf("%d%d", &a, &b);
                    add(a, b);//调用大佬编写的add函数并且给add函数传递两个数值也就是a,b的值
                    return 0;
          }
  李四同学代码:
          int main(void) {
                    int a, b;
                    scanf("%d%d", &a, &b);
                    add(a, b);//调用大佬编写的add函数并且给add函数传递两个数值也就是a,b的值
                    return 0;
          }
  结论:如果将来要想实现这个需求,只需调用大佬编写的add函数即可,无需非常辛苦的编写代码
        大大提高了开发的效率,提高代码的可维护性,大大降低了开发的工作量 


函数三大步骤 函数定义:(函数实现,函数封装)

返回值类型 函数名(形参表){

        函数体;

}

1.函数的返回值类型默认为int,若没有返回值,则需要用void标明

2.若函数的返回值类型为void,则不需要return任何值,或者省略return语句,若加了return,后边也不要加任何值

3.若函数的返回值类型不是void,但没有通过return语句显式返回任何值,则会返回一个不确定值

4.若函数的返回值类型与return值的类型不一致,则会发生类型转换

遇到return时,编译器相当于加一条goto语句,跳到末尾的花括号

函数调用:

1.函数在定义时使用的参数叫形参,调用函数时传入的参数叫实参

2.函数调用时将实参传递给形参的过程, 类似于把实参赋值给形参

3.形参只是实参的一份拷贝,而非实参本身,这种参数传递方式叫值传递

示例:

//函数的用法
#include 
//函数玩法步骤一:函数定义
//形式1:定义无返回值无形参的函数
//无返回值:就是函数执行完毕不需要返回一个数值
//无形参:就是函数不需要接收传递来的参数
void foo(void) {
    printf("void foo(void)n");
    //return; //可以省略return关键字
}
void foo1(void) {
    printf("void foo1(void)n");
    return;//如果是无返回值函数,并且用return进行返回,此时return后面不要跟数值
    printf("我会被执行吗?n");
}
//形式2:定义有返回值无形参的函数
//有返回值:就是函数执行完毕最后返回一个运行的结果
int bar(void) { //int:表示bar函数返回运行结果的数据类型
    return 520; //返回常量 
}
int bar2(void) {
    int a = 521;
    a++;
    return a; //返回变量a的内存值522
}
int bar3(void) {
    printf("int bar3(void)n");
} //忘记写return,忘记添加返回值,gcc会返回一个随机数
char bar4(void) {
    int a = 555;
    return a;//gcc会将int类型的a强转为char类型之后在返回 
}
//形式3:定义无返回值有形参的函数
//有形参:就是调用函数时可以给函数传递参数,函数的形参可以用来保存传递的参数
//形参就是一堆变量,此变量又称形参变量
void add(int x, int y) { //x,y就是形参变量,分配的内存用来保存调用函数时给函数传递的参数值
                          //形参变量x保存实参变量a的值10,形参变量y保存实参变量b的值20
    if(x < 0 || y < 0) {
        printf("传递的参数值不是正数.n");
        return;
    }
    int sum = x + y;
    printf("add函数:sum = %dn", sum);
}
//形式4:定义有返回值并且有形参的函数
int sub(int x, int y) {
    return x - y; //返回形参变量x,y相减的结果
}
int main(void) {
    printf("main函数开始.n");
    //函数玩法步骤二:函数调用
    int a = 10, b = 20;
    printf("sub函数的返回值是:%dn", sub(a, b));
    add(a, b);//调用无返回值有形参的函数,并且调用时给add函数传递两个实参变量a,b的值10,20
    int ret = 0; //ret变量将来保存函数的返回值
    ret = bar(); //调用有返回值无形参函数,用ret来保存函数的返回值
    printf("bar函数的返回值是:%dn", ret);
    ret = bar2(); //调用有返回值无形参函数,用ret来保存函数的返回值
    printf("bar2函数的返回值是:%dn", ret);
    ret = bar3(); //调用有返回值无形参函数,用ret来保存函数的返回值
    printf("bar3函数的返回值是:%dn", ret);
    ret = bar4(); //调用有返回值无形参函数,用ret来保存函数的返回值
    printf("bar4函数的返回值是:%dn", ret);
    printf("bar4函数的返回值是:%dn", bar4());
    foo();//调用无返回值无形参的函数
    foo1();//调用无返回值无形参的函数
    printf("main函数结束.n");
    return 0;
}

函数声明:不会分配内存

1.函数在使用前必须声明,声明可以是隐式的,隐式声明的固定形式为:

        int f(); //该函数可以接受任意参数,并返回整型值

        但是!!!!虽然可以接受任意参数,函数却不能对这些传递的参数做任何操作,因为没有形参去接收

2.如果函数的返回类型不是int,最好对其做显式声明,即函数的原型

        extern 返回值类型 函数名(形参表)

3.声明函数时,省略参数表,表示其可接受任意参数;参数表为void,表示其不接受任何参数

4.下面代码调用上面定义的函数时,可以不再单独声明

示例:

//函数的用法
#include 
//函数步骤三:函数声明(不会分配内存的)
//切记:如果函数调用的代码在函数定义的代码前面,那么就需要在函数调用代码的前面先做函数声明
extern void foo(void);
extern void foo1(void);
extern int bar(void);
extern int bar2(void);
extern int bar3(void);
extern char bar4(void);
extern void add(int x, int y);
extern int sub(int, int); //声明时形参变量名可以省略
int main(void) {
    printf("main函数开始.n");
    //函数步骤二:函数调用
    int a = 10, b = 20;
    printf("sub函数的返回值是:%dn", sub(a, b));
    add(a, b);//调用无返回值有形参的函数,并且调用时给add函数传递两个实参变量a,b的值10,20
    int ret = 0; //ret变量将来保存函数的返回值
    ret = bar(); //调用有返回值无形参函数,用ret来保存函数的返回值
    printf("bar函数的返回值是:%dn", ret);
    ret = bar2(); //调用有返回值无形参函数,用ret来保存函数的返回值
    printf("bar2函数的返回值是:%dn", ret);
    ret = bar3(); //调用有返回值无形参函数,用ret来保存函数的返回值
    printf("bar3函数的返回值是:%dn", ret);
    ret = bar4(); //调用有返回值无形参函数,用ret来保存函数的返回值
    printf("bar4函数的返回值是:%dn", ret);
    printf("bar4函数的返回值是:%dn", bar4());
    foo();//调用无返回值无形参的函数
    foo1();//调用无返回值无形参的函数
    printf("main函数结束.n");
    return 0;
}
//函数步骤一:函数定义
//形式1:定义无返回值无形参的函数
//无返回值:就是函数执行完毕不需要返回一个数值
//无形参:就是函数不需要接收传递来的参数
void foo(void) {
    printf("void foo(void)n");
    //return; //可以省略return关键字
}
void foo1(void) {
    printf("void foo1(void)n");
    return;//如果是无返回值函数,并且用return进行返回,此时return后面不要跟数值
    printf("我会被执行吗?n");
}
//形式2:定义有返回值无形参的函数
//有返回值:就是函数执行完毕最后返回一个运行的结果
int bar(void) { //int:表示bar函数返回运行结果的数据类型
    return 520; //返回常量 
}
int bar2(void) {
    int a = 521;
    a++;
    return a; //返回变量a的内存值522
}
int bar3(void) {
    printf("int bar3(void)n");
} //忘记写return,忘记添加返回值,gcc会返回一个随机数
char bar4(void) {
    int a = 555;
    return a;//gcc会将int类型的a强转为char类型之后在返回 
}
//形式3:定义无返回值有形参的函数
//有形参:就是调用函数时可以给函数传递参数,函数的形参可以用来保存传递的参数
//形参就是一堆变量,此变量又称形参变量
void add(int x, int y) { //x,y就是形参变量,分配的内存用来保存调用函数时给函数传递的参数值
                          //形参变量x保存实参变量a的值10,形参变量y保存实参变量b的值20
    if(x < 0 || y < 0) {
        printf("传递的参数值不是正数.n");
        return;
    }
    int sum = x + y;
    printf("add函数:sum = %dn", sum);
}
//形式4:定义有返回值并且有形参的函数
int sub(int x, int y) {
    return x - y; //返回形参变量x,y相减的结果
}

数组访问公式!!
//函数访问数组分配的内存编程公式
#include 
//函数玩法三:函数声明
extern void print(int parray[], int size); 
extern void change(int parray[], int size);

int main(void) {
    int array[5] = {1,2,3,4,5};
    int size = sizeof(array)/sizeof(array[0]);

    //函数玩法二:函数调用
    print(array, size);//调用print函数来打印数组的元素值,并且将数组的首地址和元素个数传递给
                        //print函数
    change(array, size);//传递数组的首地址和元素个数
    print(array, size);//传递数组的首地址和元素个数
    return 0;
}

//函数玩法一:函数定义
//第一个参数parray不是数组,本质是指针(后续课程详解),parray保存着数组的首地址
//必须是此形式,[]千万不能丢弃,函数print将来通过parray来访问数组跟通过数组名array访问数组
//一模一样
void print(int parray[], int size) {
    for(int i = 0; i < size; i++) 
        printf("%d ", parray[i]);
    printf("n");
}
void change(int parr[], int size) {
    for(int i = 0; i < size; i++)
        parr[i] += 1;
}

extern void print(int parray[], int size); //这里定义的形参用 int parry[]来接收,不能去掉[],这是公式!!!!!

print(array, size);//调用print函数来打印数组的元素值,并且将数组的首地址和元素个数传递给print函数

change(array, size);//传递数组的首地址和元素个数

print(array, size);//传递数组的首地址和元素个数

第一个参数parray不是数组,本质是指针(后续详解),parray保存着数组的首地址

必须是此形式,[]千万不能丢弃,函数print将来通过parray来访问数组跟通过数组名array访问数组


递归与递推:

1.函数在函数体内调用其自身称为调用该函数称为递归函数

2.调用递归函数的过程,逐层调用,逐层返回

3.递归就是循环迭代,上一代运算结果作为下一次的运算初始值,版本更新就是迭代过程

4.递归有可能形成无限递归,或者增加算法的时间复杂度,因此使用递归时,需要注意:

        必须有递归终止条件

        必须保证应用递归确实使算法得到简化

        段错误(核心已转储):内存非法访问了,崩溃

递归函数调用流程:
A<->B<->C
A<->A<->A

需求:利用递归函数实现打印:1 2 3
分析:
    #include
    void print(int max) {
        //3.最后添加递归退出的条件
        if(max == 1) {
            printf("1 ");
            return;
        }
        print(max-1);//2.然后发现打印2和打印3所作的工作都是一样的,只需调用自己重复打印即可
        printf("%d ", max);//1.首先要明确此递归函数最终要完成一个打印数字的功能
        return;
    }
    int main(void) {
        int max = 3;
        print(max);
        printf("n");
        return 0;
    }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/867351.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号