在函数中返回数组

时间:2010-08-13 02:17:40

标签: c++ arrays pointers function return

我有一个传递给函数int arr[5]的数组fillarr(int arr[])

int fillarr(int arr[])
{
    for(...);
    return arr;
}
  1. 如何返回该阵列?
  2. 我将如何使用它,说我返回一个指针我将如何访问它?

19 个答案:

答案 0 :(得分:168)

在这种情况下,您的数组变量arr实际上也可以通过隐式转换被视为指向内存中数组块开头的指针。您正在使用的语法:

int fillarr(int arr[])

只是一种语法糖。你真的可以用它替换它,它仍然可以工作:

int fillarr(int* arr)

所以从同样的意义上说,你想从函数返回的是一个指向数组中第一个元素的指针:

int* fillarr(int arr[])

你仍然可以像普通阵列一样使用它:

int main()
{
  int y[10];
  int *a = fillarr(y);
  cout << a[0] << endl;
}

答案 1 :(得分:98)

C ++函数不能按值返回C样式数组。最接近的是返回一个指针。此外,参数列表中的数组类型只是转换为指针。

int *fillarr( int arr[] ) { // arr "decays" to type int *
    return arr;
}

您可以通过使用参数和返回的数组引用来改进它,这可以防止衰减:

int ( &fillarr( int (&arr)[5] ) )[5] { // no decay; argument must be size 5
    return arr;
}

使用Boost或C ++ 11时,传递引用只是可选的,语法不那么令人费解:

array< int, 5 > &fillarr( array< int, 5 > &arr ) {
    return arr; // "array" being boost::array or std::array
}

array模板只生成一个包含C风格数组的struct,因此您可以应用面向对象的语义,同时保留数组的原始简洁性。

答案 2 :(得分:19)

$ 8.3.5 / 8州 -

“函数不应该有类型数组或函数的返回类型,尽管它们可能有类型指针的返回类型或对这些东西的引用。虽然可以有函数指针数组,但是不应该有函数数组。 。“

int (&fn1(int (&arr)[5]))[5]{     // declare fn1 as returning refernce to array
   return arr;
}

int *fn2(int arr[]){              // declare fn2 as returning pointer to array
   return arr;
}


int main(){
   int buf[5];
   fn1(buf);
   fn2(buf);
}

答案 3 :(得分:16)

在C ++ 11中,您可以返回std::array

#include <array>
using namespace std;

array<int, 5> fillarr(int arr[])
{
    array<int, 5> arr2;
    for(int i=0; i<5; ++i) {
        arr2[i]=arr[i]*2;
    }
    return arr2;
}

答案 4 :(得分:14)

答案可能取决于您计划如何使用该功能。对于最简单的答案,让我们决定而不是数组,你真正想要的是一个向量。向量很好,因为所有世界的外观都像无聊的普通值,你可以存储在常规指针中。我们会看看其他选项以及之后你想要它们的原因:

std::vector<int> fillarr( std::vector<int> arr ) {
    // do something
    return arr;
}

这将完全符合您的预期。好处是std::vector负责确保一切都得到妥善处理。缺点是,如果您的阵列很大,这会复制大量数据。实际上,它会复制数组的每个元素两次。首先它复制矢量,以便函数可以将它用作参数。然后它再次复制它以将其返回给调用者。如果您可以自己处理矢量,那么您可以更轻松地完成任务。 (如果调用者需要将其存储在某种变量中以进行更多计算,它可以第三次复制它)

看起来你真正想要做的就是填充一个集合。如果您没有特定的理由返回集合的新实例,那么请不要。我们可以这样做

void fillarr(std::vector<int> &  arr) {
    // modify arr
    // don't return anything
}

这样你就可以获得对传递给函数的数组的引用,而不是它的私有副本。您对参数所做的任何更改都会被调用者看到。如果你愿意,你可以返回对它的引用,但这不是一个好主意,因为它有点暗示你得到的东西与你传递的不同。

