繁体   English   中英

在C ++中将数组作为参数传递

[英]Passing an array as an argument in C++

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

//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 ++作为第一语言,并且对语言的功能只有基本的了解。 谢谢您的帮助。

为了稍微扩展一下,请记住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字节的偏移量,即ar[1]是1000加上int大小的1倍,因此下一个 int结束了。 实际上,在C语言中总是如此。

这称为数组引用

当我们使用*ar_p语法时,我们告诉编译器将事物AT包含在ar_p包含的地址中。 `。

这称为取消引用指针

如果我们说

ar_p = ar;

然后*ar_par[0]指的是同一件事。

当我们说ar[0]我们告诉编译器我们想要的东西是ar的地址0字节。 ar[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 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倍,即int宽度,即sizeof(int)

现在,仅此而已,并且C ++被定义为C的“一种”,因此C ++也同样适用。

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

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

您不应该这样使用sizeof(originalarray)/sizeof(int) 它仅适用于静态声明的数组(大小在编译时已知)。 您必须将尺寸和它一起传递。 您为什么不只是从数组中生成一个vector ,然后传递它呢?

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

我看到您包括<vector> 我建议您不要使用数组的所有用法,而只能使用vector类。 您可以在此处查看有关如何使用STL容器(例如vector示例。

  • 当您将数组传递给函数时,尽管使用了这种表示法,它们也会衰减到指向数组第一个元素的指针。 因此,您的sizeof无法正常工作。

  • 传递数组时,最好传递数组大小,以便您知道在哪里停止。 将其添加为附加参数。

除上述所有答案外,您可能还想从c-faq.com上对阵列进行Q&A检查: http ://c-faq.com/aryptr/index.html

不幸的是,很难完全按照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);

换句话说,您将指针传递给第一个元素和元素数。

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

看起来您正在同时使用动态分配的数组和向量,但是我相信仅使用std :: vector就足够了。

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

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

现在,重要的是声明您的mergesort函数以引用对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!
}

请注意,您似乎没有进行就地排序,因此,由于要复制大量数据,因此预计您的排序会花费一些时间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM