函数和二维数组 |
使用二维数组作为参数, 必须指定第二维的维数 – 元素的类型
- 表示arr为一个数组名,而数组的每一个元素也是一个数组, 由2个int组成
- 即arr的类型是指向由2个int组成的数组的指向
- 其中的括号必不可少,因为 int *arr[2]表示由2个指向int的指针组成的数组 – 函数参数不能为数组
- 另一种格式 –
int sum(int arr[][2], int n);
二者含义相同 - 两个原型都指出, arr是指针而非数组,这是至关重要的一点
int sum(int (*arr)[2], int n) { int res = 0; for(int i = 0; i < n; ++i) for(int j = 0; j < 2; ++j) res += arr[i][j]; return res; } int a[3][2] = { {1, 2}, {3, 4}, {5, 6} }; cout << sum(a, 3) << endl;
函数和C风格字符串 |
将字符串作为参数
- 使用 char* (指向char类型的指针) –
void show_str(const char* str);
- 也可使用
void show_str(const char str[]);
void show_str(const char* str) { while (*str) { cout << *str; ++str; } cout << endl; } char str[] = "hello world"; show_str(str);
- 使用 char* (指向char类型的指针) –
将字符串作为返回值
- 返回字符串的地址即可
#include <iostream> using namespace std; char* build_str(char ch, int n) { char* p_str = new char[1+n]; // 虽然p_str在函数结束时会被释放 p_str[n] = '\0'; while(n-- > 0) p_str[n] = ch; return p_str; // 但 new 的内存还在 } int main() { char* str = build_str('d', 10); cout << str << endl; delete [] str; // 所以需要手动delete此内存块 }
函数和结构体 |
像对待基本数据类型一样对待结构体即可
#include <iostream> using namespace std; struct pos { int x, y; }; pos sum_pos(pos a, pos b) { pos res; res.x = a.x + b.x; res.y = a.y + b.y; return res; } int main() { pos m{1, 2}; pos n = {3, 4}; pos r = sum_pos(m, n); cout << r.x << " " << r.y << endl; }
传递结构体的地址 – 以节省时间和空间
pos* sum_pos(const pos* a, const pos* b) { pos* res = new pos; res->x = a->x + b->x; res->y = a->y + b->y; return res; } pos* r = sum_pos(&m, &n); cout << r->x << " " << r->y << endl; delete r;
- 传递地址的话可以将结果作为指针直接放在参数中,而不用返回值
void sum_pos(const pos* a, const pos* b, pos* res) { res->x = a->x + b->x; res->y = a->y + b->y; } pos r; sum_pos(&m, &n, &r); cout << r.x << " " << r.y << endl;
- string对象, array对象 等,都可看作基本类型, 像结构体一样在函数中使用
递归函数 |
- 除了main函数外,函数都可以调用自身
- 一个递归函数必须有递归调用的终点,否则将会无限调用下去
- 每一个递归过程中的函数都是独立的
- 递归的过程与普通函数调用的过程类似
只需将函数里对自己本身的调用也看作是对其他函数的调用(只不过功能相同)即可
// 求n的阶乘 int factorial(int n) { if(n == 1) return 1; // 循环终止条件 return n * factorial(n-1); // 递归 }
// 快速排序 -- O(nlogn) void quick_sort(int a[], int L, int R) { //[L, R] if(L >= R) return; // 循环终止条件 int x = L, y = R, p = a[L]; while(x < y) { //最后找到的x即为划分地 while(x < y && a[y] >= p) --y; a[x] = a[y]; //y向左到比p小的,移到左边去 while(x < y && a[x] <= p) ++x; a[y] = a[x]; //x向右到比p大的,移到右边去 }//end 划分 a[x] = p; quick_sort(a, L, x-1); quick_sort(a, x+1, R); // 递归 } int a[] { 5, 3, 2 ,1, 4}; quick_sort(a, 0, 4); for(int i = 0; i < 5; ++i) cout << a[i] << endl;
函数指针初探 |
- 函数的地址 – 函数名即为函数的地址(不带括号)
声明函数指针 – 使用(*pf) 替代函数名
bool cmp(int a, int b); bool (*p_cmp)(int a, int b);
- 由于
(*p_cmp)
与cmp
等价,所以(*p_cmp)
也是函数,则p_cmp
就是函数指针了 - 不加括号的话
bool *p_cmp(int a, int b);
为一个返回bool*的函数,而非函数指针
- 由于
给函数指针赋值
- 赋值的条件是函数参数和返回类型与指针都一致
p_cmp = cmp
使用函数指针调用函数
- 可以使用(*pf)调用,也可以直接使用指针名作为函数名调用 – amazing
cout << (*p_cmp)(1, 2) << endl; cout << p_cmp(1, 2) << endl;
一个短而有力的例子
#include <iostream> using namespace std; bool cmp(int a, int b) { return a > b; } bool cmp_2(int a, int b) { return a <= b; } //返回两个数的较大值 -- 自定义比较规则 int max_i(int a, int b, bool (*p_cmp)(int a, int b)) { if(p_cmp(a, b)) return a; else return b; } int main() { cout << max_i(1, 2, cmp) << endl; cout << max_i(1, 2, cmp_2) << endl; }
输出结果为
2
1更复杂的用法
函数指针的数组
int (*p_s[3])(int, int);
- [] 的优先级高于 *, 故
(*p_s[3])
表示一个包含三个指针的数组
- [] 的优先级高于 *, 故
指向 函数指针数组 的指针
int (*(*p_ps)[3])(int, int); // 有些小变态
- 将
p_s
替换成(*p_ps)
即可 - 加括号表示p_ps是一个指针,它指向一个包含3个元素的数组
- 将
可使用auto 或typedef简化代码
- auto 只能用于单值初始化,而不能用于初始化表
- 使用typedef 可声明函数指针的别名 – 使代码更容易理解
typedef int (*p_fun)(int, int); p_fun p1 = s1; p_fun pa[3] = {s1, s2, s3}; p_fun (*pd)[3] = &pa;
一个短而有力例子
#include <iostream> using namespace std; int s1(int a, int b) { return a + b + 0; } int s2(int a, int b) { return a + b + 1; } int s3(int a, int b) { return a + b + 2; } int main() { // 函数指针的数组 int (*p_s[3])(int, int) = { s1, s2, s3}; for(int i = 0; i < 3; ++i) { cout << p_s[i](1, 2) << " "; // 等价于 cout << (*p_s[i])(1, 2) << endl; } // 指向 函数指针数组 的指针 // 也可用 auto p_ps = &p_s; 简化 int (*(*p_ps)[3])(int, int) = &p_s; for(int i = 0; i < 3; ++i) { cout << (*p_ps)[i](1, 2) << " "; // 等价于 cout << (*(*p_ps)[i])(1, 2) << endl; } }