如果你真的需要一个新的集合实例,但是想要避免在堆栈中使用它(以及所需的所有复制),你需要为如何处理该实例创建某种契约。最简单的方法是使用智能指针,只要有人抓住它,就会保持引用的实例。如果它超出范围,它会干净利落地消失。这看起来像这样。

std::auto_ptr<std::vector<int> > fillarr( const std::vector<int> & arr) {
    std::auto_ptr<std::vector<int> > myArr(new std::vector<int>);
    // do stuff with arr and *myArr
    return myArr;
}

在大多数情况下,使用*myArr与使用普通香草矢量完全相同。此示例还通过添加const关键字来修改参数列表。现在你得到一个引用而不复制它,但你不能修改它,所以调用者知道它将与函数之前相同。

所有这些都是膨胀的,但惯用的c ++很少与整个集合一起使用。通常,您将在这些集合上使用迭代器。看起来更像是这样的

template <class Iterator>
Iterator fillarr(Iterator arrStart, Iterator arrEnd) {
    Iterator arrIter = arrStart;
    for(;arrIter <= arrEnd; arrIter++)
       ;// do something
    return arrStart;
}

如果你不习惯看到这种风格,使用它看起来有点奇怪。

vector<int> arr;
vector<int>::iterator foo = fillarr(arr.begin(), arr.end());

foo now'指向'修改后的arr的开头。

对此非常好的是,它在矢量上同样适用于普通C数组和许多其他类型的集合,例如

int arr[100];
int *foo = fillarr(arr, arr+100);

现在看起来非常像这个问题中其他地方给出的普通指针示例。

答案 5 :(得分:8)

此:

int fillarr(int arr[])

实际上与以下内容相同:

int fillarr(int *arr)

现在,如果你真的想要返回一个数组,你可以将该行改为

int * fillarr(int arr[]){
    // do something to arr
    return arr;
}

它并没有真正返回一个数组。你正在返回指向开头的指针 数组地址。

但请记住,当你传入数组时,你只会传入一个指针。 因此,当您修改数组数据时,您实际上正在修改数据 指针指向。因此,在传入数组之前,您必须意识到 你已经在外面修改了结果。

e.g。

int fillarr(int arr[]){
   array[0] = 10;
   array[1] = 5;
}

int main(int argc, char* argv[]){
   int arr[] = { 1,2,3,4,5 };

   // arr[0] == 1
   // arr[1] == 2 etc
   int result = fillarr(arr);
   // arr[0] == 10
   // arr[1] == 5    
   return 0;
}

我建议你可以考虑在你的fillarr函数中添加一个长度 此

int * fillarr(int arr[], int length)

这样你可以使用长度来填充数组的长度,无论它是什么。

要正确使用它。做这样的事情:

int * fillarr(int arr[], int length){
   for (int i = 0; i < length; ++i){
      // arr[i] = ? // do what you want to do here
   }
   return arr;
}

// then where you want to use it.
int arr[5];
int *arr2;

arr2 = fillarr(arr, 5);

// at this point, arr & arr2 are basically the same, just slightly
// different types.  You can cast arr to a (char*) and it'll be the same.

如果你想要做的就是将数组设置为某些默认值,请考虑使用 内置的memset功能。

像这样的东西:     memset((int *)&amp; arr,5,sizeof(int));

虽然我在谈论这个话题。你说你正在使用C ++。看看使用stl向量。您的代码可能更强大。

有很多教程。这是一个让您了解如何使用它们的方法。 http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html

答案 6 :(得分:5)

从函数返回一个数组,让我们在一个结构中定义该数组; 所以它看起来像这样

struct Marks{
   int list[5];
}

现在让我们创建类型结构的变量。

typedef struct Marks marks;
marks marks_list;

我们可以通过以下方式将数组传递给函数并为其赋值:

void setMarks(int marks_array[]){
   for(int i=0;i<sizeof(marks_array)/sizeof(int);i++)
       marks_list.list[i]=marks_array[i];
}

我们也可以返回数组。要返回数组,函数的返回类型应为结构类型,即标记。这是因为实际上我们正在传递包含数组的结构。所以最终的代码可能看起来像这样。

marks getMarks(){
 return marks_list;
}

答案 7 :(得分:4)

