说明
看《C++ Primer Plus》时整理的学习笔记,部分内容完全摘抄自《C++ Primer Plus》(第6版)中文版,Stephen Prata 著,张海龙 袁国忠译,人民邮电出版社。只做学习记录用途。
本章介绍 C++ 中编程模块函数的基础用法。
7.1 函数的基本知识
要使用 C++ 函数,必须完成以下工作:
- 提供函数原型;
- 提供函数定义;
- 调用函数。
7.1.1 函数原型
函数原型描述了函数到编译器的接口,它将函数返回值的类型以及参数的类型和数量告诉编译器。一般情况下 C++ 程序在首次使用函数之前都需要提供函数原型,避免使用函数原型的唯一方法是:在首次使用该函数前提供它的定义,例如将函数定义写在 main()
函数前面。函数原型是一条语句,常包含于 include
文件中,此时通过 #include
编译指令即可提供函数原型。
//方式一:包含头文件
#include <cmath>
//方式二:函数原型(省略参数名)
double sqrt(double);
//方式三:函数原型(参数名等价于占位符)
double sqrt(double x);
C++ 函数原型与 ANSI C 函数原型是有区别的:ANSI C 函数原型不需指出参数的类型和数量,例如原型 void say_hi();
能与对应的无参函数匹配,也能与对应的有参函数匹配,对函数参数没有做限制;而在 C++ 中,原型 void say_hi();
与原型 void say_hi(void);
是等效的,它们都只能与对应的无参函数匹配。在 C++ 中,不指定参数列表时应使用省略号:
//不指定参数列表(C++语法)
void say_hi(...);
//不指定参数列表(ANSI C语法)
void say_hi();
函数原型有以下几个作用:
- 使编译器正确处理函数返回值;
- 使编译器检查使用的参数数目是否正确;
- 使编译器检查使用的参数类型是否正确,若不正确,则强制转换为正确的类型(可能丢失数据),条件是转换前后的类型都是算术类型,且没有函数重载所出现的二义性。
在编译阶段进行的原型化被称为静态类型检查,可以捕获许多在运行阶段非常难以捕获的错误。
7.1.2 函数定义
函数分成两类:没有返回值的函数和有返回值的函数,没有返回值的函数被称为 void
函数,其通用格式如下。其中,parameterList
指定了传递给函数的参数类型和变量,语句 return;
是对 void
函数而言是可选的,也可以使用 return;
提前结束函数。
//没有返回值的函数
void functionName(parameterList)
{
statement(s);
return;
}
有返回值的函数将生成一个值,并将它返回给调用函数,其通用格式如下。其中 value
的类型必须或者可以被强制转换为 typeName
,C++ 对返回值的类型有限制:不能是数组,但可以是其他任何类型(可以将数组作为结构或者对象组成部分来返回)。
//有返回值的函数
typeName functionName(parameterList)
{
statement(s);
return value;
}
7.1.3 函数调用
函数调用比较简单,一个例子如下:
//提供std::cout<<函数原型
#include <iostream>
//提供say_hi()函数原型
void say_hi();
//在main()中调用
int main()
{
//调用say_hi()函数
say_hi();
return 0;
}
//提供say_hi()函数定义
void say_hi()
{
std::cout << "Hello World.\n";
}
执行函数 say_hi()
时,将暂停执行 main()
中的代码,等 say_hi()
执行完毕后,再继续执行 main()
中的代码。对于有返回值的函数,函数通过将返回值复制到指定的 CPU 寄存器或内存单元中来将其返回;随后,调用程序将查看该内存单元。被调用函数和调用函数必须就该内存单元中存储的数据类型达成一致,函数原型将返回值类型告知调用函数,而函数定义命令被调用函数应返回什么类型的数据。
7.2 函数参数和按值传递
函数可以有多个参数,默认情况下,C++ 将按值传递函数的参数。函数参数以及在函数中声明的变量都是该函数私有的,通常情况下,在函数被调用时,计算机将为这些变量分配内存,在函数结束时,计算机将释放这些变量使用的内存。用于接收传递值的变量被称为形参,给函数传递值的变量被称为实参;C++ 标准使用参数(argument)来表示实参,使用参量(parameter)来表示形参。
//提供函数原型
#include <iostream>
double square(double);
//函数调用
int main()
{
double argument = 2.0;
std::cout << square(argument);
return 0;
}
//提供函数定义
double square(double parameter)
{
return parameter * parameter;
}
如上例所示,main()
函数中的变量 argument
为实参,square()
函数中的变量 parameter
为形参。当 square()
函数被调用时,它将创建名为 parameter
的变量,并将其初始化为 argument
的值,初始化赋值必须符合 C++ 语法规则,例如不可将 const int *
实参传递给 int *
形参,但可将 int *
实参传递给 const int *
形参。因此,square()
函数使用的是 argument
的副本,而不是原来的数据,按值传递的方式不会更改原来的数据。
7.3 函数和一维数组
7.3.1 const 和一级指针
可用三种不同的方式将 const
关键字用于一级指针,如下所示:
//方式一:指向常量数据的指针
const int * ptc;
int const * ptc;
//方式二:指针本身为常量,需在声明时初始化
int x = 55;
int * const cpt = &x;
//方式三:指向常量数据且本身也为常量的指针,需在声明时初始化
int x = 5