目录
一、函数概述
1.函数的定义
2.函数分类
3.函数的作用
二 、函数的调用
1.函数的形参和实参
2.有无返回值
3.传值调用、传参调用
三、函数的特点
1.函数参数的计算顺序
2.函数的声明
3.命令行参数
四、函数和变量的存储方式
1.函数的存储类别
2.变量的作用域
3.变量的存储类别
一、函数概述
1.函数的定义
1.函数的定义
返回值类型 函数名字(形参列表) {//函数体,函数的功能在函数体里实现// return 返回值 }
2.形参列表
- 形参必须带类型,而且以逗号分隔。
- 形参∶可以有也可以没有,也可以有多个。但是即使没有,函数名字后面也必须加括号函数体上下位置必须有大括号。
3.函数名
- 在一个程序中,函数只能定义一次。
- 在一个程序内,相同的函数名只能出现一次。
- 函数的定义不能嵌套,即不能在一个函数体内定义另外一个函数,但是可以嵌套调用。
4.返回值
- 第一种:return (表达式);第二种:return 表达式;第三种:void型号,可以写return;也可以什么都不写。
- 如果要返回函数执行的结果,也就是返回值,则return后面跟的变量或者值,必须与函数名左边的返回值类型一致。
- 如果返回的类型和return语句表达式的值不一样,则以函数返回值类型为主,即函数返回类型决定返回值类型。(对数值型数据,可以自动进行类型转换;对于其他无法进行类型转换的程序会自动报错)
2.函数分类
1.从定义角度分类(即函数是谁实现的)
- 库函数(c语言实现的)
- 自定义函数(程序员自己实现的函数)
2.从参数角度分类
- 有参函数:函数有形参,可以是一个或者多个,参数的类型随便,完全取决于函数的功能。
- 无参函数:函数没有参数,在形参列表的位置写一个 viod 或什么都不写。
3.从返回值角度分类
- 带返回值的函数:在定义函数的时候必须带着返回值类型,在函数体里必须有 return ,如果没有返回值类型,默认返回整型。
4.注意点:
- 在定义函数的时候,函数的返回值类型,到底是什么类型取决于函数的功能
- 没有返回值的函数,在定义函数的时候,函数名字前面加 void ,在函数里不需要 return。如果想结束函数返回到被调用的地方,return ;什么都不返回就可以了。
3.函数的作用
- 函数的使用可以省去重复代码的编写,降低代码重复率。
- 函数可以使程序更加模块化,从而有利于程序的阅读,修改和完善。
二 、函数的调用
1.函数的形参和实参
1.实参:真实传给函数的参数,在调用有参函数时,函数名后面括号中的参数称为实际参数,实参可以是常量、变量、表达式或者函数。
- 在进行函数调用的时候,它们都必须有确定的值,以便传给形参。(实参进入被调函数后,实参就不能使用)
- 实参变量对形参变量的数据传递是“值传递”,单向传递,只由实参传递给形参
2.形参:函数名后括号中的变量,只有在函数被调用的过程中才实例化(分配内存单元)所以叫形式参数。(目的是用来接收调用该函数时传入的参数)
- 形式参数当函数调用完成之后就自动销毁了,因此形式参数只在函数中有效。
- 实参和形参可以重名,必须注意实参的个数,类型应与形参一一对应,并且实参必须要有确定的值。
3.形参与实参的差别:
- 本质不同:形参的本质是一个名字,不占用内存空间。实参的本质是一个变量,已经占用内存空间。
- 作用域不同:形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。
- 生命周期不同:形参变量只有在被调用时才分配内存单元(栈空间),在调用结束时, 即刻释放所分配的内存单元。因此形参只有在函数内部有效。 函数调用结束返回主调函数后则不能再使用该形参变量。
2.有无返回值
1.有无返回值
变量=函数名(实参列表);//带返回值的 函数名(实参列表); //不带返回值的
- 有返回值的,根据返回值的类型,要在主函数中定义一个对应类型的变量,接收返回值
- 没有返回值的函数,不需要接收返回值
#include <stdio.h>void myfun1() {printf("hello world\n");return ;//可写可不写 }//a,b:形式参数,主要用于保存实数传递的值,本质跟实参没有任何关系,只是值传递 void myfun2(int a,int b) {int sum;sum =a+b;printf("%d+%d=%d\n",a,b,sum); }int myfun3(int a,int b) {int sum;sum =a+b;return sum;//必须有返回值 }int main() {int x=10,y=49,n;myfun1();myfun2(12,5);myfun2(x,y); //x,y:实参,实际参数,本质就是在函数调用时将实参的值传递给形参n=myfun3(277,99);printf("%d\n",n);printf("sum=%d\n",myfun3(277,99));return 0; }
3.传值调用、传参调用
1.传值调用
- 函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
#include <iostream> using namespace std;//v只在函数f1内部可见,并在函数f1执行完的时候释放 void f1(int v) {v = 2; }int main() {int a = 1;f1(a); cout << a << endl;//仍然是1return 0; }
2.传址调用
- 传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
- 传址调用可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
#include <iostream> using namespace std;//以引用方式传递,v是调用时传递变量a的别名 void f2(int& v) {v = 2; }int main() {int a = 1;f2(a);cout << a << endl;//a被函数修改了,此时是2return 0; }
三、函数的特点
1.函数参数的计算顺序
- printf()函数输出时,表达式的计算顺序是从右到左的。(printf()函数处理参数时是一个压栈的过程,类似于栈的先进后出)
#include<stdio.h>int main(){int a = 10;printf("%d %d %d %d %d\n", a++, ++a, --a, a--, a);//正确结果为:9 10 10 10 10return 0; }
2.函数的声明
1.函数声明
- 告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了。
- 函数的声明一般出现在函数的使用之前,要满足先声明后使用。
- 一个函数只能被定义一次,但是可以声明多次。
#include<stdio.h> int add(int x, int y);
2.函数定义
- 函数的定义是指函数的具体实现,交待函数的功能实现。
//函数的实现 int add(int x,int y) {return x + y; }
3.命令行参数
1.命令行参数的概述
- 平时写主函数的方式
int main() {return 0; }
- 事实上main函数是可以带参数的,我们把main函数的参数称为命令行参数
int main(int argc, char *argv[]) {return 0; }
2.命令行参数使用
- argc : argument count 参数个数
- argv : argument value 参数的值
int main(int argc, char *argv[]) {printf("argc = %d\n", argc);for (int i = 0; i < argc; ++i){printf("%s\n", argv[i]);}return 0; }
四、函数和变量的存储方式
1.函数的存储类别
1.静态存储:指在程序运行期间由系统分配固定的存储空间的方式。(用来存放全局变量及静态类型的局部变量)
- static变量:静态局部变量;编译时赋初值;不赋初值时自动赋初值为0或空字符串;对于auto不付赋值是一个不确定的值;只能在本编译单位中的其他函数调用它,避免不同编译单元因函数同名而引起混乱。
2.动态存储:在程序运行期间根据需要进行动态的分配存储空间的方式。(用来保存函数调用时的返回地址,自动类型的局部变量)
- auto 变量:动态分布存储空间;调用函数时系统给他们分配空间,调用结束自动释放;auto 可以省略不加static的一般都是auto;必须赋初值;
#include <stdio.h> void main() {auto int a =5; //=int aprintf("%d",a); }
- extern 变量:声名外部变量;
#include <stdio.h> void fun() { }void main() {extern A,B;printf("%d%d",A,B);fun(); } int A=5,B=6;
2.变量的作用域
1.局部变量
- 在函数或一个代码块内部声明的变量称为局部变量。
- 它们只能被函数内部或者代码块内部的语句使用,在其他范围内无效。
2.全局变量
- 在所有函数外部定义的变量称为全局变量。全局变量的值在程序的整个生命周期内都是有效的。
- 全局变量可以被任何函数访问。全局变量一旦声明,在整个程序中都是可用的。
- 若全局变量和函数内的局部变量同名(发生冲突),优先使用局部变量。
3.变量的存储类别
1、局部变量的存储区别:
1.aotu局部变量:自动变量,存储在动态存储区。作用域从定义的位置到函数体结束为止;
- 调用时必须赋初值
- 不同函数使用了同名auto变量也不会相互影响
- 再次进入函数时,auto变量的值不会被保留重新赋初值。
2.register局部变量:寄存器变量。作用域从定义的位置到函数体结束为止;
- 执行速度更快,只能把频繁使用的少量变量指定为register变量,提高运行速率
3.sttic局部变量:静态局部变量。作用域从定义的位置到函数体结束为止;
- 编译时就进行赋值,如果未赋值,自动赋初值为0
- 静态局部变量的生存期一直延长到程序运行结束,再次进入函数时候,static变量会使用上次结束函数时的值。
感谢来自大佬们的资料分享:
勐拉丽莎的哭泣
阿明6
多低调