一个 function 是为了完成某个任务的许多命令的一个集合。使用 function 的优势有:

  • 代码复用
  • 独立测试某功能
  • 修改一个 function 内部代码不影响程序整体结构
  • 同一个 function 可使用不同传入参数调用

一个有效的 c++ 程序至少要有一个 function:main()

返回类型

mian() function 通常结构如下:

int main()
{
  // some code
  return 0;
}

function 的返回值类型定义在它的名称前,以上示例中,返回类型为 int 型,表明此 function 会返回一个 int 型数据。有些 function 在执行后不需返回数据,则使用 void 来定义。

void 是一个基本数据类型,用来定义无值 valueless 申明。

结构

function 定义结构如下:

return_type function_name( parameter list )
{
   body of the function
}
  • return-type: 返回值数据类型
  • function name: function 名称
  • parameters: 传递参数,当此function被调用时,传递数据给 function 内部使用。需要指定类型,名称及个数
  • body of the function: 指令集合

parameters 参数是可选的,当不需要传递参数时可以留空。

使用

我们定义一个无返回值类型的 function:

void printSomething() 
{
  cout << "Hi there!";
}

此 function 功能为输出一个字符串。

我们在 main() 中调用此 function:

int main() 
{
   printSomething();
   
   return 0;
}

调用某个 function 只需要使用 function 名称及传入参数即可。

注意 function 的申明和调用顺序,需要先申明然后调用,不然会报错:

#include <iostream>
using namespace std;

void printSomething() {
  cout << "Hi there!";
}

int main() {
  printSomething();

  return 0;
}

一个 function 的申明告诉编译器这个 function 的名称及调用方法,其内容可以在后续代码中定义:

#include <iostream>
using namespace std;

//Function declaration
void printSomething();

int main() {
  printSomething();

  return 0;
}

//Function definition
void printSomething() {
  cout << "Hi there!";
}

传递参数

如果一个 function 需要传递数据,需要在申明定义正式的参数用来接收传递数据值。例如:

void printSomething(int x) 
{
   cout << x;
}

以上定义一个 function 接收一个 int 整数然后输出这个整数。

function 内的变量在调用此 function 时创建,在结束时清除。

当一个带传递参数的 function 被定义后,在调用时需要传入对于数据类型的数据:

#include <iostream>
using namespace std;

void printSomething(int x) {
  cout << x;
}

int main() {
  printSomething(42);
}

// Outputs 42

以上示例将 42 传入 printSometing() 然后输出数据。

在 function 内对传入参数数据的改变不会对影响到外部的数据。

可以在调用时使用不同的传入数据:

int main() {
  printSomething(42);
  printSomething(22);
  printSomething(36);
}

可以定义多个传递参数,使用逗号, 分隔,如:

int addNumbers(int x, int y) {
  int result = x + y;
  return result;
}

int main() {
  cout << addNumbers(50, 25);
  // Outputs 75
}

以上示例定义了两个传递参数,返回值为两个参数的和。

rand() function

创建一个随机整数是程序内常用的使用场景,可以调用 rand() function 获取随机整数。需要用到 <cstdlib> 库:

#include <iostream>
#include <cstdlib>
using namespace std;

int main() {
  cout << rand();
}

输出 10 个 1 - 6 之间的随机数:

int main () {
  for (int x = 1; x <= 10; x++) {
  cout << 1 + (rand() % 6) << endl;
  }
}

/* Output: 
6
6
5
5
6
5
1
1
5
3
*/

但是 rand() 其实生成的是伪随机数,因为每次执行以上程序生成的数都是一样的。使用 srand() 可以获得真正的随机数,它支持设置一个 seed 种子值来作为 rand() 的运行算法:

int main () {
  srand(98);

  for (int x = 1; x <= 10; x++) {
    cout << 1 + (rand() % 6) << endl;
  }
}

改变 srand() 的 seed 传入值可以改变 rand() 算法来生成新的随机数。所以同一个 seed 值执行后生成的随机数是一样的。

那么如何使用不同的 seed 值呢,一个方法是读取当前时间来作为 seed,这样就可以得到真正的随机数,读取系统时间需要使用 <ctime> 库:

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main () {
  srand(time(0));

  for (int x = 1; x <= 10; x++) {
    cout << 1 + (rand() % 6) << endl;
  }
}

