函数(定义、声明、调用)
函数定义:
返回值类型 函数名(参数表(形参:没有内存的):类型+参数名)
{
函数体;
}
函数分类:
从实现的角度:库函数与自定义函数(实现)
从参数表的角度:有参函数与无参函数(参数表)
从返回值角度:有返回值(函数体中必须有return)与无返回值(void)(返回值)
函数调用:
函数名(参数表:实参(任意的表达式))
要求:实参个数、类型、顺序与形参严格一致
函数调用的方式:
1.函数调用作为独立的语句:不要求函数带回值,只要求函数完成一定的操作
2.作为表达式的一部分:(函数的返回值)函数表达式
3.作为另外一个函数的实参(函数的返回值):函数参数
函数调用的流程:
1.系统给形参分配临时内存,把实参传给形参(用实参给形参初始化)
2.进入被调函数函数体,执行到return(带回一个返回值)或者函数块末尾.回到主调函数。3.系统回收形参(普通局部变量)的临时内存.
函数声明:返回值类型 函数名(参数表:形参表);
1.库函数不需要自己声明,引用头文件
2.自定义函数当函数定义在调用之后,需要声明
函数参数传递方式:值传递、址传递、引用传递
注意:
1.当通过函数参数改变主调函数中变量的值,址传递(实参是变量的地址)或引用传递
2.普通类型:址传递
类类型:引用传递
3.指针可以为空,址传递时,必须要判断指针是否为空,assert()判断
引用:(C++专属):给变量取别名;
定义:类型 &引用名;必须初始化(必须是变量名)
常引用:const int &refn;只读类型的引用
指针与引用的区别:
指针可以不初始化,引用必须初始化;
指针可以为NULL,但是引用不可能为NULL;
指针有自己独立内存,但是引用没有独立内存;
指针可以改变指向的,但是引用不能改变被引用对象
普通局部变量与普通全局变量
普通局部变量:定义在函数中的变量;(生存周期:从定义到这个函数结束)
普通全局变量:定义在函数外的变量;(生存周期:从定义到源文件结束)
作用域范围(访问)与生存周期(内存)
内存区域的划分(生存周期):
全局区:全局变量、静态变量static(编译时分配内存到程序结束)
栈区:普通局部变量(定义时分配内存,函数调用完毕)
堆区:程序员自己申请(malloc、new),由程序员自己手动释放(free、delete)
常量区:const 字符串()定义到程序结束
作用域范围(访问):
(普通)局部变量:当前的语句块{}
普通全局变量:当前项目的所有文件,在其他文件中访问需要extern声明
静态全局变量:当前文件
静态局部变量与普通局部变量:作用域范围相同,生存周期不同
静态全局变量与普通全局变量:生存周期相同,作用域范围不同;
static与const的用法
static可以修饰函数为内部函数,只能在本文件中被调用,其他源文件不能声明调用该函数。
static修饰的全局变量只能在本源文件中访问,其他源文件不能使用。
static还可修饰局部变量为静态局部变量,保存到静态存储区,下次再调用该函数时可以保留上一次的调用结果。
[cpp]view plaincopyprint?
#include<stdio.h>
voidstatictest1_1(int len){
auto int a = 0;
static int b = 0;
printf("a+len = %d+%d",a,len);
a +=len;
printf("=%d\t", a);
printf("b+len=%d+%d",b,len);
b +=len;
printf("=%d\n", b);
}
staticvoid statictest1_2(){
printf("static修饰的函数只能在本文件中被调用\n");
}
voidstaticmain(){
for(int i=0; i < 5; i++){
statictest1_1(i);
}
}
输出:
a+len= 0+0=0 b+len=0+0=0
a+len= 0+1=1 b+len=0+1=1
a+len= 0+2=2 b+len=1+2=3
a+len= 0+3=3 b+len=3+3=6
a+len= 0+4=4 b+len=6+4=10
由于a使用auto修饰表示动态分配内存,每次调用函数时a的内存都是动态分配和释放的,每次都初始化为0
而b使用static修饰,表示存放在静态存储区,一直到main程序结束才释放内存,当函数调用结束时还是可以保留b的值。只在第一次初始化,下次使用上一次的计算结果。
虽然用static修饰b,但b还是局部变量,其他函数不能访问到b
可计算1+2+3+4+.....+n和1*2*3*4*....*n
函数:参数(值传递,地址传递,引用传递)
函数参数:数组
形参:数组(或者用指向该数组的指针):弱化成指针(sizeof()=4,和其数组内的基本类型没有关系了),必须添加一个参数(形参)表示数组的大小
实参:数组名(传递数组首元素的地址),数组元素(个数)
参数缺省:一般函数声明时,给形参一个缺省值
缺省顺序:从右到左(只有右边的参数缺省,左边的参数才能缺省)
传参顺序:从左到右(当两个形参都有缺省值,但又传入了一个参数,那这个参数赋值给左边的形参)
函数重载(C++):函数名相同,参数不同
参数不同:个数不同,类型不同(一一对应比较),顺序不同
函数重载二义性:调用不明确
1.参数类型不匹配:给实参类型强转(和形参一致:注意只能从低精度转到高精度)
2.参数缺省:解决方法只能是参数不缺省
函数的返回值:指针
函数与指针:函数有连续内存的,函数名是首地址
函数指针:指向函数的指针
定义:返回值类型(*指针变量名)(形参表)
(用这个指针调用函数,称为回调函数)
指针函数:函数的返回值是指针
注意:指针函数不能返回栈区的内存(普通局部变量的内存)
函数的返回值:引用
注意:不能返回栈区的变量(局部变量的内存在函数调用结束时被回收)
函数调用可以作为左值(赋值运算符),此时运用的是引用定义里面的的别名(即变量名)
参数形参必须要是指针类型(或者引用)时,但是又不需要通过指针去修改指向内存中的值,该指针最好定义为常量指针(常量引用)加const
变量的存储类别
变量从变量作用域(空间角度)分全局变量和局部变量
从变量生存期(时间角度)分静态存储方式和动态存储方式
静态存储方式:程序运行期间由系统分配固定的存储空间的方式
动态存储方式:程序运行期间根据需要进行动态的分配存储空间的方式
内存用户区分为: 程序区,静态存储区,动态存储区
数据 存放在 静态和动态存储区;全局变量存放在 静态存储区
程序一开始执行,上述两者就已经被分配固定的存储单元
函数形参,自动变量,函数调用时的现场保护和返回地址存放在 动态存储区
以上数据在函数开始调用分配动态存储空间,函数结束释放空间
C中的变量和函数有两个属性:数据类型和数据的存储类别
存储类别:指数据在内存中的存储的方式。分为4中:
auto自动的,static静态的,register寄存器的,extern外部的
auto变量
函数中的局部变量,如果没有专门声明为static存储类别,则都是动态地分配存储空间的,数据存储在动态存储区中。这类局部变量称为自动变量,用关键字auto作存储类别的声明。
一般auto可省略,隐含为“自动存储类别”,属于动态存储方式
用static声明局部变量
有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即占用存储单元不释放。就必须用关键字static进行声明,定义为“静态局部变量”。static属于静态存储类别
static变量只赋初值一次,之后保留上次函数调用结束的值
register变量
对已一些使用频繁的局部变量,C允许其存放在CPU的寄存器中,需要时直接从寄存器中取出参加运算,不必再到内存中区存取,,提高效率。这样的变量叫做寄存器变量,用关键字register声明。
只有局部自动变量和形参可以作为寄存器变量。属于动态存储类别
用extern声明外部(全局)变量
用extern声明外部变量,是为了扩展变量的作用域
用static声明外部(全局)变量
用static声明外部变量,为了限制外部变量的作用域,只能在本文件中使用,称为静态外部变量