【新知识】初涉函数——C++的编程模块

        本文使用代码案例来自《C++ Primer Plus》(第六版)一书,并对书中原代码稍加改写以方便阅读。这篇文章相当于个人的学习笔记,会充满各种不成熟的想法,所以如果有错误,希望有大佬可以斧正。

一、函数的基本知识

        C++自带一个包含函数的大型库(标准ANSI库以及多个C++类),库函数是已经定义和编译好的函数,可以使用对应的标准头文件来调用它们(比如使用strlen()之前需要先调用<cstring>头文件)。但是如果要自己设计一个可以使用的函数,必须自行完成这三个工作:提供函数定义、提供函数原型、调用函数。

二、函数的类型

        函数可分为有返回值的函数和没有返回值的函数两大类型。

        没有返回值的函数被称为void函数,其通用格式如下:

void FunctionName(parameterlist);

int main(){
    FunctionName(parameterlist);
}

void FunctionName(parameterlist){
    statement(s);
    return; //可有可无
}

        其中的parameterlist指定了传递给函数的参数类型和数量,这一部分稍后细讲。 例如,我们可以设计一个叫cheers()的void函数:

void cheers(int);

int main(){
    int n;
    cheers(n);
    system("pause");
    return 0;
}

void cheers(int n){
    cin >> n;
    for(int i=0;i<n;i++){
        cout <<"Cheers!"<<endl;
    }
}

        注意,main()里的n和cheers()里的n虽然名字一样,但是其实是两个不同的变量。就像住在北京和住在山西的两个张三虽然名字一样,但是却不是同一个人。理论上,这两个东西可以起不同的名字,比如说a和b或c和d,而不会对结果造成任何影响。

        有返回值的函数类型很多,你可以像规定变量的类型那样规定函数类型,比如int cheers()或double cheers(),前面的数据类型决定了这个函数返回值的类型。return操作可以把一个值返回给main()函数。比如:

int Fmax(int,int);

int main(){
    int a,b;
    cin >>a>>b;
    cout << Fmax(a,b)<<endl;
    system("pause");
    return 0;
}

int Fmax(int a,int b){
    if(a>b){
    return a;
    }
    if(a<b){
    return b;
    }
}

        这个函数实现的功能是,比较a和b两个整数的大小,并返回较大的一个给main()函数。

        返回语句甚至可以使用表达式,比如return x*x,就是返回x的平方。

        可以发现,main也是一个有返回值的函数,其返回值的类型为int。我们在main()函数的结尾总是写一句return 0,这句话的用途就是把0返回给操作系统,告诉操作系统该程序已经正常结束了,如果返回值非0,则说明程序异常。

三、函数原型的语法

        上面的几个代码案例大体框架都是以第一个案例为基础的。这里再引述一遍:

void FunctionName(parameterlist);

int main(){
    FunctionName(parameterlist);
}

void FunctionName(parameterlist){
    statement(s);
    return; //可有可无
}

        第一行代码即函数原型,函数原型本质上是一条语句,所以必须以分号结尾。原型描述了函数到编译器的接口。C语言中原型可以省略不写,一般不会影响编译器正常编译,但C++必须写。在C语言中,如果不写函数原型的话,编译器如果在main()中找到这个函数,它将找到此函数调用存放值的位置,并使用这里的值。但是C++强制要求写出函数原型,以减少编译器报错的可能性。

        由于编译器在搜寻文件时会停止对main()的编译,甚至有可能要调用的函数压根不在同一个文件中(C++允许把一个程序放在多个文件中,随后单独编译这些文件并组合起来),所以提前使用整型提醒编译器是很有必要的,可以极大提高代码效率。

        函数原型括号内的paramterlist即原型的参数列表,可以包括变量名,也可以不包括(比如可以写为void cheers(int n),也可以直接写为void cheers(int))。原型中的变量名相当于占位符,所以不要求与函数定义中的变量名相同。

        接下来,我们假设有这么一个语句cheers(cube(2)),其中cube的参数列表类型为double,而cheers则为int型。cube()的功能是求一个数的立方并返回其立方值。现在,编译器发现cube接受到的值是整数2,而非2.0,编译器便会把2转化为2.0,并返回8.0。接下来,编译器将继续检查原型,并进一步发现,cheers需要int型,得到的参数却是8.0,因此它将返回值转化为8以供cheers使用。通常情况下,原型自动将被传递的参数强制转化为期望的类型(但是函数重载可能导致二义性,因此不允许某些自动强制类型转换,这个内容以后再细讲)。

        注意,强制类型转换并不能解决所有的问题。例如,如果将8.33E27传递给一个期望int值的函数,那么这么大的值将不能被正确地转换为int值。当较大的类型被转换为较小的类型时,有些编译器将会发出警告,指出这样可能会丢失数据。 仅当这样做有必要时,原型化才会导致类型转换。例如,原型不会将整数转换为结构或者指针。

        在编译阶段进行的原型化被称为“静态类型检查”(static type checking)。静态类型检查可以捕获很多在运行阶段非常难以捕获的错误。

四、函数参数和按值传递

        在下面的代码案例中:

int Fmax(int,int);

int main(){
    int a,b;
    cin >>a>>b;
    cout << Fmax(a,b)<<endl;
    system("pause");
    return 0;
}

int Fmax(int a,int b){
    if(a>b){
    return a;
    }
    if(a<b){
    return b;
    }
}

        函数原型的参数列表为两个int型,随后main()中声明了两个整型变量a和b,并向Fmax()中输入了这两个变量的值,被调用的Fmax()随后创建了新的(注意是新的!)两个整型变量a和b,并分别赋值。以上过程即按值传递,这样操作可以保护main()中的数据免受影响。Fmax()新创建的两个变量名为形参,形参接受到的数值名为实参。C++标准使用参数(argument)来表示实参,使用参量(parameter)来表示形参,因此参数传递就是将参数赋给参量。

        在函数中声明的变量(包括参数)是该函数私有的。在函数被调用时,计算机将为这些变量分配内存;在函数结束时,计算机将释放这些变量使用的内存。这样的变量被称为局部变量,因为它们被限制在函数中,这样做有助于保证数据的完整性。它们也被称为自动变量,因为它们是在程序执行过程中自动被分配和释放内存的。

        函数原型的参数列表可以有一个两个甚至多个变量类型,比如void FunctionName(int a,double b,char c),也可以不写变量名而写作void FunctionName(int,double,char),但是写明变量名可以方便代码阅读者理解,如double melon_density(double weight,double volume)。

        下篇文章将会是关于函数与数组的笔记。        

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值