【问题标题】:Passing an array as an argument in C++在 C++ 中将数组作为参数传递
【发布时间】:2010-10-20 07:34:59
【问题描述】:

我正在编写一个合并排序函数,而现在我只是在使用一个测试用例数组(没有输入 - 目前是静态的)。我不知道如何将数组作为参数传递。这是我现在的代码:

//merge sort first attempt

#include <iostream>

#include <algorithm>

#include <vector>

int mergeSort(int[]);
int main() {
    int originalarray[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
    mergeSort(originalarray[]);
}

int mergeSort(int[] originalarray) {
    int num = (sizeof(originalarray) / sizeof(int));
    std::vector < int > original(num);

    if (num > 2) {
        return num;
    }

    // Fill the array using the elements of originalarray
    // This is just for demonstration, normally original will be a parameter,
    // so you won't be filling it up with anything.
    std::copy(originalarray, originalarray + num, original.begin());

    // Create farray and sarray of the appropriate size
    std::vector < int > farray(num / 2);
    std::vector < int > sarray(num - farray.size());

    // Fill those using elements from original
    std::copy(original.begin(), original.begin() + farray.size(), farray.begin());
    std::copy(original.begin() + farray.size(), original.end(), sarray.begin());

    mergeSort(farray);
    mergeSort(sarray);
}

请注意,此 mergeSort 函数不起作用,因为我还没有弄清楚如何合并它们(这是我的任务)。我想在处理它之前对我的两个向量进行排序,但我无法编译它,因为我需要将数组作为参数传递。我不明白指针,所以如果这是解决方案,我的借口是无知。我现在正在学习编程,以 C++ 作为第一语言,并且只对语言的特性有一个基本的掌握。感谢您的帮助。

【问题讨论】:

  • 一些推荐阅读:gnomesane.net/code/doc/ptrarray
  • mergeSort(originalarray[]) 格式不正确。您需要以下函数的定义 mergeSort(originalarray, arraySize);数组总是通过函数中的地址/引用传递,您还需要数组的大小来迭代它们。

标签: c++ arrays sorting mergesort divide-and-conquer


【解决方案1】:

只是为了扩展一点,请记住 C++ 数组完全是 C 数组。所以你所拥有的只是一块内存的地址,它声称(没有保证)是一个数组。

更新

好的,我们再扩展一点。

C(因此 C++)并没有真正的“数组”。它只有地址,指针。所以当你把某个东西变成一个“数组”时,真正发生的事情是你告诉编译器某个变量代表一个地址。

在C 中区分声明定义 是很有用的。在声明中,您只是简单地给某物一个名称和一个类型;在定义中,您实际上分配了空间。

所以,如果我们从定义一个数组开始,比如

int ar[100];

这意味着我们告诉编译器我们想要 100 个int 的空间,我们希望它们都被分配到一个块中,我们将使用名称ar 来表示它。 sizeof 运算符给出类型或对象使用的字节数,因此我们的数组 ar 将占用 100×sizeof(int) 字节。在大多数机器上,这将是 400 字节,但它因机器而异。

如果我们定义一个变量

int * ar_p;   // using '_p' as a reminder this is a pointer

我们正在为包含地址的变量定义空间。它的大小将是sizeof(int*),通常是 4 或 8,但在某些机器上可能是 2 到 16 之间的任何值,而在某些您不太可能很快遇到的机器上。

数组的名称ar。编译器将该名称转换为地址,因此我们可以将该地址保存为

ar_p = ar ;     // THIS WORKS

现在,为了方便,假设我们的数组 ar 恰好从内存中的位置 1000 开始。

那个名字ar确实没有有任何空间分配给它;它就像一个常数,一个数字。所以,你不能撤销那个任务

ar = ar_p ;     // THIS WON'T WORK

出于同样的原因,你不能说

1000 = ar_p ;   // THIS WON'T WORK EITHER

即,您无法更改 1000 的值。(在早期版本的 FORTRAN 中,由于复杂的原因,这个技巧会起作用。这是一个错误。直到您尝试调试一个“2”的值为3的程序。)

C 中的数组始终从零开始,即第一个索引始终为零。任何其他索引只是使用索引计算的地址。所以,ar[0] 只是地址 1000 加上 0 个字节的偏移量,或 1000。ar[1] 是 1000 加上 int 大小的 1 倍,所以 next int 结束了。事实上,这在 C 中总是如此。

这称为数组引用

当我们使用语法*ar_p 时,我们是在告诉编译器在ar_p 中包含的地址处获取东西。 `.

这称为取消引用指针

如果我们说

ar_p = ar;

那么*ar_par[0] 指的是同一个东西。

当我们说ar[0] 时,我们是在告诉编译器我们想要ar 的地址0 字节处的东西。 ar[1] 是地址 1 int,或 4 个字节,来自 ar。所以,*(ar_p+3)ar[3] 指的是同一件事。 (我们需要括号,因为我们要先将地址加 3,然后再查看内容。*ar_p+3 会先获取 ap_p 指向的内容,然后再将其加 3。

问题是,C 不知道,或者很在意数组到底有多大。如果我来做ar[365],编译器会很高兴地生成代码来查看单元格1000+(365×sizeof(int))。如果它在你的数组中,很好,但如果它只是随机内存,那也很好。 C 不在乎。

(记住 C 来自电话公司。“我们不在乎;我们不必这样做。我们是电话公司。”)

所以,现在,我们知道了一些规则,我已经把它们移到了这里。将“≡”读作“等同于”或“相同于”。

你可以依赖什么:

  • foo(TYPE t[])foo(TYPE * t)

由于 C 不知道指针和数组之间的区别,您可以声明其中任何一个。当你定义一个函数时,你可以写

void foo(int[] ar){

void foo(int* ar){

并获得完全相同的效果。

  • t[i]*(t+i)

这是上面的。任何你可以写ar[i] 的地方,你都可以用*(ar+i) 替换它。 (实际上有一个奇怪的案例打破了这一点,但作为初学者你不会遇到它。)

  • 其中TYPE *t(t+i) 将等于t 的地址加上i*sizeof(TYPE)

上面也解释了这一点。当你索引到一个数组时,比如ar[42],这意味着你想要从起始地址开始的第 42 个。所以,如果你使用int,那么无论int有多宽,你都需要移动42次,也就是说sizeof(int)

现在,这就是 C,而且由于 C++ 被定义为“一种”C,所以它也适用于 C++。除了

  • 除非TYPE 是重载operator[]operator* 的用户定义类型。

在 C++ 中,您可以决定要定义一个与任何其他类型一样的新类型,但您可以更改语言执行特定操作的方式。因此,程序员可以决定用他们自己设计的东西“重载”——即替换——数组引用和指针取消引用运算符的默认行为。作为初学者,您不应该很快就遇到这种情况,但您应该意识到这一点。

【讨论】:

  • 我认为你高估了我的知识,因为我知道你刚才所说的。我目前正在学习编程,还没有学习指针或 C++ 的 OOP 部分。
  • 这是一个非常好的 C++ 数组细分。我很高兴我使用 .NET/Java! :)
  • 感谢 Alex 的客气话,但实际上理解这一点也会对您对 Java/C# 的理解产生重大影响。例如,当你说 Object a = new Object(); 时你会得到什么在爪哇。 “a”到底是什么?
【解决方案2】:

你不应该这样使用sizeof(originalarray)/sizeof(int)。它仅适用于静态声明的数组(大小在编译时已知)。您必须将大小连同它一起传递。为什么不直接从数组中创建一个 vector 并传递它呢?

旁注:根据经验,请始终注意sizeof 将在编译时进行翻译。所以它不可能知道作为参数传递的数组的大小。

【讨论】:

  • 我不明白你的意思。我应该把所有元素都复制到一个向量中并传递它吗?如何将 sizeof() 与向量一起使用?
  • 您不要在矢量上使用 sizeof。 v.size() 将获取大小。您应该这样做,或者如果您想传递一个数组,请将大小作为另一个参数传递。
【解决方案3】:

我看到你包括&lt;vector&gt;。我建议你不要使用数组,只使用 vector 类。您可以查看如何使用 STL 容器的示例,例如 vector here

【讨论】:

    【解决方案4】:
    • 当您将数组传递给函数时,它们会衰减为指向数组第一个元素的指针,尽管有符号。因此,您的 sizeof 无法按预期工作。

    • 传入数组时,最好传入数组大小,这样就知道在哪里停下了。将其添加为附加参数。

    【讨论】:

      【解决方案5】:

      除了以上所有答案,您可能还想查看来自 c-faq.com 的数组问答:http://c-faq.com/aryptr/index.html

      【讨论】:

        【解决方案6】:

        不幸的是,很难在 C 或 C++ 中完全按照您的意愿进行操作。你可以像这样传递一个固定大小的数组:

        int mergeSort(int originalarray[20])
        {
            // do something
        }
        

        但是,数组的大小不是由数字定义的,而是由初始化列表中元素的数量定义的。

        在您的情况下要做的事情(即使这样做确实是错误的事情)是分两步进行:

        int originalarray[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
        const size_t arraySize = sizeof originalarray / sizeof originalarray[0];
        int mergeSort(int array[arraySize])
        {
            // do something
        }
        

        太糟糕了,它不会做你需要做的事情:将数组传递给这样的函数会生成数组的副本,排序的重点是更改原始数组。

        实际上,如果不了解“指针”的概念,您就无法再进一步了。

        你真正需要开发的功能应该是这样的:

        int originalarray[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
        const size_t arraySize = sizeof originalarray / sizeof originalarray[0];
        
        int mergeSort(int *array, const size_t size)
        {
            // do something
        }
        
        mergeSort(&(originalArray[0]), arraySize);
        

        换句话说,你传递一个指向第一个元素的指针,以及元素的数量。

        或者,您可以处理向量。 Vector 将相同的两件事(指向第一个元素的指针和大小)封装在一个称为“对象”的实体中。此外,它还为您管理内存,因此您可以根据需要扩展元素的数量。这是 C++ 的方式。太糟糕了,你不能像数组一样用 {...} 初始化向量。

        【讨论】:

          【解决方案7】:

          看起来你同时使用了动态分配的数组和向量,而我相信只使用 std::vector 就足够了。

          首先,将您的输入数组更改为 std::vector,并用您的输入数据填充它。

          int main()
          {
             std::vector<int> originalarray;
             for (int data = 1; data <= 10; data++)
             {
                originalarray.push_back(data);
             }
             mergeSort(originaldata);
          }
          

          现在声明合并排序函数以引用 std::vector 很重要。

          int mergeSort(std::vector<int>& originalarray)
          {
             // The rest of your code, note that now you are passing 
             // in your array for sorting, so you can continue with your code to split
             // the vector into farray and sarray
          
             // then call sort on your halves.
             mergeSort(farray);
             mergeSort(sarray);
          
             // I'm guessing at this point you'd write code to combine your farray sarray, and
             // put it back into originalarray...don't forget to clear original array first!
          }
          

          请注意,您似乎没有进行就地排序,因此预计您的排序需要一段时间,因为您要复制大量数据。

          【讨论】:

            猜你喜欢
            • 2017-03-19
            • 2011-12-30
            • 1970-01-01
            • 2010-10-01
            • 2013-07-24
            • 2022-01-09
            相关资源
            最近更新 更多