c++之函数形参和实参讲解

1、非地址型参数

在c++中实现模块化编程时,我们形成会遇到对自定义的函数模块传入参数的操作,即形参。这里主要讲解一个非地址型的形参。

不多说,先看代码:

 #include <iostream>

 using namespace std;

 void changeNumber(int num){
     num ++;
 }

 int main(){
     ;
     //猜猜num的值是多少
     changeNumber(num);
     cout << "num = " << num << endl;
     ;
 }

我们从上面的代码可以看到,我们通过一个函数模块对num的值进行了修改,但是最后的输出会是多少呢,是10还是9呢。

我们来看一下控制台的输出结果:

输出结果显示的9,而不是10,那么这是为什么呢,在这之前我们先看看函数体内部的值是多少。

我们可以看到函数体内部的num的值是10,而主函数内的num依旧是9,并没有改变。

这是因为,传入给changeNumber(num);函数模块的num是一个形参,因为,函数的返回值是一个void类型,也就是无类型,那么该函数模块只是执行函数模块内部的代码并不会返回任何的值。但是就是说,虽然都是一个叫做num的变量,但是在changeNumber(num);体内,num的作用域仅仅在函数模块体内有用,一旦函数模块执行完毕,那么num的作用域也就结束了。实际上是内存中有两块不同的内存空间,他们的变量名都是num,但是实际上的值确实不一样的。如下图所示:

从图中我们可以看到主函数和自定义函数模块中的num变量的内存地址是不一样的。

但是如果我们换一种写法那就是截然不同的结果。

看代码:

 #include <iostream>

 using namespace std;

 void changeNumber(int &num){ <-修改的地方  加了一个&符号
     num ++;
     cout << &num <<" in the model : num = " << num << endl;

 }

 int main(){
     ;
     //猜猜num的值是多少
     changeNumber(num);
     cout << &num << " num = " << num << endl;
     ;
 }

从代码中我们可以看到,我仅仅只是在changeNumber()函数模块的形参部分修改了一点点,也就是加了一个引用的符号,取地址的意思,这样的结果将是截然不同,

看运行结果图:

从结果图中,我们可以看到,主函数和函数模块内部的变量num都是同一个变量(内存地址一样就是一样的变量),且最终在主函数中的num和函数模块里面的num的值都发生了改变。

原因:在非数组型形参中,形参只是实参的一份拷贝,也就是说是一个局部变量,通过变量对该变量赋值改变其值,只是在一个局部作用域中对变量进行改变,但是全部的变量(变量名相同)并没有改变。但是数组型形参是与此不同。

2.地址型参数

当我们给自定义的函数模块传入的是一个数组时,那么传入的就是当前数组的第一个元祖的地址,因为在内存中,数组就是一串连续的地址空间。先来看一段代码:

#include <iostream>

using namespace std;

void changeNumber(int &num){
    num ++;
    cout << &num <<" in the model : num = " << num << endl;

}

void changeArray(int arrayInt[], int len){ //此时传入的是数组的第一个元素的地址,类似指针操作
    /*
    if(len > sizeof(arrayInt) / sizeof(int)){
        cout << "输入的数组大小越界。" << endl;
    }
    ; i < len;i++){
        arrayInt[i] = i;
    }
}

void printArray(int arrayyInt[], int len){
    /*
    cout << "len= " << len<<endl;
    cout << "sizeof(arrayInt) / sizeof(int)= " << sizeof(arrayInt) / sizeof(int) <<endl;//输出为1

    因为传入的数组是一个头元素的地址也即指针地址,所以只有单位长,也就是一个int单位长,所以得到的值为1
    在main函数体内得到的值为真实的数组的大小长度

    if(len > (signed)(sizeof(arrayInt) / sizeof(int)) ){  //前者是有符号整数,后者是无符号整数

        cout << "输入的数组大小越界。" << endl;
    }
    */
    //打印

    cout << ;i<len;i++){
        cout << arrayyInt[i] <<endl;
    }
    cout << "-----print-----" <<endl;
}

int main()
{

    ]{,,,,};//原始数组的数值
    cout << "原始输出:" <<endl;
    cout << "arrayInt=" <<endl;
    printArray(arrayInt,);
    //开始改变

    changeArray(arrayInt,sizeof(arrayInt) / sizeof(int));
    cout << "改变之后:"<<endl;
    cout <<"arrayInt=" <<endl;
    printArray(arrayInt,sizeof(arrayInt) / sizeof(int));
    ;
}

运行结果如图所示:

从图中可以看到,同样的操作,对于int型的整数num和对于只能存放int型的数组来讲,c++对其做的改变是不一样的。这里对形参的操作其实也是对实参的操作,因为如果对数组实参进行一份拷贝的话,会增加很大的内存消耗,所以c++就直接修改了实参值。

当然对于数组的操作,还有一种指针的传参方式,先看代码:

 void printPointArray(int* arrayInt,int len){
     ;i<len;i++){
         cout << *(arrayInt+i) << endl;
     }
 }

从代码中我们看到,我们只是修改了打印数组的一个自定义函数,数组的参数传递有两种方式,一种是指针的方式:void printPointArray(int* arrayInt,int len),另一种是数组的方式:void printArray(int arrayInt[],int len),不管哪一种,都是传入一个数组的首地址。

