【问题标题】:C++ Passing Static Array and Dynamic Array By ReferenceC++ 通过引用传递静态数组和动态数组
【发布时间】:2015-02-26 04:44:25
【问题描述】:

为了完全理解指针、值和引用是如何工作的,我正在编写一个基本的 C++ 程序,该程序试图篡改一些静态和动态数组,并准确理解它们应该如何传入。

首先我生成一个包含 3 个元素的静态数组。然后我将它传递给一个修改所有元素的函数。然后我将它传递给另一个签名稍有不同的函数,但也可以更改数组的值。

接下来我生成一个动态大小的数组,通过引用将它传递给一个函数,以便可以更改这个动态大小的数组中的所有值。

代码如下:

#include "stdafx.h"
#include <iostream>
#include <string>

using namespace std;

void changeIndexStaticArrayMethod1(int* stat);
void changeIndexStaticArrayMethod2(int (&stat)[3]);
void changeIndexDynamicArrayMethod1(int* dyn, int size);

int main() {
    const int MAX = 3;
    int arr[MAX] = { 1,2,3 };

    changeIndexStaticArrayMethod1(arr);
    cout << arr[0] << endl;
    cout << arr[1] << endl;
    cout << arr[2] << endl;
    cout << endl;
    changeIndexStaticArrayMethod2(arr);
    cout << arr[0] << endl;
    cout << arr[1] << endl;
    cout << arr[2] << endl;

    int SIZE;
    cout << "Please choose a size for the array" << endl;
    cin >> SIZE;

    int *ne = new int[SIZE];
    //Build array
    for (int i = 0; i < SIZE; i++) {
        ne[i] = i;
    }

    changeIndexDynamicArrayMethod1(ne, SIZE);
    for (int i = 0; i < SIZE; i++) {
        cout << "ne[" << i << "] = " << ne[i] << endl;
    }


    //To hang program
    cin >> SIZE;

    delete[] arr;
    delete[] ne;
    return 0;
}

void changeIndexStaticArrayMethod1(int* stat) {
    stat[0] = 10;
    stat[1] = 20;
    stat[2] = 30;
}

void changeIndexStaticArrayMethod2(int (&stat)[3]) {
    stat[0] = 40;
    stat[1] = 50;
    stat[2] = 60;
}

void changeIndexDynamicArrayMethod1(int* dyn, int size) {
    for (int i = 0; i < size; i++) {
        dyn[i] = i * 10;
    }
}

以上所有代码都按我的意愿工作,我只是对为什么有几个问题(我在其他 SO 问题上找到了一些通过引用传递数组的方法)。

  • 在changeIndexStaticArrayMethod1() 和changeIndexDynamicArrayMethod1() 函数中,为什么我们可以使用解引用* 操作符作为我们数组的引用?我的下意识反应是,实际上是按值传递数组,因为它是取消引用运算符。我知道使用数组,它与使用变量有很大不同,而且,为什么以下内容不适用于单个 int 变量:

    void changeStaticNumber(int* num){ 数 = 100; }

显然,如果我们使用&amp;num 而不是int* num,上述方法将起作用,显然我并不完全理解指针和数组之间的关系,但我无法弄清楚为什么当我们通过引用传递数组时,@ 987654327@就可以了。

对我遇到的这些问题的任何解释将不胜感激。谢谢。

【问题讨论】:

  • 当数组作为参数传递给函数时,它会衰减为指针。参见例如stackoverflow.com/questions/1461432/what-is-array-decaying.
  • 所以我会在将它传递给函数时与它进行交互,就像我与指向某种地址的常规旧指针变量进行交互一样?
  • 指针指向数组的第一个元素。您可以像使用原始数组标识符一样使用它,除了丢失有关数组中元素数量的信息(并且 sizeof 不再有效)。
  • 你也忘了尝试std::vector

标签: c++ arrays pointers reference pass-by-reference


【解决方案1】:

为什么我们可以对我们的数组使用解引用 * 操作符作为引用?

C 中的* 有很多含义。它可以表示一元间接(“内容”)运算符,可以表示二进制乘法运算符,也可以表示指针声明。 int* stat 是一个指针声明。

由于您没有使用 * 来取消引用该函数内指针的内容,我不太确定您在问什么。

当您在 main() 中获取数组的数组名称时,它“衰减”为指向第一个元素的指针。那么这些函数所做的就是按值获取指针。如果您通过键入 *stat = something; 取消引用指针,您将访问 main 中的实际数组。

如果你做一些奇怪的事情比如改变指针本身,例如stat++;,那么它不会影响main中使用的地址。您通过值传递指针本身,因此指针是本地副本。

我的下意识反应是,实际上是按值传递数组,因为它是取消引用运算符。

如果不使用肮脏的技巧(将它们存储在结构或类中),您无法真正在 C 或 C++ 中按值传递数组。例如,如果你的函数写成void changeIndexStaticArrayMethod1(int stat[3]),它仍然会给你一个指向第一个元素的指针。它不会按值传递数组,因为语法可能会诱使您相信。

为什么以下内容不适用于单个 int 变量:

void changeStaticNumber(int* num){ num = 100; }

