C++函数

2023-10-27

C++函数

函数是一组一起执行一个任务的语句。与C程序类似,每个 C++ 程序都至少有一个函数,即主函数 main(),通过函数,还可以把一个复杂任务分解成为若干个易于解决的小任务,充分体现结构化程序设计由粗到精,逐步细化的设计思想,即将任务合理划分为功能相对简单的若干子任务,分别进行设计调试,并通过某种机制将其连接成完整的程序,可以提高程序设计的效率。

按函数是否由系统定义:分为库函数(系统函数)和自定义函数。

C++ 标准库提供了大量的程序可以调用的内置函数。例如,函数 strcat() 用来连接两个字符串,函数 memcpy() 用来复制内存到另一个位置。

本文重点介绍自定义函数

C++ 中的函数定义的一般形式如下:

return_type function_name( parameter list )

{

   函数体

}

在 C++ 中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:

返回类型:一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void。

函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。

参数:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。

函数体:包含一组定义函数执行任务的语句。

注意:对于main函数,main 函数的类型必须是 int ,当遇到到return 0;语句,那么整个程序就会停止,退出程序的执行。对于一般自定义函数,函数定义为什么样的类型,若需要有return语句,就应该返回相应类型的值,并且,当遇到return 语句,那么程序就会返回到调用该函数的地方接着执行。

C++自定义函数的定义
按函数是否带有参数:分为无参函数和有参函数。
无参函数:无参函数定义格式为:
    [<类型>]<函数名> ([void])
    {<函数体>}

有参函数:有参函数定义格式为:
    [<类型>]<函数名> (<类型1> <形式参数1>[,<类型2><形式参数2>,…] )
    {<函数体>}
函数的调用
创建 C++自定义函数后,就可以通过调用之来执行它。当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。
无参函数的调用格式为:
    <函数名>( )

有参函数的调用格式为:
    <函数名>(<实际参数表>)

例、编写一个求x的n次方的函数

#include<iostream>
using namespace std;

double power(double x,int n)
{
 double val=1.0;
 while(n--)
 val*=x;
 return val;
}

int main()
{
 float x,y;
 cout<<"输入底数和指数(两数之间空格分隔):";
 cin>>x>>y; 
 cout<<x<< "的"<<y<< "次方是"<<power(x, y)<<endl;
 return 0;
}

运行之,参见下图:

C++ 中的空函数
一个空函数示例:
void displayMessage()
{
    cout << "Hello from the function displayMessage.\n";
}
该函数的名称是 displayMessage,意思是“显示消息”,它是一个描述性的名称,说明了函数的功能。函数就应该按这种方式命名,即通过名称揭示其功能。因为该函数不需要接收任何信息以执行其任务,所以它的括号中没有形参列表。
该函数的返回类型是 void。这意味着函数在完成执行后不返回值,并返回到调用该程序的部分。因为没有返回值,所以不需要 return 语句。当函数中的语句己经完成执行并且遇到结束函数的封闭大括号时,程序将自动返回。
演示空函数的例:
#include <iostream>
using namespace std;
// 定义空函数
void displayMessage()
{
    cout << "你好,来自displayMessage函数的问候。\n";
}
//mian函数
int main()
{
    cout << "你好,来自mian函数的问候。\n";
    displayMessage(); // 调用displayMessage
    cout << "现在又回到了mian函数。\n";
    return 0;
}

运行之,显示如下:

C++函数原型(prototype)声明
被调用的函数一般定义在前,调用在后,像上面的例子。
可否将被调用的函数在后面定义?可以,此时就需要在前面先声明一个函数原型(),这样也就可以进行调用了。
函数原型声明形式如下:
  函数类型  函数名(形式参数表);
包括:函数的类型,函数名,形式参数表,注意函数原型末尾有一个分号。

演示函数原型的例,本例和上例不同之处是,使用函数原型声明:
#include <iostream>
using namespace std;

// 函数原型(Function prototype)声明 
void displayMessage();

