C++入门基础07:函数定义与声明、函数传参(传值、传地址、传引用)、函数重载

news2024/12/23 23:33:30

C++入门基础07:函数定义与声明、函数传参(传值、传地址、传引用)、函数重载

1、函数定义与声明

函数是一起执行一个任务的一组语句。每个程序(C/C++)都有一个主函数 main() ,
所有简单的程序都可以定义其他额外的函数。可以把代码划分到不同的函数中,函数
划分通常是根据每个函数执行一个特定的任务来进行的。

函数定义的语法
函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:

int max(int x, int y)
{
 //函数体
}

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

函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
参数:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
函数主体:函数主体包含一组定义函数执行任务的语句。

函数声明
函数声明会告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。
如下是一个函数声明:
int max(int num1, int num2);
在函数声明中,参数的名称并不重要,只有参数的类型是必需的,因此下面也是有效的声明:
int max(int, int);
当您在一个源文件中定义函数且在另一个文件中调用函数时,函数声明是必需的。在这种情况下,您应该在调用函数的文件顶部声明函数。

函数声明告诉编译器函数的名称、返回类型和参数。
函数定义提供了函数的实际主体。
C++中常将声明与定义分开。
函数必须先声明或者定义才能使用。

函数调用
当程序调用函数时,程序控制权会转移给被调用的函数。
被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。
调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。

下面这个代码会报错:

#include <iostream>
//系统定义头文件一般是尖括号
#include<fstream>
#include<string>
#include<exception> //标准库的头文件,标准的异常
#include<cstring>
using namespace std;


int print_string(string x)
{
    fun(x);
    if (x.empty())
        return -1;
    cout << x << endl;
    return 0;
}

string fun(string str)
{
    return str;
}

int main()
{
    string str = "cplusplus";
    int res = print_string(str);
    if(res == -1)
    {
        cout << "input string is empty!" << endl;
    }

    return 0;
}

报错内容是找不到fun标识符。
在这里插入图片描述
这是由于fun函数是在print_string函数之后,那么在定义print_string函数的时候,fun函数还没定义,就不知道这个函数的名称。所以会报错。函数还没有声明。

如果要解决这个报错就需要将这个fun函数的声明放到print_string函数之前。
下面代码是将fun函数在print_string函数前声明了,就不会报错了。

#include <iostream>
//系统定义头文件一般是尖括号
#include<fstream>
#include<string>
#include<exception> //标准库的头文件,标准的异常
#include<cstring>
using namespace std;

string fun(string str); //声明fun函数,fun函数在print_string函数前声明了,就不会报错了。
//参数的名称并不重要,这里我们将参数名删除也是不会报错的。

int print_string(string x)
{
    fun(x);
    if (x.empty())
        return -1;
    cout << x << endl;
    return 0;
}

string fun(string str)
{
    return str;
}

int main()
{
    string str = "cplusplus";
    int res = print_string(str);
    if(res == -1)
    {
        cout << "input string is empty!" << endl;
    }

    return 0;
}

在这里插入图片描述

此外在声明函数时参数的名称并不重要,这里我们将参数名删除也是不会报错的。
就如下面代码中fun函数的声明,参数的参数名删除了,也没有报错,是可以编译成功的。

#include <iostream>
//系统定义头文件一般是尖括号
#include<fstream>
#include<string>
#include<exception> //标准库的头文件,标准的异常
#include<cstring>
using namespace std;

//string fun(string str); //声明fun函数,fun函数在print_string函数前声明了,就不会报错了。
string fun(string ); //fun函数的声明,参数的参数名删除了,不会报错。


int print_string(string x)
{
    fun(x);
    if (x.empty())
        return -1;
    cout << x << endl;
    return 0;
}

string fun(string str)
{
    return str;
}

int main()
{
    string str = "cplusplus";
    int res = print_string(str);
    if(res == -1)
    {
        cout << "input string is empty!" << endl;
    }

    return 0;
}

在这里插入图片描述

2、 函数传参

函数传参有三种传参方式:传值、传址、传引用。
1、按值传递
(1)形参和实参各占一个独立的存储空间。
(2)形参的存储空间是函数被调用时才分配的,调用开始,系统为形参开辟一个临时的存储区,然后将各实参传递给形参,这是形参就得到了实参的值。
2、地址传递
地址传递与值传递的不同在于,它把实参的存储地址传送给形参,使得形参指针和实参指针指向同一块地址。因此,被调用函数中对形参指针所指向的地址中内容的任何改变都会影响到实参。
3、引用传递
引用传递是以引用为参数,则既可以使得对形参的任何操作都能改变相应数据,又使函数调用方便。引用传递是在形参调用前加入引用运算符“&”。引用为实参的别名,和实参是同一个变量,则他们的值也相同,该引用改变则它的实参也改变。

