C++菜鸟学习笔记系列(18)——函数参数传递

简介: C++菜鸟学习笔记系列(18)——函数参数传递

C++菜鸟学习笔记系列(18)

本期主题:函数参数传递

形参的初始化机理和变量初始化一样,与之类似的,形参的类型决定了形参和实参交互的方式。如果形参是引用类型时,我们说它对应的实参被引用传递或者函数被传引用调用。和其他引用一样,引用形参是他绑定对象的别名,也就是说引用形参是它对应的实参的别名。

当实参的值被拷贝给形参时,形参和实参是两个相互独立的对象,我们说这样的实参被值传递或者函数被传值调用。

(1)传值参数

当初始化一个非引用类型的变量时,初始值被拷贝给变量。此时,对变量的改动不会影响初始值。

我们来看一个小例子:

/*
author: wxc_1998
date: 2018/10/31
*/
#include <iostream>
using namespace std;
int reset(int i);
void main()
{
  int val1,val2;
  cout << "please inpute a integer:" << endl;
  cin >> val1;
  val2 = reset(val1);
  cout << "the original value is: " << val1 << endl;
  cout << "we reset " << val1 << " to " << val2 << endl;
  cout << "please input any key to continue!" << endl;
  cin.clear();
  cin.sync();
  cin.get();
}
int reset(int i)
{
  i = 0;
  return i;
}

我们可以看到变量val1的值在经过reset函数的处理之后并没有发生改变。

(2)传引用参数

我们在C++菜鸟学习笔记系列(4)——引用、指针中也曾经介绍过对于传引用操作实际上就是作用在引用所绑定的对象上。引用形参也是类似的,通过使用引用形参,允许函数改变一个或多个实参的值。

下面我们把上一部分中介绍的reset函数改写一下:

void reset(int &i)
{
  i = 0;
}

这样我们调用reset函数时,形参i仅仅是实参val1的一个别名,我们在函数中对形参i所做的全部操作实质上都是直接作用在实参val1上的。

当然我们也可以使用指针形参实现类似的效果,但是与之不同的是如果我们使用了指针形参,那么我们在调用函数时需要使用取地址符获得实参的地址。

例如:

void reset(int *i)
{
  *i = 0;
}

这时我们需要通过

reset( &val )

调用函数。


与第一种介绍的传值参数相比,传引用参数更加高效,例如在拷贝大的类型对象及容器对象时,这一优点会体现的更加明显,还有一些类型并不支持拷贝操作,这时就只能通过引用形参访问该类型的对象。


引用形参还有一个非常重要的优点是我们可以通过引用形参返回额外的信息(弥补return函数只能返回一个参数的不足)。


下面我们来看一个关于引用形参使用的小例子:

/*
author: wxc_1998
date: 2018/10/31
*/
#include <iostream>
#include <string>
using namespace std;
int find_c(const string &str,const char c, int &occurs);
void main()
{
  string s;
  char c;
  int count = 0, f = 0;
  cout << "please input a world: "<< endl;
  cin >> s;
  cout << "please input the char of you want to find in " << s << endl;
  cin >> c;
  f = find_c(s, c, count);
  cout << "the first location of " << c << " is " << f+1 << endl;
  cout << c << " have been found " << count << " times in " << s << endl; 
  cout << "please input any key to continue!" << endl;
  cin.clear();
  cin.sync();
  cin.get();
}
int find_c(const string &str, char c, int &occurs)
{
  int ff = str.size();
  for (int i = 0; i != str.size(); ++ i)
  {
    if (str[i] == c)
    {
      if (ff == str.size())
      {
        ff = i;
      }
      ++ occurs;
    }
  }
  return ff;
}

小提示:如果函数无须改变引用形参的值,最好将其声明为常量引用。(关于这个大家自己百度理解)

(3)数组形参

数组的两个特殊性质对我们定义和使用作用在数组上的函数有影响:

 1.不允许拷贝数组。
 2.使用数组时会把其转换成指针。

第一个特性让我们无法以值传递的方式使用数组参数,第二个特性决定了我们在为函数传递一个数组时,实际上是传递了一个指向数组首元素的指针。

数组的引用形参:在我们使用数组的引用作为形参时,要注意符号的优先级,例如:

void prin (doule &a[10]);// error
void prin (doule (&a) [10]);//right

第一种错误的把a声明成立引用的数组,第二种才是正确的具有10个双精度的double类型数组的引用。


传递多维数组:我们在前面也曾经说过,C++中并没有真正的多维数组,所谓的多维数组只是数组的数组。

因为我们处理的是数组的数组,所以将多维数组传递给函数时,真正传给函数的是指向一个数组的指针。数组的第二个维度及其后的所有维度的大小都是数组类型的一部分不能省略。


好了,这次我们就写到这里了,下次再见!


注:虽然这篇博客的内容十分简单,但是大家若有转载还请标明出处!

目录
相关文章
|
17天前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
28天前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
43 6
|
28天前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
21 0
C++ 多线程之线程管理函数
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
23 3
|
1月前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
123 1
|
1月前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
25 1
|
1月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
37 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
21天前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
21 4
|
21天前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
19 4
|
20天前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
17 1