//mian函数
int main()
{
    cout << "你好,来自mian函数的问候。\n";
    displayMessage(); // 调用displayMessage
    cout << "现在又回到了mian函数。\n";
    return 0;
}

// 定义空函数
void displayMessage()
{
    cout << "你好,来自displayMessage函数的问候。\n";
}

运行之,显示如下:

再举一例、求两数最大值
#include<iostream>
using namespace std;

int max(int x,int y);//函数的声明 

int main()
{
    int x,y,z;
    while(1)
    {
        cout<<"请输入两个不同数值,以空格分开\n"; 
        cin>>x>>y;
        z=max(x,y); //函数的调用 
        cout<<"最大值是:"<<z<<endl; 
    }
}
 
 
int max(int x,int y)//函数的定义:返回两数最大值 
{
    int z;
    if (x>y)
        z=x;
    else 
        z=y; 
    return z;
 }
 

C++函数的实参和形参

形式参数(形参)和实际参数(实参)

形式参bai数就是定义函数时候的参数表,只是定义了调用时参数的个数、类型和用来引用的名字,并没有具体的内容。

实际参数是调用函数传递的具体数据,实参可以是常量、变量或者表达式,且要与形参类型一致!实参对形参数据传递时是单向传递——形参相当于剧本中的人物;实参相当于演员,演员(实参)去扮演(替换)剧本里的角色(形参),不可能用剧中人物去替代现实的演员!

形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。 每次调用函数时,都会重新创建该函数所有的形参,此时所传递的实参将会初始化对应的形参。形参的初始化与变量的初始化一样:如果形参具有非引用类型,则复制实参的值;如果形参为引用类型,则它只是实参的别名。

形参和函数体内部定义的变量统称为局部变量,仅在函数的作用域内可见,同时局部变量还会隐藏在外层作用域中同名的其他所有声明(局部变量和全局变量可以重名)

C++局部变量和全局变量

局部变量

在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外是不能使用这些变量的。同样,在复合语句中定义的变量只在本复合语句范围内有效。这称为局部变量(local variable)。参见如示意图:

对局部变量的一些说明:

1)局部变量在定义时可加修饰词auto,但通常省略。局部变量在定义时若未初始化,其值为随机数。

2) 主函数main中定义的变量(m, n)也只在主函数中有效,不会因为在主函数中定义而在整个文件或程序中有效。主函数也不能使用其他函数中定义的变量。

3) 不同函数中可以使用同名的变量,它们代表不同的对象,互不干扰。例如,在f1函数中定义了变量b和c,倘若在f2函数中也定义变量b和c,它们在内存中占不同的单元,不会混淆。

4) 可以在一个函数内的复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为分程序或程序块。

5) 形式参数也是局部变量。例如f1函数中的形参a也只在f1函数中有效。其他函数不能调用。

6) 在函数声明中出现的参数名,其作用范围只在本行的括号内。实际上,编译系统对函数声明中的变量名是忽略的,即使在调用函数时也没有为它们分配存储单元。例如:

int max(int a, int b);//函数声明中出现a、b

int max(int x, int y) //函数定义,形参是x、y

{

    cout<<x<<y<<endl; //合法,x、y在函数体中有效

    cout<<a<<b<<endl;  //非法,a、b在函数体中无效,编译时报错

}

全局变量

程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。在函数内定义的变量是局部变量,而在函数之外定义的变量是外部变量,称为全局变量(global variable。全局变量的有效范围为从定义变量的位置开始到本源文件结束。参见如示意图:

p、q、c1、c2都是全局变量,但它们的作用范围不同,在main函数和f2函数中可以使用全局变量p、q、c1、c2,但在函数f1中只能使用全局变量p、q,而不能使用c1和c2。

在一个函数中既可以使用本函数中的局部变量,又可以使用有效的全局变量。

对全局变量的一些说明:

1)全局变量在编译时建立在全局数据区,在未给出初始化值时系统自动初始化为0。

2) 全局变量的作用是增加函数间数据联系的渠道,但要慎重使用,建议不在必要时不要使用全局变量,因为:

全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。

它使函数的通用性降低了,因为在执行函数时要受到外部变量的影响。如果将一个函数移到另一个文件中,还要将有关的外部变量及其值一起移过去。但若该外部变量与其他文件的变量同名,就会出现问题,降低了程序的可靠性和通用性。在程序设计中,在划分模块时要求模块的内聚性强、与其他模块的耦合性弱。即模块的功能要单一(不要把许多互不相干的功能放到一个模块中),与其他模块的相互影响要尽量少,而用全局变量是不符合这个原则的。

一般要求把程序中的函数做成一个封闭体,除了可以通过“实参——形参”的渠道与外界发生联系外,没有其他渠道。这样的程序移植性好,可读性强。

使用全局变量过多,会降低程序的清晰性。在各个函数执行时都可能改变全局变量的值,程序容易出错。因此,要限制使用全局变量。

3) 如果在同一个源文件中,全局变量与局部变量同名,则在局部变量的作用范围内,全局变量被屏蔽,即它不起作用。

简单的说,在{...}中出现的都是局部变量,否则就是全局变量。

变量的有效范围称为变量的作用域(scope)。归纳起来,变量有4种不同的作用域、文件作用域(file scope)、函数作用域(function scope)、块作用域(block scope)和函数原型作用域(function prototype scope)。文件作用域是全局的,其他三者是局部的。

除了变量之外,任何以标识符代表的实体都有作用域,概念与变量的作用域相似。


变量作用域示例1:
#include <iostream>
using namespace std;
int i=10;//全局变量
int main()
{
    cout<<i<<endl;//输出全局变量i值10
    i=5;//为全部变量i赋值
    {
        int i;//局部变量,局部作用域
        i=7;
        cout<<i<<endl;//输出7
    }
    cout<<i<<endl;//输出5

    return 0;
}

运行之,参见下图:

变量的有效范围称为变量的作用域(scope),C++变量有三种作用域:文件作用域(file scope)、函数作用域(function scope)、块作用域(block scope)。文件作用域是全局的,函数作用和域块作用域是局部的。

函数的参数传递

函数参数传递的三种方式:

1)值传递(传值):

形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。

2)引用传递(传引用):

形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。因此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

3)指针传递(传址):

形参指向实参地址,当对形参操作时,就相当于对实参本身进行的操作。指针变量中可以存放的是其它变量的地址, 向函数参数中传递指针变量,意味着指针变量这个形参指向实参变量的实际存储位置, 对实际位置中的内容进行操作, 实参的值自然就会跟着改变。

下面通过例子说明。

☆值传递

值传递是指向函数传递自身的一个副本, 也可以认为是自身的克隆, 他最大的一个特点就是函数对传入的副本进行操作不会影响到实参的本身。值传递的简单例子:

#include<iostream>

using namespace std ;

void fun(int val)

{

    val = 100 ;     //将传进来的参数的值更改为100

}

int main()

{

    int n = 0 ;

    fun(n); // 尝试通过函数改变n的值

    cout<<"n = "<<n ;

    return 0 ;

}

运行之,参见下图:

可以看到, n的值并未发生任何改变。

☆引用传递

引用传递不是使用实参的"副本", 而是真实的实参值在内存中的地址, 因此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。引用传递的简单例子:

#include<iostream>

using namespace std;

void fun(int &r)

{

    r = 100 ;  //通过引用改变实参的值

}

int main()

{

    int n = 0 ;

    int &rn = n ;

    fun(rn) ;   //传递n的引用rn

    cout<<"n = "<<n ;

    return 0 ;

}

运行之,参见下图:

☆指针传递

指针变量中可以存放的是其它变量的地址, 向函数参数中传递指针变量,意味着指针变量这个形参指向实参变量的实际存储位置, 对实际位置中的内容进行操作, 实参的值自然就会跟着改变。关于指针参见“C++指针”一文。指针传递的简单例子:

#include<iostream>

using namespace std;

void fun(int *p)

{

    *p = 100 ;  //通过指针p改变实参的值

}

