第07章 函数
<c++ primer plus>第六版
7 函数
7.1 复习函数的基本知识
没有返回值的函数:
void FunctionName(parameterList)
{
statments
return; //optional
}
有返回值的函数
typeName FunctionName(parameterList)
{
statments
return value; //value的数据类型为TypeName.
}
7.2 函数参数和按值传递
7.3 函数和数组
将数组作为函数的参数
给函数传递常规变量时, 函数将使用变量的拷贝, 但传递数组时, 函数将使用原数组(函数得到的是数组地址).
优点: 节省复制整个数组所需的时间和内存.
缺点: 增加了破坏原始数据的风险(可以通过const限定符规避).
注意, 需要同时传递元素个数, 因为函数得到的是数组的地址, 对这个地址使用sizeof, 得到的是地址的长度, 而不是数组长度.
参数传递本质上是赋值, 将一块内存的数据复制到另一块内存上.
c/c++禁在函数调用时传递数组内容, 而是强制传递数组指针, 但对struct和object没有限制.
基本类型: char, int, float等.
聚合类型: 数组, 结构体, 类. 它们由基本类型组合而成. 也称为复杂类型/构造类型.
可以使用引用传递聚合类型数据.
#include<iostream>
const int ArraySize=8;
//函数第一个参数是数组, 也可以写做
//int sum_arr(int arr[], int n);
//在C++中, 当且仅当用于函数原型或函数头中时, int * arr和int arr[]的含义相同
int sum_arr(int * arr, int n);
int main()
{
using namespace std;
int cookies[ArraySize] = {1,2,4,8,16,32,64,128};
int sum = sum_arr(cookies, ArraySize); //直接传递数组名, 实际传递的是第0元素的地址&cookies[0]
cout << "Total count: " << sum << endl;
return 0;
}
int sum_arr(int arr[], int n) //函数得到的是数组地址, 所以函数内部可以修改数组内容.
{
int total = 0;
for (int i=0; i<n; i++)
{
total += arr[i];
}
return total;
}
//使用const修饰传入的数组, 可以防止函数无意中修改数组内容.
void show_array(const double ar[], int n);
7.4 函数和二维数组
7.10 函数指针
函数的地址是存储其机器语言代码的内存的开始地址.
使用函数地址就可以用来传递函数.
函数名即函数的地址, 如果函数名后加了括号, 就是函数调用.
double pam(int); //函数原型, 返回值类型为double
double (*pf)(int); //pf是一个指针, 指向函数, 该函数返回值为double
pf = pam; //pf现在指向pam()函数
double x = pam(4); //使用函数名调用函数.
double y = (*pf)(5); //使用指针调用函数.
double z = pf(5); //仍然是使用指针调用函数, 但无法看出是通过指针调用的.
注意 double *pf(int), 表示pf()是一个函数, 它的返回值是指针, 该指针指向double类型.
7.10.4 使用typedef进行简化
typedef double real; //给double取个别名就real.
typedef const double *(p_fun)(const double *, int); //p_fun就成为一个类型名
p_fun p1 = f1; //p1指向f1()function
===================================
函数定义分成两部分: 函数原型, 函数体:
//函数原型, 这时参数变量名可以省略, 只保留变量类型.
返回值类型 函数名(int, int);
//实际函数的定义
返回值类型 函数名(参数声明){
函数体;
return 表达式;
}
//内联函数(inline function)
定义方法:在函数定义处增加inline关键字
inline void swap(int *a, int *b){
语句;
}
作用: 在编译时, 将对该函数的调用改为函数体, 消除函数调用的开销. 一般将短小的函数声明为inline function.
注意: inline关键字添加在函数定义的地方, 不能添加在函数声明的地方(会被忽略).
//函数重载(Function Overloading)
多个函数可以拥有相同的名字, 只要它们的参数列表不同就可以;
参数列表不同包括: 参数类型不同, 参数个数不同, 参数顺序不同;
函数重载原理: 编译时要根据参数列表对函数进行重命名, void SWAP(int a, int b)会重命名为_SWAP_int_int, 函数调用时根据参数匹配编译后的函数;