因为num 是指针本身,而不是它的内容。为了编写这样的代码,您可以通过引用int&amp; num 传递变量。言下之意,这实际上与传递指针是一回事,只是语法更简单。

要更好地理解指针和数组之间的关系,请从阅读整章开始:http://c-faq.com/aryptr/index.html(在指针方面,C 和 C++ 是相同的)。

【讨论】:

  • 好的,所以int* num 不适用于常规变量,因为如果您想编辑原始值,您需要将它们传入,这样您就可以访问它们的地址,该地址通过引用传递(@ 987654332@) 确实如此。如果 main() 中的数组名称衰减为指向第一个元素地址的指针,则可以通过执行以下操作来接受地址:void f(int n*),这是有道理的,因为您正在创建指向您所在地址的指针传入。但是,为什么 (&arr)[N] 有效? &amp; 不是多余的吗?以及为什么这可以保留您使用 sizeof() 的能力,而使用 ptr 则不能。
  • @DomFarolino 不确定“int* num 不适用于常规变量”是什么意思。您当然仍然可以访问指向的变量,与引用相比只是语法不同。 (&amp;arr)[N] 是对 N 个元素的数组的引用。它之所以有效,是因为 C++ 这么说,您只能传递给定大小的数组,因此可以使用 sizeof。指针没有这种类型安全性,您可以传递任意大小的数组,它会衰减为指向第一个元素的指针,其中包含有关所指向数据大小的所有信息。
【解决方案2】:

让我看看我是否可以尝试一下。

指针只是地址持有者。一旦你做了 int * ptr = myarray; --- 你在实习期间所做的是将我的数组的指针地址存储到 ptr 中 --- 数组名实际上是指向数组中第一个内存位置的指针。您可以使用指针算法来获取其他所有内容,例如 myarray +1 将指向下一个位置或 myarray[1]。

当您需要修改数组时,按值传递不是很有用。通过引用传入本质上是创建一个指向数组的指针并传递它。由于像向量这样的数组是连续的内存块,因此您可以很容易地对它们进行索引。

就您的示例而言 void changeStaticNumber(int* num){ num = 100; } 将不起作用,因为您尝试做的是将 100 存储到指针的地址中。如果您尊重 num 并将其设为 void changeStaticNumber(int* num){ *num = 100;它会起作用,因为您实际上要更进一步并访问 num 指向的数据。当您使用 &num 时,它本质上是相同的 - & 只是为您提供某物的地址。

例如,如果你想指向一个 int 的指针,你会做的是

int num = 5; int *ptr = &num;

此时ptr在num中具有相同的地址。要打印出 num 中的数据或 ptr 指向的数据,您需要取消引用或更进一步,因为我想告诉自己并取消引用所以 cout &lt;&lt; *ptr;

【讨论】:

  • 我知道你说的所有东西,这很困难,因为数组是一个指针。我认为你的措辞帮助很大。说得有道理吗,既然数组是一个指针,我们必须将我们的函数参数(一个指针)设置为等于我们数组的地址(第一个元素+指针算术),这样我们才能真正改变原始地址的值指的是我们函数在函数中的指针变量?对我来说这是有道理的,因为如果我们想设置一个指针等于我们的数组,我们必须说 int*parray = &array.在将数组传递给函数的情况下..
  • 函数参数充当指针。并且传入的数组作为地址...现在似乎有意义
  • 上面的 int *ptr = array 是在函数中设置的方式。对于数组和向量,不需要 & ——名称是一个指针。在一个函数中,这对动态的东西很有用。传递时 - & 是您提供地址的方式,因此您传递的地址是正确的!这是通过引用传递的——所有数据都可以访问。如果您更改函数中传递数组的任何数据点,它将在声明和初始化的原始数组中更改它。如果您想限制可访问性,请使用 const - 您可以在数组和指针上使用它。
【解决方案3】:

changeIndexStaticArrayMethod1changeIndexDynamicArrayMethod1 中,您都没有传递数组,因此没有通过引用传递(仅当参数类型是引用类型时才会发生 - 即使用&amp;)。该参数的类型为int *(指向int 的指针)。您正在传递一个指向int 按值的指针。两个函数中都没有“取消引用运算符”。

ne 已经是int *,所以传递它并没有什么特别的。 arr 是一个 int [3],一个数组,而不是一个指针。在 C 中,当T 的数组在需要指向T 的指针的上下文中使用时,它会隐式转换(无需您做任何事情)到指向其第一个元素的指针。因此,当您这样做时,changeIndexStaticArrayMethod1(arr),编译器会获取指向arr 的第一个元素的指针,并将其传递给函数。

[] 运算符适用于指针。 a[i] 始终保证与 *(a + i) 相同。在changeIndexStaticArrayMethod1changeIndexDynamicArrayMethod1 函数中,[] 用于使用指向第一个元素的指针访问后续元素。

【讨论】:

    猜你喜欢
    • 2012-04-20
    • 1970-01-01
    • 2010-10-06
    • 1970-01-01
    • 1970-01-01
    • 2022-12-04
    • 2013-04-06
    • 1970-01-01
    • 2018-06-30
    相关资源
    最近更新 更多