简体   繁体   English

C ++从函数返回指向数组的指针的正确方法

[英]C++ correct way to return pointer to array from function

I am fairly new to C++ and have been avoiding pointers.我对 C++ 相当陌生,并且一直在避免使用指针。 From what I've read online I cannot return an array but I can return a pointer to it.根据我在网上阅读的内容,我无法返回数组,但可以返回指向它的指针。 I made a small code to test it and was wondering if this was the normal / correct way to do this:我编写了一个小代码来测试它,并想知道这是否是执行此操作的正常/正确方法:

#include <iostream>
using namespace std;

int* test (int in[5]) {
    int* out = in;
    return out;
}

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int* pArr = test(arr);
    for (int i = 0; i < 5; i++) cout<<pArr[i]<<endl;
    cout<<endl;
    return 0;
}

Edit : This seems to be no good.编辑:这似乎不好。 How should I rewrite it?我应该如何重写它?

int* test (int a[5], int b[5]) {
    int c[5];
    for (int i = 0; i < 5; i++) c[i] = a[i]+b[i];
    int* out = c;
    return out;
}

Your code as it stands is correct but I am having a hard time figuring out how it could/would be used in a real world scenario.您的代码目前是正确的,但我很难弄清楚它在现实世界中如何/将如何使用。 With that said, please be aware of a few caveats when returning pointers from functions:话虽如此,请注意从函数返回指针时的一些注意事项:

  • When you create an array with syntax int arr[5];当您使用语法int arr[5];创建数组时int arr[5]; , it's allocated on the stack and is local to the function. ,它在堆栈上分配并且是函数的局部变量。
  • C++ allows you to return a pointer to this array, but it is undefined behavior to use the memory pointed to by this pointer outside of its local scope. C++ 允许您返回指向此数组的指针,但在其本地范围之外使用此指针指向的内存是未定义的行为 Read this great answer using a real world analogy to get a much clear understanding than what I could ever explain. 使用现实世界的类比阅读这个很棒的答案,以获得比我无法解释的更清晰的理解。
  • You can still use the array outside the scope if you can guarantee that memory of the array has not be purged.如果您能保证阵列的内存没有被清除,您仍然可以在范围之外使用该阵列。 In your case this is true when you pass arr to test() .在您的情况下,当您将arr传递给test()时,这是正确的。
  • If you want to pass around pointers to a dynamically allocated array without worrying about memory leaks, you should do some reading on std::unique_ptr / std::shared_ptr<> .如果您想在不担心内存泄漏的情况下传递指向动态分配数组的指针,则应该对std::unique_ptr / std::shared_ptr<>进行一些阅读。

Edit - to answer the use-case of matrix multiplication编辑 - 回答矩阵乘法的用例

You have two options.你有两个选择。 The naive way is to use std::unique_ptr / std::shared_ptr<> .天真的方法是使用std::unique_ptr / std::shared_ptr<> The Modern C++ way is to have a Matrix class where you overload operator * and you absolutely must use the new rvalue references if you want to avoid copying the result of the multiplication to get it out of the function.现代 C++ 方法是拥有一个Matrix类,您可以在其中重载operator *并且如果您想避免复制乘法的结果以将其从函数中取出,则绝对必须使用新的rvalue references In addition to having your copy constructor , operator = and destructor , you also need to have move constructor and move assignment operator .除了拥有copy constructoroperator =destructor ,您还需要具有move constructormove assignment operator Go through the questions and answers of this search to gain more insight on how to achieve this.浏览此搜索的问题和答案,以更深入地了解如何实现这一目标。

Edit 2 - answer to appended question编辑 2 - 对附加问题的回答

int* test (int a[5], int b[5]) {
    int *c = new int[5];
    for (int i = 0; i < 5; i++) c[i] = a[i]+b[i];
    return c;
}

If you are using this as int *res = test(a,b);如果你使用它作为int *res = test(a,b); , then sometime later in your code, you should call delete []res to free the memory allocated in the test() function. ,然后在稍后的代码中,您应该调用delete []res以释放在test()函数中分配的内存。 You see now the problem is it is extremely hard to manually keep track of when to make the call to delete .您现在看到的问题是手动跟踪何时调用delete非常困难。 Hence the approaches on how to deal with it where outlined in the answer.因此,在答案中概述了如何处理它的方法。

Your code is OK.你的代码没问题。 Note though that if you return a pointer to an array, and that array goes out of scope, you should not use that pointer anymore.请注意,如果您返回一个指向数组的指针,并且该数组超出范围,则不应再使用该指针。 Example:例子:

int* test (void)
{
    int out[5];
    return out;
}

The above will never work, because out does not exist anymore when test() returns.以上将永远不会起作用,因为当test()返回时out不再存在。 The returned pointer must not be used anymore.不得再使用返回的指针。 If you do use it, you will be reading/writing to memory you shouldn't.如果你确实使用它,你将读取/写入你不应该的内存。

In your original code, the arr array goes out of scope when main() returns.在您的原始代码中,当main()返回时, arr数组超出范围。 Obviously that's no problem, since returning from main() also means that your program is terminating.显然这没问题,因为从main()返回也意味着您的程序正在终止。

If you want something that will stick around and cannot go out of scope, you should allocate it with new :如果你想要一些可以坚持并且不能超出范围的东西,你应该用new分配它:

int* test (void)
{
    int* out = new int[5];
    return out;
}

The returned pointer will always be valid.返回的指针将始终有效。 Remember do delete it again when you're done with it though, using delete[] :请记住,使用delete[]完成后再次删除它:

int* array = test();
// ...
// Done with the array.
delete[] array;

Deleting it is the only way to reclaim the memory it uses.删除它是回收它使用的内存的唯一方法。

New answer to new question:新问题的新答案:

You cannot return pointer to automatic variable ( int c[5] ) from the function.您不能从函数返回指向自动变量 ( int c[5] ) 的指针。 Automatic variable ends its lifetime with return enclosing block (function in this case) - so you are returning pointer to not existing array.自动变量以返回封闭块(在本例中为函数)结束其生命周期 - 因此您将返回指向不存在数组的指针。

Either make your variable dynamic:要么使您的变量动态:

int* test (int a[5], int b[5]) {
    int* c = new int[5];
    for (int i = 0; i < 5; i++) c[i] = a[i]+b[i];
    return c;
}

Or change your implementation to use std::array :或者更改您的实现以使用std::array

std::array<int,5> test (const std::array<int,5>& a, const std::array<int,5>& b) 
{
   std::array<int,5> c;
   for (int i = 0; i < 5; i++) c[i] = a[i]+b[i];
   return c;
}

In case your compiler does not provide std::array you can replace it with simple struct containing an array:如果您的编译器不提供std::array您可以将其替换为包含数组的简单结构:

struct array_int_5 { 
   int data[5];
   int& operator [](int i) { return data[i]; } 
   int operator const [](int i) { return data[i]; } 
};

Old answer to old question:旧问题的旧答案:

Your code is correct, and ... hmm, well, ... useless.你的代码是正确的,而且……嗯,好吧,……没用。 Since arrays can be assigned to pointers without extra function (note that you are already using this in your function):由于可以将数组分配给没有额外函数的指针(请注意,您已经在函数中使用了 this):

int arr[5] = {1, 2, 3, 4, 5};
//int* pArr = test(arr);
int* pArr = arr;

Morever signature of your function:您的功能的更多签名:

int* test (int in[5])

Is equivalent to:相当于:

int* test (int* in)

So you see it makes no sense.所以你看它没有意义。

However this signature takes an array, not pointer:但是这个签名需要一个数组,而不是指针:

int* test (int (&in)[5])

A variable referencing an array is basically a pointer to its first element, so yes, you can legitimately return a pointer to an array, because thery're essentially the same thing .引用数组的变量基本上是指向其第一个元素的指针,所以是的,您可以合法地返回指向数组的指针,因为它们本质上是相同的 Check this out yourself:自己检查一下:

#include <assert.h>

int main() {
  int a[] = {1, 2, 3, 4, 5}; 

  int* pArr = a;
  int* pFirstElem = &(a[0]);

  assert(a == pArr);
  assert(a == pFirstElem);

  return 0;
}

This also means that passing an array to a function should be done via pointer (and not via int in[5] ), and possibly along with the length of the array:这也意味着数组传递给函数应该通过指针(而不是通过int in[5] )完成,并且可能与数组的长度一起:

int* test(int* in, int len) {
    int* out = in;
    return out;
}

That said, you're right that using pointers (without fully understanding them) is pretty dangerous.也就是说,您是对的,使用指针(没有完全理解它们)是非常危险的。 For example, referencing an array that was allocated on the stack and went out of scope yields undefined behavior :例如,引用在堆栈上分配并超出范围的数组会产生未定义的行为

#include <iostream>

using namespace std;

int main() {
  int* pArr = 0;
  {
    int a[] = {1, 2, 3, 4, 5};
    pArr = a; // or test(a) if you wish
  }
  // a[] went out of scope here, but pArr holds a pointer to it

  // all bets are off, this can output "1", output 1st chapter
  // of "Romeo and Juliet", crash the program or destroy the
  // universe
  cout << pArr[0] << endl; // WRONG!

  return 0;
}

So if you don't feel competent enough, just use std::vector .因此,如果您觉得自己不够胜任,只需使用std::vector

[answer to the updated question] [回答更新的问题]

The correct way to write your test function is either this:编写test函数的正确方法是:

void test(int* a, int* b, int* c, int len) {
  for (int i = 0; i < len; ++i) c[i] = a[i] + b[i];
}
...
int main() {
   int a[5] = {...}, b[5] = {...}, c[5] = {};
   test(a, b, c, 5);
   // c now holds the result
}

Or this (using std::vector ):或者这个(使用std::vector ):

#include <vector>

vector<int> test(const vector<int>& a, const vector<int>& b) {
  vector<int> result(a.size());
  for (int i = 0; i < a.size(); ++i) {
    result[i] = a[i] + b[i];
  }
  return result; // copy will be elided
}

In a real app, the way you returned the array is called using an out parameter .在实际应用中,返回数组的方式是使用 out 参数调用的 Of course you don't actually have to return a pointer to the array, because the caller already has it, you just need to fill in the array.当然你实际上并不需要返回一个指向数组的指针,因为调用者已经有了它,你只需要填充数组。 It's also common to pass another argument specifying the size of the array so as to not overflow it.传递另一个参数来指定数组的大小以避免溢出也是很常见的。

Using an out parameter has the disadvantage that the caller may not know how large the array needs to be to store the result.使用 out 参数的缺点是调用者可能不知道数组需要多大才能存储结果。 In that case, you can return a std::vector or similar array class instance.在这种情况下,您可以返回 std::vector 或类似的数组类实例。

Your code (which looks ok) doesn't return a pointer to an array.您的代码(看起来不错)不会返回指向数组的指针。 It returns a pointer to the first element of an array.它返回一个指向数组第一个元素的指针。

In fact that's usually what you want to do.事实上,这通常是你想要做的。 Most manipulation of arrays are done via pointers to individual elements, not via pointers to the array as a whole.大多数对数组的操作都是通过指向单个元素的指针完成的,而不是通过指向整个数组的指针来完成的。

You can define a pointer to an array, for example this:可以定义指向数组的指针,例如:

double (*p)[42];

defines p as a pointer to a 42-element array of double s.p定义为指向 42 个元素的double s 数组的指针。 A big problem with that is that you have to specify the number of elements in the array as part of the type -- and that number has to be a compile-time constant.这样做的一个大问题是您必须指定数组中元素的数量作为类型的一部分——并且该数量必须是编译时常量。 Most programs that deal with arrays need to deal with arrays of varying sizes;大多数处理数组的程序需要处理不同大小的数组; a given array's size won't vary after it's been created, but its initial size isn't necessarily known at compile time, and different array objects can have different sizes.给定数组的大小在创建后不会改变,但它的初始大小在编译时不一定知道,不同的数组对象可以有不同的大小。

A pointer to the first element of an array lets you use either pointer arithmetic or the indexing operator [] to traverse the elements of the array.指向数组第一个元素的指针允许您使用指针算术或索引运算符[]来遍历数组的元素。 But the pointer doesn't tell you how many elements the array has;但是指针不会告诉您数组有多少个元素; you generally have to keep track of that yourself.您通常必须自己跟踪。

If a function needs to create an array and return a pointer to its first element, you have to manage the storage for that array yourself, in one of several ways.如果一个函数需要创建一个数组并返回一个指向它的第一个元素的指针,您必须自己管理该数组的存储,方法有多种。 You can have the caller pass in a pointer to (the first element of) an array object, probably along with another argument specifying its size -- which means the caller has to know how big the array needs to be.您可以让调用者传入一个指向数组对象(的第一个元素)的指针,可能还有另一个指定其大小的参数——这意味着调用者必须知道数组需要有多大。 Or the function can return a pointer to (the first element of) a static array defined inside the function -- which means the size of the array is fixed, and the same array will be clobbered by a second call to the function.或者函数可以返回一个指向函数内部定义的静态数组(的第一个元素)的指针——这意味着数组的大小是固定的,并且同一数组将被第二次调用函数破坏。 Or the function can allocate the array on the heap -- which makes the caller responsible for deallocating it later.或者函数可以在堆上分配数组——这使得调用者负责稍后释放它。

Everything I've written so far is common to C and C++, and in fact it's much more in the style of C than C++.到目前为止,我编写的所有内容对于 C 和 C++ 都是通用的,事实上,它比 C++ 更具有 C 风格。 Section 6 of the comp.lang.c FAQ discusses the behavior of arrays and pointers in C. comp.lang.c FAQ 的第 6 节讨论了 C 中数组和指针的行为。

But if you're writing in C++, you're probably better off using C++ idioms.但是,如果您使用 C++ 编写代码,则最好使用 C++ 习语。 For example, the C++ standard library provides a number of headers defining container classes such as <vector> and <array> , which will take care of most of this stuff for you.例如,C++ 标准库提供了许多定义容器类的头文件,例如<vector><array> ,它们将为您处理大部分这些事情。 Unless you have a particular reason to use raw arrays and pointers, you're probably better off just using C++ containers instead.除非您有使用原始数组和指针的特殊原因,否则最好只使用 C++ 容器。

EDIT : I think you edited your question as I was typing this answer.编辑:我想你在我输入这个答案时编辑了你的问题。 The new code at the end of your question is, as you observer, no good;作为您的观察者,您问题末尾的新代码不好; it returns a pointer to an object that ceases to exist as soon as the function returns.它返回一个指向一个对象的指针,该对象在函数返回后立即停止存在。 I think I've covered the alternatives.我想我已经涵盖了替代方案。

you can (sort of) return an array你可以(有点)返回一个数组

instead of代替

int m1[5] = {1, 2, 3, 4, 5};
int m2[5] = {6, 7, 8, 9, 10};
int* m3 = test(m1, m2);

write

struct mystruct
{
  int arr[5];
};


int m1[5] = {1, 2, 3, 4, 5};
int m2[5] = {6, 7, 8, 9, 10};
mystruct m3 = test(m1,m2);

where test looks like测试看起来像

struct mystruct test(int m1[5], int m2[5])
{
  struct mystruct s;
  for (int i = 0; i < 5; ++i ) s.arr[i]=m1[i]+m2[i];
  return s;
}

not very efficient since one is copying it delivers a copy of the array效率不高,因为正在复制它会提供数组的副本

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

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