C++ Primer 笔记 - 第7章 函数
第7章 函数——C++的编程模块
定义函数
- 可以将函数分成两类:没有返回值的函数和有返回值的函数
- 对于有返回值的函数,必须有返回语句
- C++对于返回值的类型有一定限制:不能是数组,但可以是其他任何类型——整数、浮点数、指针、结构体和对象。
- 函数的返回值过程:
- 函数通过将返回值复制到指定的CPU寄存器或内存单元中来将值返回。
- 调用程序将查看该内存单元。
- 函数在执行返回语句后结束。如果函数包含多条返回语句,则函数在执行遇到的第一条返回语句后结束
函数原型和函数调用
1 |
|
- 原型描述了函数到编译器的接口,也就是说,它将返回值的类型以及参数的类型和数量告诉了编译器。
- 原型的功能:
- 编译器正确处理函数的返回值
- 编译器检查使用的参数数目是否正确
- 编译器检查使用的参数类型是否正确,如果不正确,则转换成正确的类型(如果可能的话)。
- 仅当有意义时,原型化才会导致类型转换。
- 在编译阶段进行的原型话被称为静态类型检查(static type checking)
函数如何使用指针来处理数组
- C++和C一样,也将数组名视为指针。C++将数组名解释为其第一个元素的地址。
- 规则的例外:
- 数组声明使用数组名来标记存储位置
- 对数组名使用
sizeof将得到整个数组的长度(以字节为单位) - 将地址运算符
&用于数组名时将返回整个数组的地址。
- 为防止函数无意中修改数组的内容,可在声明形参时使用关键字
const- 这并不意味着原始数组必须是常量,而只是意味着不能在函数中使用数组指针变量来修改这些数据。(如果尝试修改,则编译器会报错)
指针和 const
- 可以用两种不同的方式将
const关键字用于指针。- 让指针指向一个常量对象,这样可以防止使用该指针来修改所指向的值
- 将指针本身声明为常量,这样可以防止改变指针指向的位置
1 | int age = 39; |
pt指向一个const int,因此不能使用pt来修改这个值。- 可以直接通过
age变量来修改age的值,但不能使用pt指针来修改它
1 | *pt = 20; // INVALID bevause pt points to a const int |
- 不能将
const变量的地址赋给常规指针
1 | const fload g_earth = 9.80; |
- 第一种情况:既不能用
g_earth来修改值 9.80,也不能使用pe来修改。C++禁止第二种情况,因为不能用pm来修改g_moon
- 如果涉及一级间接关系,则将非
const指针赋值给const指针是可以的
1 | int age = 39; // age++ is a valid operation |
1 | const int **pp2; |
- 仅当只有一层间接关系(如指针指向基本数据类型时),才可以将非
const地址或指针赋值给const指针。
- 禁止将常量数组的地址赋给非常量指针意味着不能将数组名作为参数传递给使用非常量形参的函数。
1 | const int cArr = {1, 2, 3, 4}; |
- 禁止将指针参数声明为指向常量数据的指针有两条理由:
- 可以避免由于无意间修改数据而导致编程错误
- 使用
const使得函数能够处理const和非const实参,否则只能接受非const数据。如果条件允许,则应将指针形参声明为指向const的指针。
函数和结构
- 定义结构体
1 | struct travel_time { |
其他定义结构体的例子
1 | struct polar { |
- while 循环同时读取两个变量
1 | while (cin >> rplace.x >> rplace.y) { |
cin是istream类的一个对象。抽取运算符>>被设计成使得cin >> rplace.x也是一个istream对象。
传递结构的地址 (结构体指针)
假设要传递结构的地址而不是整个结构以节省时间和空间,则需要修改函数:
调用函数时,将结构的地址
&pplace而不是结构本省pplace传递给函数将形参声明为指向
polar的指针,即polar*类型。由于函数不应该就该结构,因此使用了const修饰符形参是指针而不是结构,因此应使用间接成员运算符
->,而不是.1
2
3
4
5
6
7
8
9
10
11
12
13void show_polar (const polar* pda) {
using namespace std;
const double Rad2deg = 57.29577951;
cout << "distance = " << pad->distance;
cout << ", angle = " << pad->angle * Rad2deg;
cout << " degrees\n";
}
int main() {
...
show_polar(&pplace);
}函数使用的是指针,是的函数能对原始结构进行操作
函数和 string 对象
- 函数读取 string 对象数组
1 | int main() { |
函数和 array 对象
array对象的定义
1 | std::arrray<double, 4> expenses; |
递归
函数指针
- 与数据项相似,函数也有地址。函数的地址是存储其机器语言代码的内存的开始地址。
- 可以编写将另一个函数的地址作为参数的函数。这样第一个函数就能找到第二个函数,并运行它。
声明函数的指针
1 | double pam(int); // 函数原型 |
函数的传递 - 函数的地址与函数的返回值
1 | process(think); // passes address of think() to process() |
函数指针的声明和赋值
1 | double pam(int) |
- 使用指针来调用函数
1 | double best(int) |
1 | double pam(int); |
- 函数指针的数组
1 | const double * (*pa[3]) (const double *, int) = {f1, f2, f3}; |
- 这里不能使用
auto,自动类型推断只能用于单值初始化,而不能用于列表初始化
深入探讨函数指针
1 | const double * f1(const double ar[], int n); |
这里
p1,p2都调用了指向的函数。在每条cout语句中,前半部分显示存储函数返回值的地址。后半部分为存储在这些地址里的实际返回值。指向函数数组的指针初始化
1 | const double * (*pa[3]) (const double *, int) = {f1, f2, f3}; |
用 typedef 进行简化
1 | typedef double real; // make real another name for double |
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Comment