传值与传引用的差别:
1 传引用时,形参和实参是同一个变量,即使用相同的内存空间,二者有相同的地址。而传值时二者地址不同;
2 传引用时,由于没有新建变量,所以对于类对象参数,不会产生构造和析构。而如果是传值调用,调用时会进行构造,退出函数时会进行析构,会有性能的消耗,能传引用的地方就传引用;
3 由于传引用使用的是原本实参的地址,所以对引用参数值的修改,会在退出函数后体现在主调函数中,而传值调用对参数的修改不会影响到主调函数。

传地址的例子(传指针):
可以发现输出cout的地址是一样的。

#include <iostream>
//系统定义头文件一般是尖括号
#include<fstream>
#include<string>
#include<exception> //标准库的头文件,标准的异常
#include<cstring>
using namespace std;

//传指针
int print_string(string *x)
{
    if ((*x).empty()) //这里(*x)是对指针的一个解引用。
        return -1;
    cout << "取x地址:" << x << endl;
    return 0;
}

int main()
{
    string str = "cplusplus";
    int res = print_string(&str); //传一个地址,取str变量的地址。
    cout << "取str地址:" << &str << endl;
    if(res == -1)
    {
        cout << "input string is empty!" << endl;
    }

    return 0;
}

在这里插入图片描述

传引用的例子:
引用相当于实际参数的一个别名,所以可以直接使用。也就是和传实际参数是一样的。
引用的参数改变,对应的原本参数值也会改变。就如下面这个代码:

#include <iostream>
//系统定义头文件一般是尖括号
#include<fstream>
#include<string>
#include<exception> //标准库的头文件,标准的异常
#include<cstring>
using namespace std;


//传引用
//引用相当于实际参数的一个别名,所以可以直接使用。也就是和传实际参数是一样的。
int print_string(string &x)
{
    if (x.empty()) //这里(*x)是对指针的一个解引用。
        return -1;
    cout << "x的内容:" << x << endl;
    x = "cpp";//这里改变了参数的值。
    cout << "x改变内容:" << x << endl;
    return 0;
}

int main()
{
    string str = "cplusplus";
    int res = print_string(str); //将变量本身传进去。
    cout << "str的内容:" << str << endl; //这里可以看到变量本身也是改变了。
    if(res == -1)
    {
        cout << "input string is empty!" << endl;
    }

    return 0;
}

在这里插入图片描述

3、函数重载

C++ 允许在同一作用域中的某个函数指定多个定义,这就是函数重载。

重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。

当调用一个重载函数时,编译器通过把你所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数的过程,称为重载决策。

在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形参(如参数的个数、类型或者顺序)必须不同,不能仅通过返回类型的不同来重载函数。

如下代码中同名函数 print() 被用于输出不同的数据类型:

 void print(int i) {
 cout << "整数为: " << i << endl;
 }
 void print(double f) {
 cout << "浮点数为: " << f << endl;
 }
 void print(char c[]) {
 cout << "字符串为: " << c << endl;
 }

注意,参数列表不同包括参数的个数不同、类型不同或顺序不同,仅仅参数名称不同是不可以的。函数返回值也不能作为重载的依据。

函数的重载的规则:
函数名称必须相同。

参数列表必须不同(个数不同、类型不同、参数排列顺序不同等)。

函数的返回类型可以相同也可以不相同。

仅仅返回类型不同不足以成为函数的重载。

C++代码在编译时会根据参数列表对函数进行重命名(不同的编译器有不同的重命名方式,这里仅仅举例说明,实际情况可能并非如此),例如 void print(int i)会被重命名为_print_int,void print(float f)会被重命名为_print_float。当发生函数调用时,编译器会根据传入的实参去逐个匹配,以选择对应的函数,如果匹配失败,编译器就会报错。

因此,函数重载只是在用户层面看到的函数名称是一致的,本质上它们还是不同的函数,占用不同的内存,函数地址也不一样。

#include <iostream>
//系统定义头文件一般是尖括号
#include<fstream>
#include<string>
#include<exception> //标准库的头文件,标准的异常
#include<cstring>
using namespace std;

//定义了三个函数,这三个函数的参数列表不同。
//这三个函数的功能都是返回较大的那个值。

int mymax(int x, int y)
{
    cout << "call max int!" << endl;
    return (x > y) ? x : y;
}

float mymax(float x, float y)
{
    cout << "call max float!" << endl;
    return (x > y) ? x : y;
}

char mymax(char x, char y)
{
    cout << "call max char!" << endl;
    return (x > y) ? x : y;
}

int main()
{
    int a = 10, b = 100;
    cout << mymax(a, b) << endl;

    char c = 'a', d = 'A';
    cout << mymax(c, d) << endl;

    float e = 10.1f, f = 100.3f;
    cout << mymax(e, f) << endl;

    return 0;
}

在这里插入图片描述

这里将float型和char型的mymax注释掉了。可以看到依然是可以执行的,都是调用的int型的mymax函数了,只不过都进行隐式转换,转换到了int类型。

#include <iostream>
//系统定义头文件一般是尖括号
#include<fstream>
#include<string>
#include<exception> //标准库的头文件,标准的异常
#include<cstring>
using namespace std;

//定义了三个函数,这三个函数的参数列表不同。
//这三个函数的功能都是返回较大的那个值。

int mymax(int x, int y)
{
    cout << "call max int!" << endl;
    return (x > y) ? x : y;
}

//float mymax(float x, float y)
//{
//    cout << "call max float!" << endl;
//    return (x > y) ? x : y;
//}
//
//char mymax(char x, char y)
//{
//    cout << "call max char!" << endl;
//    return (x > y) ? x : y;
//}

int main()
{
    int a = 10, b = 100;
    cout << mymax(a, b) << endl;

    char c = 'a', d = 'A';
    cout << mymax(c, d) << endl;

    float e = 10.1f, f = 100.3f;
    cout << mymax(e, f) << endl;

    return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/78309.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1563_AURIX_TC275_EVR的控制寄存器

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 1. 连续的写入必须确保是解锁状态&#xff0c;否则的话可能会导致所有的总线阻塞。 2. 多核系统中&#xff0c;尽量写入之后再读取一下确认写入的状态。 这里是过压以及欠压的几个监控结果…

if、for、while结构的用法

分支与循环的流程控制一、分支流程控制1. if分支语句结构1). 单分支2). 双分支3). 三元运算符&#xff08;双分支的简化&#xff09;4). 多分支二. 循环流程控制1. while循环语句语法结构1.while循环用法2.while 的死循环3. while else的用法2. for循环语句语法结构1. for和ran…

嵌入式开发学习之--串口通讯(上)

提示&#xff1a;本篇开始学习各种通讯方式&#xff0c;重中之重。 文章目录前言一、 串口通讯协议简介1.1 物理层1.2 协议层1.2.1 基本组成。1.2.2 波特率1.2.3 起始和终止位1.2.4 有效数据1.2.5 数据校验二、USART结构体详解总结前言 作为一个嵌入式的开发者&#xff0c;解析…

网页木马挂马的实现与防范

一、网页挂马是什么 不少用户都碰到过这样的现象&#xff1a;打开一个网站&#xff0c;结果页面还没显示&#xff0c;杀毒软件就开始报警&#xff0c;提示检测到木马病毒。有经验的朋友会知道这是网页恶意代码&#xff0c;这就是典型的网页挂马现象。那么是什么原因导致了这种…

数据库概论之MySQL表的增删改查 - 进阶版本1

MySQL表的增删改查 - 进阶1、数据库约束1.1 约束类型1.2 NULL约束1.3 UNIQUE约束1.4 DEFAULT约束1.5 PRIMARY约束1.6 FOREIGN KEY外键约束1.6.1 语法1.6.2 工作原理2、表的设计2.1 一对一2.2 一对多2.3 多对多大家好&#xff0c;已经好久没更新了 , 学校的学业有点忙 , 没有额外…

[论文解析] Denoising Diffusion Probabilistic Models

文章目录OverviewsWhat problem is addressed in the paper?What is the key to the solution?What is the main contribution?Contents扩散概率模型背景算法实验结论Overviews What problem is addressed in the paper? We present high quality image synthesis result…

【Java面试】说说类加载机制(流程)

文章目录加载流程装载(Load)链接(Link)验证(Verify)准备(Prepare)解析(Resolve)初始化(Initialize)卸载(Unload)加载流程 类的加载流程如下&#xff1a; 转载(Load)->链接(Link)->初始化(Initialize)->使用(Use)->卸载(Unload) 其中链接又包含验证(Verify)&#x…

rabbitMQ延时队列——TTL和DLX

一. 场景&#xff1a;“订单下单成功后&#xff0c;15分钟未支付自动取消” 1.传统处理超时订单 采取定时任务轮训数据库订单&#xff0c;并且批量处理。其弊端也是显而易见的&#xff1b;对服务器、数据库性会有很大的要求&#xff0c; 并且当处理大量订单起来会很力不从…

