第7章 函数——C++的编程模块
- 函数的基本知识
- 函数原型
- 按值传递函数参数
- 设计处理数组的函数
- 使用const指针参数
- 设计处理文本字符串的函数
- 设计处理结构的函数
- 设计处理string对象的函数
- 调用自身的函数(递归)
- 指向函数的指针
7.1 复习函数的基本知识
7.1.1 定义函数
C++函数返回值不能是数组(但可以将数组作为结构或对象的组成部分来返回)。
7.1.2 函数原型和函数调用
原型描述了函数到编译器的接口。
C++的编程风格是将main()放在最前面,因为它通常提供了程序的整体结构。
在编译阶段进行的原型化被称为静态类型检查(static type checking),它可捕获许多在运行阶段难以捕获的错误。
7.2 函数参数和按值传递
实参argument,形参parameter,按值传递会创建变量的副本。
7.2.1 多个参数
7.2.2 另一个接受两个参数的函数
7.3 函数和数组
int sum_arr(int arr[], int n); // arr = array name, n = size
7.3.1 函数如何使用指针来处理数组
在这里数组名视为指针,它和int* arr的含义相同。但这里数组声明使用数组名来标记存储位置,对数组名使用sizeof将得到整个数组的长度。
arr[i] == *(arr + i); // values in two notations
&arr[i] == arr + i; // addresses in two notations
7.3.2 将数组作为参数意味着什么
并没有将数组内容传递给函数,而是将数组的位置(地址)、包含的元素种类(类型)、元素数目(n变量)提交给函数。
传递常规变量时,函数将使用该变量的拷贝;但传递数组时,函数将使用原来的数组。
其实也是按值传递,但传的是地址,而不是内容。
将数组类型和元素数量都告诉数组处理函数,请通过两个不同的参数来传递他们:
void fillArray(int arr[], int size); // prototype
void fillArray(int arr[size]); // No -- bad prototype, 不要这样
因为传的是个指针,指针本身并没有指出数组的长度。 sizeoff arr结果是4,而不数组长度。
7.3.3 更多数组函数示例
为防止函数无意中修改数组的内容,可在声明形参时使用关键字const:
void show_array(const double ar[], int n);
7.3.4 使用数组区间的函数
元素区间(range)也是一种给函数提供数组信息的方法:
- 提供数组种类、数组的起始位置、数组中元素数量
- 或者使用元素区间:提供两个指针,一个标识开头,一个标识尾部。
ar, ar + ArSize。ar + ArSize指向数组结尾元素后面的一个位置。end - begin = ArSize。
int sum_arr(const int* begin, const int* end);
int main()
{
int cookies[8] = {1};
sum_arr(cookies, cookies + 8);
}
7.3.5 指针和const
const用于指针的两种用途:
- 让指针指向常量对象,防止使用该指针来修改所指向的值。
- 将指针本身声明为常量,防止改变指针指向的位置。
几种情况
// 可以用const指针指向非const量,但*pt的值为const,不能通过指针来修改指向的量
int age = 39;
const int* pt = &age;
*pt += 1; // 不能,INVALID because pt points to a const int
cin >> *pt; // 不能,INVALID for the same reson
*pt = 20; // 不能,INVALID because pt points to a const int
age = 20; // 可以,VALID because age is not declared to be const
// 可以用const指针指向const量
const float g_earth = 9.80;
const float* pe = &g_earth; // VALID
// 不能用常规指针指向const量。因为不应该用指针来修改const量的值
const float g_moon = 1.63;
float* pm = &g_moon; // INVALID
//
结论是(函数形参)尽可能使用const :
- 这样可以避免由于无意间修改数据
- 使用const使函数能够处理const和非const实参,否则将只能接受非const数据。
- 指向指针的指针不能用const(雾?)
指向const的指针和本身是const的指针:
int sloth = 3;
// 指向const的指针
// 不能修改sloth的值,但能指向别的地方
const int* ps = &sloth; // a pointer to const int
ing sage = 80;
pt = &sage; // okay to point to another location
// const指针
// 能修改sloth的值,但不能指向别的地方
int* const finger = &sloth;
*finger = 99;
7.4 函数和二维数组
int data[3][4] = {{1,2,3,4}, {9,8,7,6}, {2,4,6,8}};
int total = sum(data, 3);
// 函数原型可以是以下两种
// ar2是指针而不是数组,它指向由4个int组成的数组
int sum(int(*ar2)[4], int size);
int sum(int ar2[][4], int size);
int sum(int ar2[][4], int size)
{
int total = 0;
for (int r = 0; r < size; r++) // 行数由变量来确定
{
for (int c = 0; c < 4; c++) // 列数是确定的
{
total += ar2[r][c];
}
}
return total;
}
// 对指针ar2执行两次解除引用,才能得到数据
ar2[r][c] == *(*(ar2 + r) + c) // same thing
// 每层的含义
ar2 // pointer to first row of an array of 4 int,4int数组组成数组的第一行
ar2 + r // pointer to row r (an array of 4 int),4int数组组成数组的第r行
*(ar2 + r) // row r (an array of 4 int, hence the name of an array,
// thus a pointer to the first int in the row, i.e., ar2[r])
// 4int数组组成数组的第r行的值,是一个4int数组(的首元素地址)
*(ar2 + r) + c // pointer int number c in row r, i.e., ar2[r] + c,第r行的4int数组的第c个元素的地址
*(*(ar2 + r) + c) // value of int number c in row r, i.e., ar2[r][c],第r行的4int数组的第c个元素的值
7.5 函数和C风格字符串
7.5.1 将C风格字符串作为参数的函数
将字符串作为参数传递给函数,表示字符串的3种方式(他们都是char指针,也就是char*):
- char数组
- 用引号括起的字符串常量(也称字符串字面值)
- 被设置为字符串的地址的char指针
char ghost[15] = "galloping";
char* str = "galumphing";
int n1 = strlen(ghost); // ghost is &ghost[0]
int n2 = strlen("gamboling"); // address of string
int n3 = strlen(str); // pointer to char
C风格字符串与常规char数组的重要区别是,结束字符。所以不需要将字符串长度作为参数传递给函数,可以在函数内检查每个字符,找到空值字符。
while (*str) // 处理字符串中字符的标准方式
{
...
str++;
}
7.5.2 返回C风格字符串的函数
从后向前填充字符串:
while (n-- > 0)
pstr[n] = c;
7.6 函数和结构
可以当作普通变量来使用,结构名不是结构的地址,要获得地址使用&。
将结构作为参数传递,有三种方式:
- 直接作为参数。缺点是创建了原始结构的副本,增加了内存和速度开销。
- 传结构的地址,然后使用指针来访问结构的内容
- 按引用传递(第8章)
7.6.1 传递和返回结构
当结构比较小时,按值传递。
7.6.2 另一个处理结构的函数示例
数学库cmath,sqrt, atan2, atan(不能区分180之内和之外的角度)
7.6.3 传递结构的地址
void show_polar(const polar* pda);
7.7 函数和string对象
比起数组,string对象和结构更相似。
7.8 函数和array对象
void show(std::array<double, 4> da); // da an object
void fill(std::array<double, 4>* pa); // pa a pointer to an object
7.9 递归
C++不允许main()调用自己。
7.9.1 包含一个递归调用的递归
void recurs(argumentlist)
{
statement1;
if (test)
recurs(arguments);
statements;
}
7.9.2 包含多个递归调用的递归
递归方法有时被称为分而治之策略(divide-and-conquer strategy)
7.10 函数指针
与数据项相似,函数也有地址。
7.10.1 函数指针的基础知识
- 获取函数的地址:函数名(后面不跟参数)
- 声明函数指针:指定函数的返回类型 和 函数的特征标(参数列表)
- double (*pf)(int);
- 使用指针来调用函数:(*pf)(4) 或者 pf(4)
7.10.2 函数指针示例
7.10.3 深入探讨函数指针
略!(P201)
7.10.4 使用typedef进行简化
7.11 总结
- 函数:定义+原型,调用
- 按值传递,使用拷贝
- 数组形参,指针
- C风格字符串char*,string类字符串
- 处理结构与基本类型相同
- 递归,函数指针
7.12 复习题
7.13 编程练习
1 略
2 略
3 略
4 略
5 使用递归
6 数组参数
#include <iostream>
using namespace std;
int Fill_array(double ar[], int size); // 填充数组
void Show_array(const double ar[], int size); // 显示数组
void Reverse_array(double ar[], int size); // 翻转数组
int main()
{
double ar[8];
int numCount = Fill_array(ar, 8);
Show_array(ar, numCount);
Reverse_array(ar, numCount);
Show_array(ar, numCount);
Reverse_array(ar + 1, numCount - 2);
Show_array(ar, numCount);
return 0;
}
int Fill_array(double ar[], int size)
{
printf("Input %d number for make a array:\n", size);
int count = 0;
while (count < size)
{
if (!(cin >> ar[count])) break;
count++;
}
cout << "Done! you input " << count << " number.\n";
return count;
}
void Show_array(const double ar[], int size)
{
cout << "Show_array: ";
for (int i = 0; i < size; i++)
{
cout << ar[i] << " ";
}
cout << endl;
}
void Reverse_array(double ar[], int size)
{
for (int i = 0; i < size / 2; i++)
{
double temp = ar[i];
ar[i] = ar[size - i - 1];
ar[size - i - 1] = temp;
}
}
789略
10 函数指针
#include <iostream>
using namespace std;
double add(double x, double y);
double sub(double x, double y);
double multiply(double x, double y);
double calculate(double x, double y, double (*pf)(double, double));
int main()
{
double (*pf[3])(double, double) = { add, sub, multiply };
cout << "Please input a pair of numbers:";
double x, y;
int count = 0;
while (cin >> x >> y)
{
cout << "res#" << count << ": " << calculate(x, y, pf[count % 3]) << endl;
cout << "Please input a pair of numbers:";
count++;
}
cout << "Done\n";
return 0;
}
double add(double x, double y)
{
return x + y;
}
double sub(double x, double y)
{
return x - y;
}
double multiply(double x, double y)
{
return x * y;
}
double calculate(double x, double y, double (*pf)(double, double))
{
return pf(x, y);
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 cdd@ahucd.cn