c++之函数形参和实参的更多相关文章

  1. python之函数形参、实参、可变长参数整体使用和分类

    形参与实参 '''def fn(形参们): pass fn(实参们)'''# 形参:定义函数,在括号内声明的变量名,用来结束外界传来的值# 实参:调用函数,在括号内传入的实际值,值可以为常量.变量.表 ...

  2. python函数—形参、实参、位置参数、关键字参数

    1.通过def function_name([parameter]): 定义,函数一遇到return即结束运行.如果函数没有定义返回值,则返回None,如果定义了一个返回值,则返回该对象,如果一个re ...

  3. 【学习笔记】--- 老男孩学Python,day10, 初识函数 形参、实参

    函数:对功能的封装语法: def 函数名(形参): 函数体 函数名(实参) 函数名:命名规则和变量一样 函数的返回值: return, 函数执行完毕. 不会执行后面逻辑 1. 如果函数中不写retur ...

  4. js函数形参和实参的区别

    在<Javascript权威指南>中这样定义: 参数有形参(parameter)和实参(argument)的区别,形参相当于函数中定义的变量,实参是在运行时的函数调用时传入的参数. 说明白 ...

  5. C++函数形参与实参交换

    c++中函数的实参传递到形参的值是单向的,改变形参并不会影响实参. #include <iostream> using namespace std; void swap(int a, in ...

  6. JavaScript中函数的形参和实参的实现原理剖析

    我们都知道JS里面参数的传递是可以不一样的,比如我们有一个函数: <script type="text/javascript"> function one(a,b,c) ...

  7. javascript . 03 函数定义、函数参数(形参、实参)、函数的返回值、冒泡函数、函数的加载、局部变量与全局变量、隐式全局变量、JS预解析、是否是质数、斐波那契数列

    1.1 知识点 函数:就是可以重复执行的代码块 2.  组成:参数,功能,返回值 为什么要用函数,因为一部分代码使用次数会很多,所以封装起来, 需要的时候调用 函数不调用,自己不会执行 同名函数会覆盖 ...

  8. Pyhton函数篇(一)之函数中的形参与实参

    1:什么是函数 函数其实就是带名字的代码块,用于完成一些具体的工作.如果我们在写一段程序的时候,需要多次用到同样的一个功能,如果每次都要重复写相同的代码,不仅会增加我们的代码量,更会让我们写出的代码让 ...

  9. 函数的形参和实参之arguments对象

    当函数调用函数时候传入的实参比函数声明时候制定的形参要少时候,剩余的形参就设置成了undefined.例如 function getPropertyNames(o,/*optional*/a){ va ...

随机推荐

  1. loadrunner--步长(Pacing)的设置及作用

    Pacing时间的设置需要根据使用您系统的用户的行为来决定. 如果您那边的用户在您的系统上做完一套操作后不会做下一套,则可能不需使用Pacing. 如果您那边用户在系统上需要不断地做同样的操作,比如他 ...

  2. 仅仅 IE8 有效的 CSS hack 写法

    IE8 CSS hack 就是在属性后面加上 \9 或者 \0,代码如下: color:#FFF\0; /* IE8 */ color:#FFF\9; /* 所有IE浏览器(ie6+) */ 上面的 ...

  3. mybatis Generator 生成配置文件

    <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE generatorConfiguration ...

  4. [GO]go使用contextCancel

    package main import ( "fmt" "context" ) func main() { gen := func(ctx context.Co ...

  5. HDU 6065 RXD, tree and sequence (LCA+DP)

    题意:给定上一棵树和一个排列,然后问你把这个排列分成m个连续的部分,每个部分的大小的是两两相邻的LCA的最小深度,问你最小是多少. 析:首先这个肯定是DP,然后每个部分其实就是里面最小的那个LCA的深 ...

  6. .NET基础 (21)ASP NET应用开发

    ASP.NET中的WebForm相关的内容其实有点儿过时了,但在很多的老项目中还是WebForm的,这些都是遗留问题,新上的项目基本上都用MVC了,在微软最新的 ASP.NET 的版本中已经默认使用M ...

  7. Vivado 2017封装自定义IP Core

    使用Vivado2017.3自定义IP Core.通常情况下,我们做设计采用模块化设计,对于已经设计好的一部分模块功能,就可以直接拿来调用,IP Core就是这样来的,一般来说我们看不到IP Core ...

  8. 自我介绍+github注册

    我是网络工程141的蒋易,学号是1413042018 个人兴趣:打篮球,打羽毛球,打游戏 github注册流程 id:Scorpio1 注册困难:1.刚开始网页没打开. 2.全英文的界面无法看懂,要查 ...

  9. Blend 2015 教程 (五) 自定义状态

    本篇再补充一块内容,就是自定义状态的介绍. 自定义状态用于封装用户控件在各种状态之间切换时的外观变化及其动画效果,方便调用.比如有个用户控件用于实现类似舞台幕布打开和关闭切换的效果,可以创建幕布关闭和 ...

  10. webservice需要的包以及demo

    包地址:http://pan.baidu.com/s/1qWyPgqo demo:http://pan.baidu.com/s/1dDvNJg9