这是一个相当古老的问题,但是我会提出2美分,因为有很多答案,但没有一个以清晰简洁的方式显示所有可能的方法(不确定简洁的位,如同这有点失控.TL; DR)。

我假设OP想要返回传入的数组而不复制,因为某些方法直接将其传递给调用者以传递给另一个函数以使代码看起来更漂亮。

然而,使用这样的数组是让它衰变成指针并让编译器将其视为类似数组。如果你传入一个数组,这可能会导致细微的错误,函数期望它有5个元素,但你的调用者实际上传入了其他一些数字。

有几种方法可以更好地处理这个问题。传递std::vectorstd::array(不确定是否std::array在2010年提出问题时出现了std::array<int, 5>& fillarr(std::array<int, 5>& arr) { // (before c++11) for(auto it = arr.begin(); it != arr.end(); ++it) { /* do stuff */ } // Note the following are for c++11 and higher. They will work for all // the other examples below except for the stuff after the Edit. // (c++11 and up) for(auto it = std::begin(arr); it != std::end(arr); ++it) { /* do stuff */ } // range for loop (c++11 and up) for(auto& element : arr) { /* do stuff */ } return arr; } std::vector<int>& fillarr(std::vector<int>& arr) { for(auto it = arr.begin(); it != arr.end(); ++it) { /* do stuff */ } return arr; } 。然后,您可以将对象作为参考传递,而无需复制/移动对象。

template <size_t N>
int(&fillarr(int(&arr)[N]))[N]
{
    // N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])
    for(int* it = arr; it != arr + N; ++it)
    { /* do stuff */ }
    return arr;
}

但是,如果你坚持使用C数组,那么使用一个模板来保存数组中有多少项的信息。

template <typename T>
using type_t = T;

template <size_t N>
type_t<int(&)[N]> fillarr(type_t<int(&)[N]> arr)
{
    // N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])
    for(int* it = arr; it != arr + N; ++it)
    { /* do stuff */ }
    return arr;
}

除此之外,这看起来很难看,并且超级难以阅读。我现在用一些东西来帮助解决2010年不存在的问题,我也将其用于函数指针:

type_t<int(&)[5]> fillarr(type_t<int(&)[5]> arr)
{
    // Prefer using the compiler to figure out how many elements there are
    // as it reduces the number of locations where you have to change if needed.
    for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
    { /* do stuff */ }
    return arr;
}

这会移动人们期望的类型,使更具可读性。当然,如果你不打算使用除5个元素以外的任何东西,那么使用模板是多余的,所以你当然可以对它进行硬编码:

type_t<>

正如我所说,我的template<typename T> struct type { typedef T type; }; typename type<int(&)[5]>::type fillarr(typename type<int(&)[5]>::type arr) { // Prefer using the compiler to figure out how many elements there are // as it reduces the number of locations where you have to change if needed. for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it) { /* do stuff */ } return arr; } 伎俩在提出这个问题的时候不会有效。那时你所希望的最好的就是在结构中使用一个类型:

typename

这开始看起来很难看,但至少仍然更具可读性,尽管type<int(&)[5]>::type fillarr(type<int(&)[5]>::type arr) { // Prefer using the compiler to figure out how many elements there are // as it reduces the number of locations where you have to change if needed. for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it) { /* do stuff */ } return arr; } 可能是可选的,这取决于编译器,导致:

typedef int(&array5)[5];

array5 fillarr(array5 arr)
{
    // Prefer using the compiler to figure out how many elements there are
    // as it reduces the number of locations where you have to change if needed.
    for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
    { /* do stuff */ }
    return arr;
}

当然,你可以指定一个特定的类型,而不是使用我的助手。

std::begin()

当时,自由函数std::end()void other_function(type_t<int(&)[5]> x) { /* do something else */ } void fn() { int array[5]; other_function(fillarr(array)); } 不存在,但可以轻松实现。这将允许以更安全的方式迭代数组,因为它们在C数组上有意义,但不是指针。

至于访问数组,您可以将其传递给另一个采用相同参数类型的函数,或者为它创建一个别名(由于您已经拥有该范围内的原始函数,因此没有多大意义)。访问数组引用就像访问原始数组一样。

void fn()
{
    int array[5];
    auto& array2 = fillarr(array); // alias. But why bother.
    int forth_entry = array[4];
    int forth_entry2 = array2[4]; // same value as forth_entry
}

// separate size value
int* fillarr(int* arr, size_t size)
{
    for(int* it = arr; it != arr + size; ++it)
    { /* do stuff */ }
    return arr;
}

总而言之,如果您打算迭代它,最好不允许数组衰减为指针。这只是一个坏主意,因为它使编译器不会保护您免受脚部攻击并使您的代码更难阅读。总是尝试帮助编译器尽可能长时间地保持类型,除非你有充分的理由不这样做。

修改

哦,为了完整起见,你可以让它降级为指针,但这会使数组与它所拥有的元素数量分离。这在C / C ++中做了很多,通常通过传递数组中的元素数量来减轻。但是,如果您犯了错误并将错误的值传递给元素数量,编译器将无法帮助您。

// separate end pointer
int* fillarr(int* arr, int* end)
{
    for(int* it = arr; it != end; ++it)
    { /* do stuff */ }
    return arr;
}

您可以传递结束指针,而不是传递大小,指针将指向一个超过数组末尾的指针。这很有用,因为它使得某些东西更接近std算法,它采用了开始和结束指针,但是你返回的东西现在只是你必须记住的东西。

// I document that this function will ONLY take 5 elements and 
// return the same array of 5 elements.  If you pass in anything
// else, may nazal demons exit thine nose!
int* fillarr(int* arr)
{
    for(int* it = arr; it != arr + 5; ++it)
    { /* do stuff */ }
    return arr;
}

或者,您可以记录此函数只需要5个元素,并希望您的函数用户不会做任何愚蠢的事情。

std::pair<int*, int*>

请注意,返回值已丢失其原始类型,并降级为指针。因此,您现在可以自行确保不会超出阵列。

你可以传递一个std::pair<int*, int*> fillarr(std::pair<int*, int*> arr) { for(int* it = arr.first; it != arr.second; ++it) { /* do stuff */ } return arr; // if you change arr, then return the original arr value. } void fn() { int array[5]; auto array2 = fillarr(std::make_pair(&array[0], &array[5])); // Can be done, but you have the original array in scope, so why bother. int fourth_element = array2.first[4]; } ,你可以用它来开始和结束并传递它,但它真的不再像一个数组了。

void other_function(std::pair<int*, int*> array)
{
    // Can be done, but you have the original array in scope, so why bother.
    int fourth_element = array2.first[4];
}

void fn()
{
    int array[5];
    other_function(fillarr(std::make_pair(&array[0], &array[5])));
}

std::initializer_list

有趣的是,这与{{1}}的工作方式非常相似(c ++ 11),但它们在这种情况下不起作用。

答案 8 :(得分:3)

最简单的方法是,即使你不写,也要通过引用返回它 '&amp;'符号,它通过引用自动返回

     void fillarr(int arr[5])
  {
       for(...);

  }

答案 9 :(得分:2)

int *fillarr(int arr[])

您仍然可以使用

之类的结果
int *returned_array = fillarr(some_other_array);
if(returned_array[0] == 3)
    do_important_cool_stuff();

答案 10 :(得分:1)

如上所述,路径是正确的。但是我认为,如果我们仅返回函数的局部数组变量,则有时它会返回垃圾值作为其元素。

为了避免我不得不动态创建数组并继续。是这样的。

int* func()
{
  int* Arr = new int[100];
  return Arr;
}

int main()
{
  int* ArrResult = func();
  cout << ArrResult[0] << " " << ArrResult[1] << endl;
  return 0;
} 




答案 11 :(得分:0)

为什么不将数组作为参数“返回”?

fillarr(int source[], size_t dimSource, int dest[], size_t dimDest)
{

    if (dimSource <= dimDest)
    {
        for (size_t i = 0; i < dimSource; i++)
        {   
            //some stuff...
        }
    }
    else 
    {
        //some stuff..
    }
}

或..以一种更简单的方式(但您必须知道尺寸...):

fillarr(int source[], int dest[])
{
    //...
}

答案 12 :(得分:0)

以下是要解决的此类问题的完整示例

#include <bits/stdc++.h>
using namespace std;
int* solve(int brr[],int n)
{
sort(brr,brr+n);
return brr;
}

int main()
{
int n;
cin>>n;
int arr[n];
for(int i=0;i<n;i++)
{
    cin>>arr[i];
}
int *a=solve(arr,n);
for(int i=0;i<n;i++)
{
    cout<<a[i]<<endl;
}

return 0;
}

答案 13 :(得分:0)

实际上,当您在函数内部传递数组时,指向原始数组的指针将传递给function参数,因此实际上在原始数组上对该函数内部的数组所做的更改。

#include <iostream>

using namespace std;

int* func(int ar[])
{
    for(int i=0;i<100;i++) 
        ar[i]=i;
    int *ptr=ar;
    return ptr;
}


int main() {
    int *p;
    int y[100]={0};    
    p=func(y);

    for(int i=0;i<100;i++) 
        cout<<i<<" : "<<y[i]<<'\n';
}

运行它,您将看到更改

答案 14 :(得分:0)

那又如何:

int (*func())
{
    int *f = new int[10] {1,2,3};

    return f;
}

int fa[10] = { 0 };
auto func2() -> int (*) [10]
{
    return &fa;
}

答案 15 :(得分:0)

来源:https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm

C ++不允许将整个数组作为参数返回给函数。但是,您可以通过指定不带索引的数组名称来返回指向数组的指针。

  1. 如果要从函数返回单维数组,则必须声明一个返回指针的函数,如下例所示:
  2. int * myFunction()    {
       .
       .
       .
    }
    
    1. C ++不主张将局部变量的地址返回到函数外部,因此您必须将局部变量定义为静态变量。
    2. 在当前问题上应用这些规则,我们可以按如下方式编写程序:

      # include <iostream>
      
      using namespace std;
      
      int * fillarr( );
      
      
      int main ()
      {
      
         int *p;
      
         p = fillarr();
      
         for ( int i = 0; i < 5; i++ )
             cout << "p[" << i << "] : "<< *(p + i) << endl;
      
          return 0;
      }
      
      
      int * fillarr( )
      {
          static int  arr[5];
      
          for (int i = 0; i < 5; ++i)
              arr[i] = i;
      
          return arr;
       }
      

      输出将是:

      p[0]=0
      p[1]=1
      p[2]=2
      p[3]=3
      p[4]=4
      

答案 16 :(得分:0)

template<typename T, size_t N>
using ARR_REF = T (&)[N];

template <typename T, size_t N>
ARR_REF<T,N> ArraySizeHelper(ARR_REF<T,N> arr);

#define arraysize(arr) sizeof(ArraySizeHelper(arr))

答案 17 :(得分:-1)

我使用了静态数组,因此在返回数组时,它不应抛出错误,因为您正在返回局部变量的地址... 因此,现在您可以通过将其设置为静态变量来发送任何本地创建的变量,因为它可以用作全局变量....

#include<iostream>
using namespace std;

char *func(int n)
{
   // char a[26]; /*if we use this then an error will occur because you are 
                        //  returning address of a local variable*/
    static char a[26];
    char temp='A'; 
    for(int i=0;i<n;i++)
    {
     a[i]=temp;temp++;
    }
    return a;
}
int main()
{
    int n=26;
    char *p=func(n);
    for(int i=0;i<n;i++)
     cout<<*(p+i)<<" ";

   //or you can also print like this
  
    for(int i=0;i<n;i++)
     cout<<p[i]<<" ";    

}

答案 18 :(得分:-2)

只需将类型[]定义为返回值,例如:

        private string[] functionReturnValueArray(string one, string two)
    {

        string[] x = {one, two};


        x[0] = "a";
        x[1] = "b";

        return x;
    }

。 。 。 函数调用:

string[] y;
y = functionReturnValueArray(stringOne, stringTwo)