C++ Primer 第6章 函数 学习笔记
2017-06-29 14:41
218 查看
1. 编写+调用函数
a) 一个典型的函数定义包括以下部分:返回类型、函数名字、由0个或多个形参组成的列表以及函数体。
b) 我们通过调用运算符执行函数,它作用于一个表达式,该表达式是函数或者指向函数的指针。调用表达式的类型就是函数的返回类型
c) 函数的调用完成两项工作:一是用实参初始化函数对应的形参,二是将控制权转移给被调用函数
d) return语句也完成两项工作:一是返回return语句中的值,二是将控制权从被调函数转移回主调函数
2. 形参和实参
a) 实参是形参的初始值。第一个实参初始化第一个形参,第二个实参初始化第二个形参,以此类推
b) 实参的类型必须与对应的形参类型匹配;且函数有几个形参,我们必须提供相同数量的实参
c) void返回类型表示函数不返回任何值
d) 函数的返回类型不能是数组类型或函数类型,但可以是指向数组或函数的指针
3. 局部对象
a) 形参和函数体内部定义的变量统称为局部变量,仅在函数的作用域内可见
b) 对于普通局部变量对应的对象来说,当函数的控制路径经过变量定义语句时创建该对象,当到达定义所在的块的末尾时销毁它
c) 自动对象是指只存在于块执行期间的对象,形参是一种自动对象:函数开始时为形参申请存储空间,一旦函数终止,形参被销毁
d) 局部静态对象在程序的执行路径第一次经过对象定义语句时初始化,直到程序终止才被销毁,在此期间即使对象所在的函数结束执行也不会对它有影响。可以将局部变量定义成static类型获得这样的对象
4. 函数声明
a) 类似于变量,函数名字也必须在使用之前声明。
b) 函数只能定义一次,但可以声明多次
c) 函数的返回类型、函数名、形参类型描述了函数的借口
5. 参数传递
a) 如果形参是引用类型,它将绑定到对应的实参上;否则,将实参的值拷贝后赋给形参
b) 当形参是引用类型时,引用形参是它绑定的对象的别名;引用形参是它对应的实参的别名(传引用参数)
c) 当实参的值被拷贝给形参时,形参和实参是两个相互独立的对象(传值参数)
6. 传值参数
a) 当初始化一个非引用类型的变量时,初始值被拷贝给变量。传值函数对形参做的所有操作都不会影响实参
b) 指针的行为和其他非引用类型:当执行指针拷贝操作时,拷贝的是指针的值。拷贝之后,两个指针是不同的指针
7. 传引用参数
a) 如果函数无须改变引用形参的值,最好将其声明为常量引用
b) 拷贝大的类类型对象或者容器对象比较低效,最好通过引用形参访问该类型的对象
c) 一个函数只能返回一个值,而引用形参为一次返回多个结果提供了有效的途径
下面的栗子是一个名为find_char的函数,它返回在string对象中某个制定自负第一次出现的位置及字符出现的总次数
8. 数组形参
a) 不允许拷贝数组(3.5.1节,102页),且使用数组时(通常)会将其转换成指针(3.5.3,105页)
b) 因为数组会被转换成指针,所以当我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针
c) 管理数组实参有三种常用的方法:
1) 使用标记指定数组长度:要求数组本身包含一个结束标记,使用这种方法的典型示例是C风格字符串。C风格字符串存储在字符数组中,并且在最后一个字符后面跟着一个空字符。函数在处理C风格字符串时遇到空字符停止
2) 使用标准库规范:传递指向数组首元素和尾后元素的指针
3) 显式传递一个表示数组大小的形参:专门定义一个表示数组大小的形参
d) 数组引用形参:形参可以是数组的引用,引用形参绑定到对应的实参上,也就是绑定到数组上
e) 数组的大小对函数的调用没有影响
9. return语句(终止当前正在执行的函数并将控制权返回到调用该函数的地方)
return;
return expression;
a) 无返回值函数
1) 只能用在返回类型是void的函数中
2) void函数如果想在它的中间位置提前退出,可以使用return语句。这种用法类似于用break语句退出循环
3) 一个返回类型是void的函数也能使用return语句的第二种形式,但语句的expression必须是另一个返回void的函数
b) 有返回值函数
1) 只要函数的返回类型不是void,则该函数内的每条return语句必须返回一个值
2) return语句返回值的类型必须与函数的返回类型相同,或者能隐式地转换成函数的返回类型
c) 不要返回局部对象的引用或指针,因为函数终止意味着局部变量的引用将指向不再有效的内存区域
10. 函数重载
a) 如果同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载函数
b) 这些函数接受的形参类型不一样,但执行的操作非常类似。调用这些函数时,编译器会根据传递的实参类型推断想要的是哪个函数
c) 对于重载的函数来说,它们应该在形参数量或形参类型上有所不同
d) 不允许两个函数除了返回类型外其他所有的要素都相同
11. 调用重载的函数
a) 在函数匹配过程当中,我们
b077
把函数调用与一组重载函数中的某一个关联起来。编译器首先将调用的实参与重载集合中每一个函数的形参进行比较,然后根据比较的结果决定到底调用哪个函数
b) 当调用重载函数时有三种可能的结果:
1) 编译器找到一个与实参最佳匹配的函数,并生成调用该函数的代码
2) 找不到任何一个函数与调用的实参匹配,编译器发出无匹配的错误信息
3) 有多于一个函数可以匹配,但是每一个都不是明显的最佳选择,发生错误,成为二义性调用
12. assert预处理宏
a) 可以有选择地执行调试代码
b) 预处理宏其实是一个预处理变量
c) assert宏使用一个表达式作为它的条件:assert(expr); 首先对expr求值。如果expr为假(0),assert输出信息并终止程序的执行。如果为真,assert什么也不做
d) assert宏定义在cassert头文件中
e) 含有cassert头文件的程序不能再定义名为assert的变量、函数或者其他实体
a) 一个典型的函数定义包括以下部分:返回类型、函数名字、由0个或多个形参组成的列表以及函数体。
b) 我们通过调用运算符执行函数,它作用于一个表达式,该表达式是函数或者指向函数的指针。调用表达式的类型就是函数的返回类型
c) 函数的调用完成两项工作:一是用实参初始化函数对应的形参,二是将控制权转移给被调用函数
d) return语句也完成两项工作:一是返回return语句中的值,二是将控制权从被调函数转移回主调函数
int fact(int val){ int ret=1; while(val>1) ret*=val--; return ret; }
2. 形参和实参
a) 实参是形参的初始值。第一个实参初始化第一个形参,第二个实参初始化第二个形参,以此类推
b) 实参的类型必须与对应的形参类型匹配;且函数有几个形参,我们必须提供相同数量的实参
c) void返回类型表示函数不返回任何值
d) 函数的返回类型不能是数组类型或函数类型,但可以是指向数组或函数的指针
3. 局部对象
a) 形参和函数体内部定义的变量统称为局部变量,仅在函数的作用域内可见
b) 对于普通局部变量对应的对象来说,当函数的控制路径经过变量定义语句时创建该对象,当到达定义所在的块的末尾时销毁它
c) 自动对象是指只存在于块执行期间的对象,形参是一种自动对象:函数开始时为形参申请存储空间,一旦函数终止,形参被销毁
d) 局部静态对象在程序的执行路径第一次经过对象定义语句时初始化,直到程序终止才被销毁,在此期间即使对象所在的函数结束执行也不会对它有影响。可以将局部变量定义成static类型获得这样的对象
#include <iostream> using namespace std; size_t count_calls(){ static size_t ctr=0; return ++ctr; } int main(){ for(size_t i=0;i!=10;++i) cout<<count_calls()<<endl; return 0; } 输出结果是1~10
4. 函数声明
a) 类似于变量,函数名字也必须在使用之前声明。
b) 函数只能定义一次,但可以声明多次
c) 函数的返回类型、函数名、形参类型描述了函数的借口
5. 参数传递
a) 如果形参是引用类型,它将绑定到对应的实参上;否则,将实参的值拷贝后赋给形参
b) 当形参是引用类型时,引用形参是它绑定的对象的别名;引用形参是它对应的实参的别名(传引用参数)
c) 当实参的值被拷贝给形参时,形参和实参是两个相互独立的对象(传值参数)
#include <iostream> using namespace std; void reset(int *p){ *p=0; p=0; } int main(){ int i=42; reset(&i); cout<<i<<endl; return 0; } 输出0
6. 传值参数
a) 当初始化一个非引用类型的变量时,初始值被拷贝给变量。传值函数对形参做的所有操作都不会影响实参
b) 指针的行为和其他非引用类型:当执行指针拷贝操作时,拷贝的是指针的值。拷贝之后,两个指针是不同的指针
#include <iostream> using namespace std; void swap(int *a,int *b){ int c=*a; *a=*b; *b=c; } int main(){ int i=42,n=56; swap(&i,&n); cout<<i<<" "<<n; return 0; } 输出56 42
7. 传引用参数
a) 如果函数无须改变引用形参的值,最好将其声明为常量引用
b) 拷贝大的类类型对象或者容器对象比较低效,最好通过引用形参访问该类型的对象
c) 一个函数只能返回一个值,而引用形参为一次返回多个结果提供了有效的途径
下面的栗子是一个名为find_char的函数,它返回在string对象中某个制定自负第一次出现的位置及字符出现的总次数
#include <iostream> using namespace std; string::size_type find_char(const string &s,char c,string::size_type occurs){ auto ret=s.size(); //第一次出现的位置 occurs=0; //设置表现出现次数的形参的值 for(decltype(ret) i=0;i!=s.size();++i){ if(s[i]==c){ if(ret==s.size()) ret=i; //记录c第一次出现的值 ++occurs; //将出现的次数加1 } } return ret; //出现次数通过occurs隐式地返回 } //给函数传入一个额外的引用实参保存字符出现的次数
8. 数组形参
a) 不允许拷贝数组(3.5.1节,102页),且使用数组时(通常)会将其转换成指针(3.5.3,105页)
b) 因为数组会被转换成指针,所以当我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针
void print(const int*); void print(const int[]); void print(const int[10]); //这三个函数是等价的,每个函数的唯一形参都是const int*类型
c) 管理数组实参有三种常用的方法:
1) 使用标记指定数组长度:要求数组本身包含一个结束标记,使用这种方法的典型示例是C风格字符串。C风格字符串存储在字符数组中,并且在最后一个字符后面跟着一个空字符。函数在处理C风格字符串时遇到空字符停止
2) 使用标准库规范:传递指向数组首元素和尾后元素的指针
void print(const int *beg, const int *end){ //输出beg到end之间的所有元素 while(beg!=end) cout<<*beg++<<endl; //输出当前元素并将指针向前移动一个位置 }
3) 显式传递一个表示数组大小的形参:专门定义一个表示数组大小的形参
void print(const int ia[], size_t size){ //const int ia[]等价于const int *ia //size表示数组的大小,将它显式地传给函数用于控制对ia元素的访问 for(size_t i=0;i!=size;++i) cout<<ia[i]<<endl; }
d) 数组引用形参:形参可以是数组的引用,引用形参绑定到对应的实参上,也就是绑定到数组上
void print(int (&arr)[10]){ for(auto elem:arr) cout<<elem<<endl; }&arr两端的括号必不可少
f(int&arr[10]) //错误:将arr声明成了引用的数组 f(int (&arr)[10]) //正确:arr是具有10个整数的整形数组的引用
e) 数组的大小对函数的调用没有影响
9. return语句(终止当前正在执行的函数并将控制权返回到调用该函数的地方)
return;
return expression;
a) 无返回值函数
1) 只能用在返回类型是void的函数中
2) void函数如果想在它的中间位置提前退出,可以使用return语句。这种用法类似于用break语句退出循环
void swap(int &v1, int &v2){ if(v1==v2) return; //如果两个值是相等的,不需要交换,直接退出 int tmp=v2; v2=v1; v1=tmp; //不需要显式的return语句 }
3) 一个返回类型是void的函数也能使用return语句的第二种形式,但语句的expression必须是另一个返回void的函数
b) 有返回值函数
1) 只要函数的返回类型不是void,则该函数内的每条return语句必须返回一个值
2) return语句返回值的类型必须与函数的返回类型相同,或者能隐式地转换成函数的返回类型
c) 不要返回局部对象的引用或指针,因为函数终止意味着局部变量的引用将指向不再有效的内存区域
10. 函数重载
a) 如果同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载函数
b) 这些函数接受的形参类型不一样,但执行的操作非常类似。调用这些函数时,编译器会根据传递的实参类型推断想要的是哪个函数
c) 对于重载的函数来说,它们应该在形参数量或形参类型上有所不同
d) 不允许两个函数除了返回类型外其他所有的要素都相同
11. 调用重载的函数
a) 在函数匹配过程当中,我们
b077
把函数调用与一组重载函数中的某一个关联起来。编译器首先将调用的实参与重载集合中每一个函数的形参进行比较,然后根据比较的结果决定到底调用哪个函数
b) 当调用重载函数时有三种可能的结果:
1) 编译器找到一个与实参最佳匹配的函数,并生成调用该函数的代码
2) 找不到任何一个函数与调用的实参匹配,编译器发出无匹配的错误信息
3) 有多于一个函数可以匹配,但是每一个都不是明显的最佳选择,发生错误,成为二义性调用
12. assert预处理宏
a) 可以有选择地执行调试代码
b) 预处理宏其实是一个预处理变量
c) assert宏使用一个表达式作为它的条件:assert(expr); 首先对expr求值。如果expr为假(0),assert输出信息并终止程序的执行。如果为真,assert什么也不做
d) assert宏定义在cassert头文件中
e) 含有cassert头文件的程序不能再定义名为assert的变量、函数或者其他实体
相关文章推荐
- c++ primer 第五版学习笔记-第6章-返回数组指针的函数和函数指针的数组
- C++ Primer 学习笔记——函数(二)
- C++ Primer学习笔记之第六章--函数
- c++ primer 学习笔记(2): 函数 function
- 《python基础教程(第二版)》学习笔记 函数(第6章)
- C++ Primer 学习笔记_23_函数(续2) --局部对象、内联函数、类的成员函数
- Python基础教程 第6章: 抽象(函数) 学习笔记
- C++ primer第二次阅读学习笔记(第6章)
- C++ Primer 学习笔记——函数(三)
- C++ Primer 学习笔记_24_函数(续3) --重载函数、指向函数的指针
- C++ Primer 学习笔记12 函数(return语句、函数声明、局部对象、内联函数、类的成员函数、重载函数)
- C++ Primer学习笔记——$14 操作符重载、函数对象及类类型转换
- 《Lua程序设计》第6章 深入函数 学习笔记
- C++ Primer 学习笔记_86_模板与泛型编程 -满载与函数模板
- C++ Primer 学习笔记:标准库定义的函数对象
- C++ primer学习笔记_6_函数---函数定义、参数传递
- C++ Primer 学习笔记_62_重载操作符与转换 --调用操作符和函数对象
- C++ Primer 学习笔记11 函数(函数调用、引用形参、非引用形参)
- 【C++ Primer 学习笔记】chapter7 函数
- C++ Primer学习笔记2--c++异常处理和函数