一. 函数的概念:
1. 将一些大的或者是功能相同的程序分割成一个个程序块, 在使用的时候可以直接调用, 这种程序块就称为函数.
2. 函数的作用:
①. 函书是构成程序的基本单元.
②. 函数的使用可以省去重复代码的编写.
③. 函数使得程序更加模块化, 从而有利于程序的阅读.修改和完善.
3. 函数的分类:
(1). 按函数定义的角度分为:
①. 库函数: 由C++系统提供, 用户无须定义, 只需在程序前包含有该函数原形的头文件即可在程序中调用.
②. 用户自定义函数: 由用户按需要写的函数.
(2). 按函数的返回结果角度分:
①. 有返回值函数.
②. 无返回值函数.
(3). 按函数间数据通信方式分:
①. 无参函数: 函数定义. 函数说明及函数调用中均不带参数.
②. 有参函数: 在函数定义及函数说明时都有参数(形参), 在函数调用时也给出参数(实参).
※ main()函数是主函数, 它可以调用其他函数, 而不允许被其他函数调用.
(4). 函数的一些约定:
①. 函数不能嵌套定义, 要另外写.
②. 允许嵌套调用(在一个函数中调用另一个函数).
③. 允许递归调用(在函数中调用它自己本身).
④. C++源程序必须有, 也只能有一个主函数main().
4. 函数的几种形式:
(1). void f() ; // 函数声明(原形)
(2). void f()
{
….; // 函数定义(实现)
}
(3).f() ; // 函数调用
二. 函数的定义:
※ 说明: 返回值类型: 函数返回给调用者的数据的类型.
函数名: 是由用户定义的标识符, 它的命名规范为:
①. 首字母必须大写.
②. 要求用大小写字母组合规范函数命名, 即每个单词的首字母也大写.
③. 最好用下划线进行间隔, 例:
intSum( int _nNum1, int_nNum2 ) // int后有空格.
{
return(_nNum1 + _nNum2 ) ;
}
1. 无参函数的定义:
格式:
返回值类型 函数名(void) // void可不填.
{
语句块; // 函数体.
}
2. 有参函数的定义:
格式:
返回值类型 函数名(形式参数列表)
{
语句块; // 最后一定要有return(..)作为结尾.
}
三. 函数的参数:
函数的参数分为形参(形式参数)和实参(实际参数)两种.
1. 形参出现在函数定义中,并在整个函数体内都有效, 当该函数结束后不能使用.
2. 实参出现在主调函数中, 进入被调函数后, 实参变量不能使用.
3. 形参和实参具有以下特点:
(1). 实参和形参在数量上, 类型上, 顺序上应严格一致, 否则会发生”类型不匹配”的错误.
(2). 形参变量只有在被调用时才分配内存单元, 只有在函数内部有效, 函数结束后不能再使用.
(3). 实参和形参占据不同的存储单元.
(4). 函数默认采用值传递, 即实参的值单向传递给形参, 实参的值并不改变(无论形参怎么改).
(5). 实参可以是常量.变量.表达式甚至是函数, 但是在传递给函数前, 必须有确定的值.
※ 理解形参只在函数内部有效:
void Swap( int_a, int _b )
{
int temp = _a ;
_a = _b ;
_b= temp ;
}
int main( argc, char*argv[] ) // 此运算得出来的结果为”x: 10 y:20”
{ // 因为形参只在函数内部有效, 所以无论形参怎么互相赋值, 都不会改变实参的值.
int x = 10 ;
int y = 20 ;
Swap( x, y) ;
printf( “x=%d, y=%d\n”, x, y ) ;
}
四. 函数的返回值:
定义: 是指函数被调用之后, 被调用的函数返回给主调函数的值.
在使用函数返回值的时候应注意以下几点:
1. 它是通过return语句返回主调函数的, 以下是几种方式:
return; 在无返回值函数中使用.
return(常量); 例如: return 100; 或return “OK”;
return(变量); 例如: return a ;
return(表达式); 例如: return a*b ;
return(计算语句); 例如: return( a>b? a:b ) ;
2. 在函数中允许有多个return语句, 但每次调用只能有一个return语句被执行, 只能有一个返回值. 例:
int max( int_a, int _b )
{
if( _a > _b )
{
return _a ;
} // 如果没有下面的else, 就会报警告, 因为函数没有return作为结束.
else
{
return _b ;
}
}
语句块可以优化成:
if( _a > _b )
{
return _a ;
}
return _b ;
最简单的方法是用三目运算的条件表达式: ( a>b ? a:b )
3. 函数返回值类型和函数定义时的返回值类型应保持一致, 如果不一致, 则以函数定义时为准, 自动进行类型转换, 例:
int Sum( int_value )
{
return _value*10.5; // 返回结果为10; 丢失精度.
}
4. 无返回值的函数, 返回值可以明确定义为”空类型”, 但是不能不写返回值类型, 类型为”void”. 返回值可以不写, 也可以写”return ;”
5. 当在函数中使用return语句返回后, 其后面的语句将不会被执行.
五. 函数的声明及调用.
1. 声明格式: 返回值类型 函数名(形式参数列表)
或者是
返回值类型 函数名(形参类型, 形参类型,…)
例如: void f() ;
(1). 函数可以被多次声明, 但只能定义一次.
注: 函数声明里有这种情况:
intMax( int _a, int_b ) ;
可以写成
int Max( int, int ) ;
注: 定义的时候一定不能省.
(2).函数的声明就是函数的原形.
※ 要学会看函数的原形, 从原形里知道函数的用法.
(3). 当函数写在main下面的时候, 就要在main函数前面进行声明, 如果写在前面, 就不需要声明(也可以写).
2. 函数的调用格式:函数名(实际列表参数);
例如: f() ;
3. 函数的嵌套调用: C语言和C++中不允许嵌套的函数定义, 但允许在一个函数中调用另一个函数, 叫嵌套调用.
函数与变量
一. 程序的内存区域:
1. 代码区: 存放程序的代码和和各个函数的代码块.
2. 数据区: 存放程序的全局变量和静态变量及常量.(由系统自动管理)
3. 栈区: 存放程序的局部变量. 用于存放非常小的数据, PC上1M左右, 手机上1K左右. 它存放的数据为:
①. 临时变量.
②. 函数的形参.
③. 8字节长度左右的数据.
4. 堆区: 存放动态数据, 需要用指针访问. 最大支持2G(PC), 手机上为2M.
※ 栈区和堆区的区别:
(1). 堆区的内存由自己申请自己释放, 如果申请了不释放, 就叫内存泄漏;
栈区的内存是由系统自动分配的, 没有内存泄漏问题.
(2). 栈区放非常小的数据, 堆区放比较大的数据.
(3). 堆区相比灵活性更高, 而栈区则效率更高.
(4). 栈区不会出现碎片, 堆区会出现.
(5). 就内存位置来说, 栈区是顺序分配的, 堆区是随机分配的.
二. 全局与局部变量:
1. 全局变量: 在函数外部定义的变量, 不属于哪一个函数, 而是属于一个源程序文件.
2. 局部变量: 也称为内部变量, 现默认所有非全局变量都为局部变量.
3. 静态全局变量:
格式: staticint a = 0 ;
4. 静态局部变量: 如果希望在一个函数结束后保留在其内部的局部变量的值, 就用”static”进行声明, 称为静态局部变量.
格式: staticint b = 10 ;
※ 比较几种变量的区间.生命周期.作用域及初始值:
类型 | 区间 | 生命周期 | 作用域 | 初始值 |
全局变量 | 数据区 | main函数执行之前被创建, 在整个程序结束之前被回收. | 从定义开始到文件结束的所有函数; 在同一个项目中其他文件都可以使用. | 0 |
静态全局变量(static全局变量) | 数据区 | 同上 | 从定义开始到文件结束的所有函数; 其他项目中的文件不可以使用. | 0 |
局部变量 | 栈区 | 从程序被调用时被创建, 在该程序块结束前被回收. | 从定义开始到大括号结束.即只能在代码块中的语句使用. | 随机值 |
静态局部变量(static局部变量) | 数据区 | 函数不被调用时不创建, 第一次调用的时候被创建, 之后再用就不会被创建了(可以忽略不看了, 只被初始化一次). 在整个程序结束前被回收. | 同上 | 0 |
以上表理解全局函数, 静态全局函数(规则一样). 注:没有局部函数的概念, 因为函数不能嵌套.
三. 杂项:
1. 程序在执行的时候, 先从当前的代码块中寻找, 找不到再到外面找, 找不到再到全局变量去找, 再到别的文件去找, 还是找不到就报错.
2. 如果在一个程序块里要访问一个全局变量, 就在变量前面加双冒号”::”(局部变量重名时使用)
例: staticin a = 0 ;
printf( “%d\n”, ::a ) ;
3. const int SIZE = 100 ;
写在函数里就占用栈区, 写在函数外就占数据区(相当于全局变量)
4. 以下例子为说明局部变量的作用域的, 输出结果为”10, 0”.
int main()
{
inta = 0 ;
char ch[100]= ”” ;
while(1)
{
int a = 10 ;
printf( “%d\n”, a ) ;
if( 10 == a )
{
break ;
}
}
printf(“%d\n”, a ) ;
return0 ;
}