天天看点

C++两个函数可以相互递归吗_【C++程序设计】第3期:函数与编译预处理

C++两个函数可以相互递归吗_【C++程序设计】第3期:函数与编译预处理

同学们好!本期C++程序设计将介绍非成员函数的定义与调用、函数原型、递归调用、函数重载、作用域和编译预处理等内容。

01

函数的基本概念

一、库函数与用户自定义函数

库函数是原型说明在特定的头文件中的预定义的函数。例如,头文件中处理输入输出的函数,头文件中数学计算的函数。

用户自定义函数是根据需要自己定义的函数。

二、函数的参数

函数在定义时定义形式参量,调用时提供实际参量。函数形参表可为空,即()或(void)。

三、函数的返回类型

函数在定义时确定了返回值类型。如果为void,则函数结束时不会返回值;否则,要返回特定类型的值。

例如,平方根函数sqrt(2)返回一个double类型的值,则sqrt(2)可以作为double变量参与运算。

四、main函数

一个C++程序从main函数开始执行,最后由main函数返回以结束程序。main函数可以调用其他的函数,其他的函数完成后返回main函数。程序中有且仅有一个main函数。

02

函数的定义与调用

函数的定义与调用有两种方法。

一、定义函数在前,调用函数在后。

例:

#includeusing namespace std;bool isPrime(unsigned n){ //函数定义    if(n<2)        return false;    //以下略}int main(){    int n;    cin>>n;    if(isPrime(n)) //函数调用        //以下略    return 0;}
           

二、先说明函数原型,再调用函数,并在其他地方定义函数。一个函数只能定义一次,但函数说明可以多次出现。

#includeusing namespace std;bool isPrime(unsigned n); //函数说明int main(){    int n;    cin>>n;    if(isPrime(n)) //函数调用        //以下略    return 0;}bool isPrime(unsigned n){ //函数定义    if(n<2)        return false;    //以下略}
           

函数的定义中的注意事项:

1、函数的名字与其形参表作为一个整体,称为函数的基调。不可出现多个基调相同的函数。

2、return语句用于返回某个值,且结果须与函数返回类型相同。可以有多条return语句,但每次调用只能有一个return语句执行。

3、形参可以指定缺省值,但是须为形参表中最右边的形参。

4、无返回函数体可为空,但花括号{ }不可省。

5、main函数应返回int类型,return 0; 结束。

函数的调用中的注意事项:

1、一般函数调用时的实参与被调用函数的形参的类型和数量一致。若形参带缺省值,则实参个数可能少于形参个数。

2、函数调用执行时,每个形参和局部变量都分配独立的存储单元,用于接收实参传递的数据。函数调用结束时,这些存储单元将被回收。

3、以值传递是指调用函数时实参给形参赋值的参数传递方式。形参值在函数体内的变化对实参本身没有影响。(这一点须牢牢掌握,后面在学习指针时会遇到其他的参数传递方式,要能够区分。)

03

函数重载

函数重载是指多个函数有相同的名称,但有不同的形参。重载的多个函数根据函数的基调进行区分。函数调用时,根据提供的实参类型决定调用哪一个函数。

若多个函数基调相同,仅返回类型不同,则不可以作为函数重载,编译报错。

函数重载的调用过程如下:

有函数重载:

void print(char);void print(int);void print(double);
           

1、尝试在函数重载的定义中寻找严格匹配。若有,则调用。

例如:

print('a'); //调用void print(char)
           

2、若不能,则通过整型提升转换寻求最佳匹配。

例如:

unsigned char a=3;print(a); //调用void print(int)
           

3、若不能,再通过标准转换寻求最佳匹配。

例如:

print(1.0f);  //调用void print(double)
           

4、若不能,再通过用户定义类型转换寻求最佳匹配。

用户自定义类型包括结构体和类等,暂不讨论。

5、若不能,则编译报错。

注意函数调用时不可产生二义性,否则编译报错。

04

函数的嵌套调用

函数不允许嵌套定义,但函数在定义时,可以调用另外的函数。嵌套的函数结果逐层返回。

例如:

int mian(){    int a = f();    //下略    return 0;}int f(){    int a = g();    //下略    return 1;}int g(){    //略    return 2;}
           

main函数中调用函数f(),函数f()中调用g(),结果层层返回。

05

函数的递归调用

函数的递归调用是指在定义函数中嵌套调用自己。需要注意:递归函数一般先判断递归结束条件,结束条件确定何时不需要进一步递归调用,而是直接return结果结束本层函数,返回上一层;然后再进行递归调用。

例:

void original(int n){    if(n==0)    //A        return;    else        original(n/10);    //B    cout<10<<}
           

函数original(int n)的作用是从高位到地位依次输出形参n的各位数。

A行首先判断递归结束的条件。

B行继续执行递归调用。

C行是:在里面一层递归调用结束之后,出来继续执行下面的C行,输出本位数。

06

变量的作用域

对于一个块(由同一对花括号{}括起来的部分)内说明的标识符,其作用域始于其说明,终于块的结尾,可被内存块访问。

内层块中可以说明与外侧块中定义的同名的标识符,在内层块中优先访问内层块中的。

具有块作用域的变量称为局部变量,存储在栈中。按照“先进后出”的规则,外层块中的变量先入栈,内层块中的变量后入栈;内层块结束时,内层的变量先出栈,因此此后外层块中不可再访问内层中的变量。

07

特殊的函数

一、带缺省值的形参

1、形参的缺省值必须再形参表的最后面。从第一个带缺省值的形参开始,其右边所有形参都应指定缺省值。

2、调用函数时,若没有提供相应的实参,形参就使用指定的缺省值。

3、重载函数时同名函数形参缺省值可能会发生二义性错误。

例如:

void f(int a, int b=1, int c=0);void f(int a, int b);int main(){    int x=0,y=1,z=2;    f(x,y);    //报错    return 0;}
           

二、inline函数

用关键字inline修饰的函数称为内联函数,该函数的所有调用都被替换位其函数体。

内联函数使得目标代码变得更长,以换取更高的执行效率,用空间换时间。

08

编译预处理

一、包含头文件

#include 是包含已有的头文件。

#include"文件名" 是包含自己写的头文件。

二、无参宏

宏是一个命名的字符串。用名称代替所要表示的一串内容。仅对宏名作简单串替换,不作计算,也不作语法检查。宏定义时不以分号; 结尾,可以以分号; 结尾,但分号会算作宏内容的一部分。

例如:

#define PI 3.1415926
           

在编程过程中,我们只需PI即可代替小数3.1415926。

double p = PI;
           

等价于

double p = 3.1415926; 
           

宏名在字符串中不展开,即

cout<<"PI";
           

输出的是PI,不是3.1415926。

三、有参宏

有参宏的定义格式为

#define (形参表) 
           

宏名与左圆括号之间不可有空格。形参表中仅给出形参名称,例如:

#define V(a,b,c) a*b*cvolumn=V(3+5,8-3,6)
           

需注意,这里展开后并不是(3+5)*(8-3)*6,而是3+5*8-3*6。即宏展开时不作运算,只替换对应的内容,注意与函数区分开。

C++两个函数可以相互递归吗_【C++程序设计】第3期:函数与编译预处理

编辑 | 牟育生

审核 | 李天意

继续阅读