time(0) 返回当前时间的秒位。

传递参数默认值

当定义一个 function 时可以给参数项设置一个 default 默认值,这样在调用这个 function 时如果没有给参数赋值,就会使用默认值的数据,例如:

int sum(int a, int b=42) {
  int result = a + b;
  return (result);
}

以上示例中给变量 b 设置默认值 42,当调用这个 function 时如果没有给 b 传入数据,就会使用默认值:

int main() {
  int x = 24;
  int y = 36;

  int result = sum(x, y);
  cout << result << endl;
  //Outputs 60

  result = sum(x);
  cout <<  result << endl;
   //Outputs 66

  return 0;
}

overload function 重写

function overload 功能支持使用同样的名称建立多个 function,拥有不同的传递参数。

例如创建一个 function,有一个 int 型的参数:

void printNumber(int a) { 
  cout << a;
}

我们可以再次创建一个有同样名称的 function 有一个 float 类型的参数:

void printNumber(float a) { 
  cout << a;
}

这两个 function 可以同时存在且互不影响,调用时根据传递参数类型或个数的不同来自动判断调用的具体是那个 function。

注意不能仅仅建立有不同的返回值类型的同名 function 例如以下 function 不能同时建立:

int printName(int a) { }
float printName(int b) { }
double printName(int c) { }

递归 recursion

递归操作在程序中很常见,可以在 function 中调用其自身。

递归在数学中很常见,如计算阶乘:

4! = 4 * 3 * 2 * 1 = 24

建立一个 function 实现上面的阶乘计算:

int factorial(int n) {
  if (n==1) {
    return 1;
  }
  else {
    return n * factorial(n-1);
  }
}

int main() {
  cout << factorial(4);
}

如果我们调用此 function 传递参数为 4,则返回值计算过程为:
返回 4 * factorial(3), 然后返回 4*3*factorial(2), 再次返回 4*3*2*factorial(1), 然后为 4*3*2*1,最后 n 为 1 结束递归调用 function。

注意设计 recursion 时一定要有 base case 跳出递归的条件,要不然就会陷入死循环。

数组类型传递参数

数组也可以作为 function 的传递参数类型,例如:

void printArray(int arr[], int size) {
  for(int x=0; x<size; x++) {
    cout << arr[x];
  }
}

int main() {
  int myArr[3]= {42, 33, 88};
  printArray(myArr, 3);
}

printArray() 的参数为 int 型一个数组和单变量,在 main() 中调用时传入一个 3 个元素的数组和数组个数数据。会输出这个数组所有元素。

当调用 function 时传入的数组只需要写数组名即可,不需要方括号[]

传入数据

有两种方式给 function 传入数据:

  • by value:复制传入参数的数据供 function 内部使用,内部对数据的修改操作不影响外部数据
  • by reference:复制传入参数的相关性到 function 内部,这时候对传入数据的操作会直接影响到外部关联的数据

c++ 默认使用 by value 传入数据。如:

void myFunc(int x) {
  x = 100;
}

int main() {
  int var = 20;
  myFunc(var);
  cout << var;
}
// Outputs 20

以上示例中,将 var 的数据传入 myFunc(),传入数据给 function 内部变量 x,内部 x 变量的值修改为 100 后不会影响到外部的 var 的数据。

by reference 方式会将传入数据的内存地址传入 function 中内部参数,这意味着 function 内对传入数据的修改会直接修改源传入数据内容。使用这种方式的 function,需要将传递数据定义为 pointer 指针类型。例如:

void myFunc(int *x) {
  *x = 100;
}

int main() {
  int var = 20;
  myFunc(&var);
  cout << var;
}
// Outputs 100

以上示例中定义一个 function 拥有指针类型的传递参数,在调用 myFunc() 时传入一个数据的地址,这样在 function 内对此地址数据的操作会直接改变外部对应地址的变量的数据。

也可以用另一种形式将数据地址传入 function,使用 & 转换数据地址:

void test2(int &a) {
    a = 2;
}

int main()
{
    int a = 1;
    test2(a);
    cout << a << endl;

    return 0;
}

//OUTPUT:
//2

使用这种方法可以将数据名称直接作为参数传入,function 会自动使用其地址。

通常情况下,使用 by value 方式更加快速和高效,使用 by reference 方式会修改源相关联的数据会占用更多的内存。

标签: none

添加新评论