int main()

{

    int n = 0 ;

    int *p = &n ;

    fun(p) ;  //将指向变量n的指针传入到函数fun

    cout<<"n = "<<n ;

    return 0 ;

}

运行之,参见下图:

 

内联函数

内联函数(inline函数)的作用就是优化被频繁调用的函数,就相当于把inline函数中的函数体直接复制到被调用的函数中一样, 不再使其频繁的中断。 定义inline函数非常简单, 只要在定义时在前面加上 inline 关键字即可, 例如:

#include<iostream>

using namespace std;

inline void fun()  //在 void fun() 前有inline

{

    cout<<"Hello, world!\n" ;

}

int main()

{

    int i ;

    for(i=0; i<2000; i++)

        fun() ; //短时间内将会被调用2000次

    return 0 ;

}

在使用inline函数时需要注意的几点问题:

☆inline 函数的函数体语句不适合过多,因为inline 函数以空间换时间 ;

☆inline 函数中不能有 循环、if或switch语句, 否则编译器将会把该函数当做普通函数来处理 ;

☆一个文件中定义的inline函数不能再另一个文件中使用,否则无效。

递归函数

递归算法(recursion algorithm)在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。递归算法是一种直接或者间接调用自身函数或者方法的算法。

运用递归的条件:每一步进行的操作基本相同,并且问题规模逐渐减小。

递归的过程

递归,顾名思义,其包含了两个意思:递 和 归,这正是递归思想的精华所在。递归就是有去(递去)有回(归来),用递归求4!如下图所示:

用递归求阶乘的代码

#include<iostream>

using namespace std;

int fun(int n) 

{

    if(n == 0 or n == 1)

        return 1;

    else

        return (n * fun(n - 1));

}

int main()

{

    cout<<"4!结果" << fun(4) << "\n" ;

    return 0 ;

}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++函数 的相关文章

