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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/763861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:10:47  来源:igfitidea点击:

Passing an array as an argument in C++

c++arrayssortingmergesortdivide-and-conquer

提问by jkeys

I'm writing a merge sort function, and right now I am just using a test case array (there is no input - this is static, for now). I don't know how to pass an array as an argument. Here is my code right now:

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

//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);
}

Note that this mergeSort function is not functional, as I have not figured out how to merge them yet (that's my assignment). I would like to get my two vectors sorted before I deal with that, and I can't compile this because of my need to pass an array as an argument. I don't understand pointers, so if that is the solution, my excuse is ignorance. I'm learning programming right now, with C++ as a first language, and only have a basic grasp of the language's features. Thanks for the help.

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

回答by Charlie Martin

Jut to extend this a bit, remember that C++ arrays are exactlyC arrays. So all you have is the address of a piece of memory that purports (with no guarantees) to be an array of somethings.

为了稍微扩展一下,请记住 C++ 数组正是C 数组。所以你所拥有的只是一块声称(不保证)是一个数组的内存的地址。

Update

更新

Okay, we'll expand a little more.

好的,我们再扩展一点。

C (and therefore C++) doesn't really have "arrays" as such. All it has are addresses, pointers. So when you make something an "array", what really happens is you tell the compiler that some variable represents an address.

C(以及因此 C++)并没有真正的“数组”。它只有地址和指针。因此,当您将某些东西创建为“数组”时,真正发生的事情是您告诉编译器某个变量表示一个地址。

It's useful to make a distinction in C between a declarationand a definition. In a declaration, you're simply giving something a name and a type; in a definition, you actually allocate space.

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

So, if we start off by definiing an array like

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

int ar[100];

that means we're telling the compiler we want space for 100 int's, we want it to all be allocated in one chunk, and we're going to use the name arfor it. The sizeofoperator gives the number of bytes used by a type or an object, so our array arwill take up 100×sizeof(int)bytes. On most machines, that will be 400 bytes, but it varies from machine to machine.

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

If we define a variable

如果我们定义一个变量

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

we're defining space for a variable that will contain an address. Its size will be sizeof(int*), which will usually be either 4 or 8, but on some machines could be anything from 2 to 16 on some machines you're unlikely to run into soon.

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

The nameof the array is ar. The compiler converts that name into an address, so we can save that address with

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

ar_p = ar ;     // THIS WORKS

Now, let's say for convenience that our array arhappened to be starting at location 1000 in memory.

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

That name ardoes nothave any space allocated to it; it's like a constant, a number. So, you can't reverse that assignment

这个名字ar不会为它分配任何空间; 它就像一个常数,一个数字。所以,你不能撤销那个分配

ar = ar_p ;     // THIS WON'T WORK

for the same reason you couldn't say

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

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

ie, you can't change the value of 1000. (Back in early versions of FORTRAN, this trick would work, for complicated reasons. It was a mistake. You've never lived until you've tried to debug a program in which the value of "2" is 3.)

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

Arrays in C are always zero-based, that is, the first index is always zero. Any other indices are just addresses computed using the index. So, ar[0]is just the address 1000 plus 0 bytes of offset, or 1000. ar[1]is 1000 plus 1 times the size of an int, so the nextint over. And in fact, this is always true in C.

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

This is called an array reference.

这称为数组引用

When we use the syntax *ar_pwe're telling the compiler to get the thing AT the address contained in ar_p. `.

当我们使用语法时,*ar_p我们是在告诉编译器获取包含在ar_p. `.

This is called dereferencing a pointer.

这称为取消引用指针

If we say

如果我们说

ar_p = ar;

then *ar_pand ar[0]refer to the same thing.

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

When we say ar[0]we're telling the compiler we want the thing at the address 0 bytes from ar. ar[1]is the address one int, or 4 bytes, from ar. So, *(ar_p+3)refers to the same thing as ar[3]. (We need the parentheses because we want to add 3 to the address first and then look at the contents. *ar_p+3would get the contents pointed to by ap_pfirst, and then add 3 to those.

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

The thing is, C doesn't know, or much care, how big the array really is. If I come along and do ar[365], the compiler will happily generate code to look in the cell 1000+(365×sizeof(int)). If that's in your array, fine, but if it's just random memory, that's fine too. C doesn't care.

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

(Remember C comes from the phone company. "We don't care; we don't have to. We're the Phone Company.")

(记住 C 来自电话公司。“我们不在乎;我们没有必要。我们是电话公司。”)

So, now, we know some rules, which I've moved down here. Read "≡" as "is equivalent to" or "is the same as".

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

What you can depend on:

您可以依赖的内容:

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

Since C doesn't know a difference between pointers and arrays, you can declare either one. When you define a function, you can write

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

void foo(int[] ar){

or

或者

void foo(int* ar){

and get exactly the same effect.

并获得完全相同的效果。

  • t[i]*(t+i)
  • t[i]*(t+i)

This was above. Anywhere you might write ar[i], you can replace it with *(ar+i). (There's actually a weird side case that breaks this, but you won't run into it as a beginner.)

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

  • where TYPE *t, (t+i)will equal the address at tplus i*sizeof(TYPE)
  • 其中TYPE *t,(t+i)将等于t加号处的地址i*sizeof(TYPE)

Explained this above as well. When you index into an array, like ar[42], it means you want the 42nd whatever over from the start address. So, if you're using int, then you need to move over 42 times however wide an intis, which is to say sizeof(int).

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

Now, that's all C, and since C++ is defined as a "kind of" C, it all holds for C++ as well. EXCEPT

现在,这就是所有的 C,并且由于 C++ 被定义为“一种”C,因此它也适用于 C++。除了

  • unless TYPEis a user defined type that overloads operator[]and operator*.
  • 除非TYPE是重载operator[]和的用户定义类型operator*

in C++, you can decide you want to define a new type that acts just like any other type, but you can change the way the language does specific things. So, a programmer candecide to "overload" -- ie, replace -- the default behavior of the array reference and pointer dereference operators with something of their own devising. As a beginner, you shouldn't be confronted with that soon, but you should be aware of it.

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

回答by Mehrdad Afshari

You should not use sizeof(originalarray)/sizeof(int)like that. It'll only work for statically declared arrays (the size is known at compile time). You have to pass the size along with it. Why don't you just make a vectorout of the array and pass it instead?

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

Side Note:As a rule of thumb, always note that sizeofwill be translated at compile time. So there's no way it could know the size of the array passed as an argument.

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

回答by Assaf Lavie

I see you include <vector>. I suggest you do away with all uses of arrays and only use the vectorclass. You can see examples of how to use STL containers such as vectorhere.

我看你包括<vector>. 我建议你不要使用数组,只使用vector类。您可以vector在此处查看如何使用 STL 容器的示例。

回答by dirkgently

  • When you pass arrays to functions, they decay to pointers to the first element of the array, the notation notwithstanding. So, your sizeofdoesnot work as expected.

  • When you pass in an array, it is best to pass in the array size, so that you know where to stop. Add it as an additional parameter.

  • 当您将数组传递给函数时,它们会衰减为指向数组第一个元素的指针,尽管有表示法。所以,你没有sizeof按预期工作。

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

回答by Ye Liu

In addition to all the answers above, you might also want to check out the Q&As on arrays from c-faq.com: http://c-faq.com/aryptr/index.html

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

回答by Ye Liu

Unfortunately, it's very hard to do exactly what you want to do in C or C++. You can pass around a fixed-size array like this:

不幸的是,很难在 C 或 C++ 中准确地做你想做的事。您可以像这样传递固定大小的数组:

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

However, your array's size is not defined by a number, it's defined by the number of elements in initialization list.

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

The thing to do in your case (even though it's really a wrong thing to do) is to do it in two steps:

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

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
}

Too bad it will not do what you need done: passing the array to a function like this makes a copy of the array, and the point of sorting would be to change the original array.

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

In truth, you cannot go any further without understanding the concept of "pointer".

事实上,如果不理解“指针”的概念,你就不能再进一步了。

The function you need to develop really should be like this:

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

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);

In other words, you pass a pointer to first element, and the number of elements.

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

Alternatively, you can deal with vectors. Vector encapsulates the same two things (pointer to first element and size) in a single entity called "object". Plus, it manages memory for you, so you can extend the number of elements as you need. This is the C++ way. Too bad you can't initialize a vector with {...} like you can an array.

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

回答by Snazzer

Looks like you're using both dynamically allocated arrays and vectors, when I believe just using std::vector will be enough.

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

First, let your input array be changed to a std::vector, and fill it with your input data.

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

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

Now it's important to declare your mergesort function to take a reference to a std::vector.

现在声明合并排序函数以引用 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!
}

Just a note, looks like you're not doing an inplace sort, so expect your sort to take a while since you're copying out a lot of data.

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