C++函数(函数原型,指标、参考、预设、可变参数)第一部

函数原型

自订函数的定义需要放在main()或呼叫之前,如果放在main()或呼叫之后,例如

复制代码
#include <iostream>
  
int main() {
    do_something("What's truth?");
    do_something("There is no spoon.");
    
    return 0;
}

void do_something(char* s) {
    std::cout << s << std::endl;
}

这样无法通过编译

复制代码
$ g++ u0801_1.cpp
u0801_1.cpp:4:5:错误:使用未声明的标识符"do_something"
   do_something("真相是什么?")
   ^
u0801_1.cpp:5:5:错误:使用未声明的标识符"do_something"
   do_something("没有勺子。");
   ^
产生了2个错误。
$

因为C++ 预设任何识别字使用前都得先定义或宣告,如果我们要把自订函数的定义放在main()或呼叫之后,就要先宣告函数原型(function prototype) ,因此上例要改写如下

复制代码
#include <iostream>
  
void do_something(char*);

int main() {
    do_something("What's truth?");
    do_something("There is no spoon.");
    
    return 0;
}

void do_something(char* s) {
    std::cout << s << std::endl;
}

函数原型的宣告在第3 行

复制代码
void do_something(char*);

参数列方面宣告参数的型态即可,编译执行结果如下

复制代码
$ g++ u0801_2.cpp
$./a.out 复制代码
什麼是真實呢?
没有勺子。
$

通常函数原型的宣告会放在标头档(header file) 之中,函数实作则会放在其他程式档案。

指标参数

如果有需要用函数直接修改某些变数(variable) ,就可以用该变数的指标(pointer) 当参数,例如

复制代码
#include <iostream>
  
void do_something(int* n_ptr) {
    *n_ptr = 10;
}

int main() {
    int a = 22;
    std::cout << a << std::endl;
    do_something(&a);
    std::cout << a << std::endl;
    
    return 0;
}

do_something()接受一个整数指标参数,然后将参数重新设定为10

复制代码
void do_something(int* n_ptr) {
    *n_ptr = 10;
}

编译执行,结果如下

复制代码
$ g++ u0802_1.cpp
$./a.out 复制代码
22
10
$

由于函数只能有一个回传值,因此当程式中有多个变数需要用函数修改时,利用指标当参数为一个解决方案,另举一例如下

复制代码
#include <iostream>
  
int do_something2(int* n1_ptr, int* n2_ptr) {
    *n1_ptr *= 2;
    *n2_ptr *= 2;
    return *n1_ptr + *n2_ptr;
}

int main() {
    int a = 22;
    int b = 33;
    std::cout << "a + b: " << do_something2(&a, &b) << std::endl;
    std::cout << "a: " << a << std::endl;
    std::cout << "b: " << b << std::endl;
    
    return 0;
}

$ g++ u0802_2.cpp
$./a.out 复制代码
a+b:110
答:44
乙:66
$

参考参数

如果有需要用函数直接修改某些变数,就可以设计接收参考参数(reference parameter) 的函数,例如

复制代码
#include <iostream>
  
void do_something(int& n_ref) {
    n_ref = 10;
}

int main() {
    int a = 22;
    std::cout << a << std::endl;
    
    do_something(a);
    std::cout << a << std::endl;
    
    return 0;
}

do_something()接受一个整数参考参数,然后将参数重新设定为10

复制代码
void do_something(int& n_ref) {
n_ref = 10;
}

编译执行,结果如下

复制代码
$ g++ u0803_1.cpp
$./a.out 复制代码
22
10
$

由于函数只能有一个回传值,因此当程式中有多个变数需要用函数修改时,利用参考当参数为一个解决方案,另举一例如下

复制代码
#include <iostream>
  
int do_something2(int &n1_ref, int &n2_ref) {
    n1_ref *= 2;
    n2_ref *= 2;
    
    return n1_ref + n2_ref;
}

int main() {
    int a = 22;
    int b = 33;
    std::cout << "a + b: " << do_something2(a, b) << std::endl;
    std::cout << "a: " << a << std::endl;
    std::cout << "b: " << b << std::endl;
    
    return 0;
}

编译执行,结果如下

复制代码
$ g++ u0803_2.cpp
$./a.out 复制代码
a+b:110
答:44
乙:66
$

预设参数

函数可以有预设参数(default parameter) ,也就是替参数设定预设值,例如

复制代码
#include <iostream>
  
void do_something(int n = 22) {
    std::cout << n << std::endl;
}

int main() {
    do_something(11);
    do_something();
    do_something();
    
    return 0;
}

替参数n设定预设值,就是直接在参数列指派数值

复制代码
void do_something(int n = 22) {

这样不使用参数也可以呼叫

复制代码
do_something(11);
do_something();
do_something();

编译执行,结果如下

复制代码
$ g++ u0804_1.cpp
$./a.out 复制代码
11
22
22
$

预设参数可以是选择性的,也就是可以替特定参数设定预设值,其他参数则须呼叫时填入小括弧,需要注意这样的预设参数必须放在参数列的后面,例如

复制代码
#include <iostream>
  
void do_something2(int n1, int n2 = 5, int n3 = 0) {
    std::cout << n1 + n2 + n3 << std::endl;
}

int main() {
    do_something2(6);
    do_something2(6, 9);
    do_something2(3, 4, 5);
    
    return 0;
}

留意n1并没有预设值

复制代码
void do_something2(int n1, int n2 = 5, int n3 = 0) {
    std::cout << n1 + n2 + n3 << std::endl;
}

因此呼叫时至少要有一个参数

复制代码
do_something2(6);
do_something2(6, 9);
do_something2(3, 4, 5);

编译执行,结果如下

复制代码
$ g++ u0804_2.cpp
$./a.out 复制代码
11
15
12
$

此外要注意参数列的顺序,预设参数只能放在参数列的后面,像是下面就无法通过编译

复制代码
void do_something2(int n1 = 6, int n2, int n3 = 0) {

可变参数

函数的参数数量也可以不固定,这是在参数列里利用...构成可变参数(variadic arguments) ,举例如下

复制代码
#include <iostream>
#include <cstdarg>

int sum(int n_args, ...) {
    va_list ap;
    va_start(ap, n_args);
    int sum = va_arg(ap, int);
    for (int i = 2; i <= n_args; i++) {
        sum += va_arg(ap, int);
    }
    va_end(ap);
    
    return sum;
}

int main() {
    std::cout << sum(3, 11, 22, 33) << std::endl;
    std::cout << sum(3, 19, 20, 21) << std::endl;
    std::cout << sum(3, 3, 65, 101) << std::endl;
    
    return 0;
}

此例的sum()用来计算参数的总和,除了第一个参数n_args为计算总和的数量之外,其他的参数都会被累加起来,结果回传为整数

复制代码
int sum(int n_args, ...) {
    va_list ap;
    va_start(ap, n_args);
    int sum = va_arg(ap, int);
    for (int i = 2; i <= n_args; i++) {
        sum += va_arg(ap, int);
    }
    va_end(ap);
    
    return sum;
}

编译执行,结果如下

复制代码
$ g++ u0805.cpp
$./a.out 复制代码
66
60
169
$
相关推荐
乱七八糟的屋子7 分钟前
MTL4 (Matrix Template Library) 超详细实战教程|C++高性能稠密/稀疏矩阵计算
c++·矩阵·稀疏矩阵·mtl4·matrixtemplate·c++线性代数·高性能数值计算
fīɡЙtīиɡ ℡16 分钟前
深入学习JAVA并发编程(上)
java·开发语言·学习
zzzll111118 分钟前
HashMap、HashTable、ConcurrentHashMap 详细区别与深度解析
开发语言·python
老师我太想进步了202631 分钟前
C语言版讲解函数递归
c语言·开发语言
猿长大人1 小时前
C# | 函数式编程入门
开发语言·c#·.net
W_326001 小时前
Python 组合数据类型——序列(列表 & 元组)
开发语言·python
Billy121381 小时前
Day10-C++20 Ranges(上):惰性求值与组合式数据处理
开发语言·c++进阶学习
依然鸣1 小时前
PTA团体程序设计天梯赛L2真题讲解L2-045-048
数据结构·c++·经验分享·学习·算法·pat考试·pat
有点。1 小时前
C++深度优先搜索(二)
开发语言·c++·深度优先
二进制杯莫停1 小时前
A和B环境的python版本相同,B环境无法安装pip依赖,离线安装
开发语言·python·pip