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++中并没有真正的多维数组,所谓的多维数组只是数组的数组。

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


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


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

目录
相关文章
|
3月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
3月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
94 6
|
3月前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
48 0
|
3月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
41 3
|
3月前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
430 1
|
3月前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
54 1
|
3月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
72 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
2月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
60 2
|
2月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
110 5
|
2月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
109 4