随机推荐

  • 使用myisamchk命令修复表 只能修复myisam表 速度块

    快速检查 myisamchk im var lib mysql db1 只检查没有正常关闭的表 myisamchk iFm var lib mysql db1 仅显示标的重要信息 myisamchk eis var lib mysql db
  • 【Markdown】Typora配置图片上传

    文章目录 0 前言 1 确定需求 2 开始配置 2 1 软件储备 2 2 插件安装 2 3 gitee配置 3 其他配置 3 1 获取SMMS token 参考链接 0 前言 对于喜欢写Markdown文档的人来说 Typora无疑是一个写
  • 30分钟学会如何使用Shiro

    http www cnblogs com learnhow p 5694876 html 一 架构 要学习如何使用Shiro必须先从它的架构谈起 作为一款安全框架Shiro的设计相当精妙 Shiro的应用不依赖任何容器 它也可以在JavaS
  • 宏定义详细知识点

    一 不带参数的宏定义 1 格式 define 宏名 字符串 例 define a 6 则a是宏名 凡是出现a的地方均用6替换 2 注意 宏替换是一种机械替换 不做语法检查 不是下一个语句 其后不加 define命令出现在函数的外面 有效范围
  • 框架中常见的设计模式有哪些学习总结第一篇

    框架中常见的设计模式有哪些 设计模式的作用 通过设计模式写代码 设计模式可以解耦 解耦只是一种思想 代码开发的时候 把代码分开便于维护和管理 运行的时候再合并起来运行 回顾软件设计原则 开闭原则 对扩展开放 对修改关闭 使用范围特变广 单一
  • c语言之实现fastcgi协议的代码完整实现

    FastCGI协议是在CGI协议的基础上发展出来的 如果想了解CGI协议 可以看我另一篇文章 动态web技术 二 CGI FastCGI程序本身监听某个socket然后等待来自web服务器的连接 而不是像CGI程序是由web服务器 fork
  • Android Studio 快速跳转到XML布局界面

    http www jianshu com p 8ca15b831b31 我们开发Android应用程序时 Activity或者Fragment会有一个相对应的布局 在Eclipse中或者一般的做法 我们会在Java代码中找到对应的代码 然后
  • jquery之ajax——全局事件引用方式以及各个事件(全局/局部)执行顺序

    jquery中各个事件执行顺序如下 1 ajaxStart 全局事件 2 beforeSend 局部事件 3 ajaxSend 全局事件 4 success 局部事件 5 ajaxSuccess 全局事件 6 error 局部事件 7 aj
  • Python画图示例(1) 一维数据集绘图

    Python画图示例 1 一维数据集绘图 Python画图示例 2 二维数据集绘图 Python画图示例 3 其他绘图样式 散点图 直方图等 Python画图示例 4 3D绘图 目录 1 用 Numpy ndarray 作为数据传入 ply
  • Trie 前缀树 字典树 简介+实现

    简介 最上面的是根结点 这棵树中存的单词是apple app all bat 如果IsWord为True 就说明从根节点连到这个结点的字母组成的是一个单词 使用前缀树查询的时候时间复杂度只和单词的长度相关 实现 import java ut
  • ctfshow-内部赛

    登录就有flag签退蓝瘦出题人不想跟你说话 jpg 登录就有flag 经过一番固定的注入尝试发现 1 长度限制为5 2 存在过滤且过滤的字符会有回显 能留下来的字符很少这里列出 gt lt 在排除一下 gt lt 可以只留等于号 逗号和点号
  • 多线程编程与互斥锁

    一 线程理论基础 在操作系统原理的术语中 线程是进程的一条执行路径 线程在Unix系统下 通常被称为轻量级的进程 线程虽然不是进程 但却可以看作是Unix进程的表亲 所有的线程都是在同一进程空间运行 这也意味着多条线程将共享该进程中的全部系
  • 浅谈前后端分离

    一 前端 前后端分离已成为互联网项目开发的业界标准使用方式 通过nginx tomcat的方式 也可以中间加一个nodejs 有效的进行解耦 并且前后端分离会为以后的大型分布式架构 弹性计算架构 微服务架构 多端化服务 多种客户端 例如 浏
  • ElasticSearch安装与整合

    1 wget https artifacts elastic co downloads elasticsearch elasticsearch 6 2 4 tar gz 下载es 环境要求 2 启动elasticsearch 使用 sh b
  • 1、图解Oracle Logminer配置使用

    LogMiner配置使用手册 1 Logminer简介 1 1 LogMiner介绍 Oracle LogMiner 是Oracle公司从产品8i以后提供的一个实际非常有用的分析工具 使用该工具可以轻松获得Oracle 在线 归档日志文件中
  • PostgreSQL 备份与恢复

    http www wohedb com db html doc administrator guide adm 9 backup and restore htm www wohedb com 中文数据库 第九章 备份与恢复 PostgreS
  • LeetCode题目笔记——463. 岛屿的周长,/C++

    文章目录 题目描述 题目难度 简单 方法一 迭代 代码 方法二 深度优先遍历DFS 代码 总结 题目描述 给定一个 row x col 的二维网格地图 grid 其中 grid i j 1 表示陆地 grid i j 0 表示水域 网格中的
  • 通过jr-qrcode生成二维码并下载到客户端本地(Vue)

    生成二维码 首先生成二维码图片的地址 引入jr qrcode import jrQrcode from jr qrcode 生成二维码图片的地址 生成二维码地址 getQRCodeUrl spreadUrl const QRCodeUrl
  • 修改环境变量引起的bash 出错 解决方案

    来自 http www iteye com wiki blog 1244124 打开ubuntu 发现了 bash 的出错信息 如下 上网检索了一下 发现是环境变量有错误 找了多种方法 下面的方法是有效的一种 错误信息 Command le
  • C++函数

    C 函数 函数是一组一起执行一个任务的语句 与C程序类似 每个 C 程序都至少有一个函数 即主函数 main 通过函数 还可以把一个复杂任务分解成为若干个易于解决的小任务 充分体现结构化程序设计由粗到精 逐步细化的设计思想 即将任务合理划分