flask前后端项目--实例-前端部分:-4-vue-Element Plus

flask前后端项目--实例-前端部分&#xff1a;-4-vue-Element Plus组件添加事项 一、实验测试步骤 1.Element Plus添加 1.先备份App.VUE&#xff0c;然后修改app.vue的内容&#xff0c;数据来源资Element Plus的表格table 2. 数据来源资Element Plus的表格table 3. 运行服务&…

023_SSS_Neural 3D Video Synthesis from Multi-view Video(CVPR2022)

Neural 3D Video Synthesis from Multi-view Video(CVPR2022) 本文提出了一种新的3D视频生成方法&#xff0c;这种方法能够以紧凑但富有表现力的表示形式表示动态真实世界场景的多视图视频记录&#xff0c;从而实现高质量的视图合成和运动插值。 1. Introduction 本文的主要…

百度地图 ( 一 ) 显示地图

1.百度地图 百度地图开放平台 https://lbsyun.baidu.com/ 使用百度地图时导入JavaScript包 <script type"text/javascript" src"http://api.map.baidu.com/api?v2.0&ak您的密钥"></script>1.1.如何申请 ak 密钥 在 开发平台 找 控制…

ChatGPT注册流程

1.访问官网点击 Sign up https://chat.openai.com/auth/login 2.输入你的邮箱 3.点击Continue下一步: 4.输入密码继续下一步&#xff1a; 5.然后你的邮箱会受到一封邮件&#xff08;如果没收到请检查垃圾邮箱&#xff09;&#xff1a; 6.点击验证邮箱按钮&#xff0c;会跳到…

MySQL 5.7中文乱码与远程链接问题

MySQL 5.7中文乱码与远程链接问题1. MySQL 5.7中文乱码2. 远程链接问题3. 不区分表大小写4. 超过最大连接数5. 时区问题5. GROUP BY 问题配置集合重启MySQL1. MySQL 5.7中文乱码 当我们直接在数据库里面输入中文时&#xff0c;保存后出现&#xff1a; Incorrect string value&…

LeetCode 第 244 场周赛题解

前言 这是 2021-06-06 的一场 LeetCode 周赛&#xff0c;本场周赛的题目相较而以往而言比较简单&#xff0c;基本上想到点上就可以做出来&#xff0c;主要涉及到矩阵的旋转、贪心、滑动窗口、前缀和、二分查找等知识点。 第 244 场周赛链接&#xff1a;https://leetcode-cn.c…

SpringBoot+Vue实现前后端分离的学校快递站点管理系统

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…

机器人开发--雷达lidar

机器人开发--雷达lidar1 介绍2 分类2.1 整体分类2.2 机械式&#xff08;三角&ToF&#xff09;三角测距激光雷达ToF测距激光雷达3 机械式单线ToF激光雷达3.1 扫描原理3.2 不同材料反射率3.3 核心参数参考1 介绍 激光雷达&#xff08;英文&#xff1a;Laser Radar &#xff…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java制造类企业erp23725

面对老师五花八门的设计要求&#xff0c;首先自己要明确好自己的题目方向&#xff0c;并且与老师多多沟通&#xff0c;用什么编程语言&#xff0c;使用到什么数据库&#xff0c;确定好了&#xff0c;在开始着手毕业设计。 1&#xff1a;选择课题的第一选择就是尽量选择指导老师…

第十四周周报

学习目标&#xff1a; 一、论文“Vector Quantized Diffusion Model for Text-to-Image Synthesis”的Code 二、猫狗识别、人脸识别模型 学习内容&#xff1a; Code 学习时间&#xff1a; 12.4-12.9 学习产出&#xff1a; 一、论文Code 正向过程&#xff1a; 先通过Tam…

Python——学生管理系统

实现学生系统的增&#xff0c;删&#xff0c;查&#xff0c;打印所有学生功能&#xff0c;分别介绍使用列表存储和使用文件存储的代码 使用列表存储 import sys students []def menu():print("1. 新增学生")print("2. 显示学生")print("3. 查找学生…

【OpenCV学习】第10课:形态学操作的应用-图像去掉干扰线丶干扰点

仅自学做笔记用,后续有错误会更改 理论 去干扰线干扰点的操作方法&#xff0c; 大体上与第9课所说的提取水平/垂直线一致&#xff0c; 只是把核改为矩形&#xff0c; 不要线型就行&#xff0c;反正都是通过开操作来实行的。 操作流程&#xff1a; 输入图像&#xff08;一般是…