在函数中返回数组

我有一个数组int arr[5],它被传递给一个函数fillarr(int arr[]):

int fillarr(int arr[])
{
for(...);
return arr;
}
  1. 我如何返回那个数组?
  2. 我将如何使用它,比如我返回了一个指针我将如何访问它?
1013500 次浏览
int *fillarr(int arr[])

你仍然可以使用结果like

int *returned_array = fillarr(some_other_array);
if(returned_array[0] == 3)
do_important_cool_stuff();

在这种情况下,数组变量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;
}

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,所以你可以应用面向对象的语义,同时保留数组原始的简单性。

这样的:

int fillarr(int arr[])

实际上与:

int fillarr(int *arr)

如果你真的想返回一个数组你可以把这行改为

int * fillarr(int arr[]){
// do something to arr
return arr;
}
它并不是真正返回一个数组。方法的开头返回一个指针 数组地址。< / p > 但是记住,当你传入数组时,你只是传入一个指针。 当你修改数组数据时,你实际上是在修改数据 指针指向。因此,在传入数组之前,必须意识到 你在外部已经有了修改后的结果

如。

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函数中放入一个长度 这个。< / p >
int * fillarr(int arr[], int length)

这样你就可以使用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函数 < p >类似: Memset ((int*)&arr, 5, sizeof(int));

当我谈到这个话题的时候。你说你在用c++。看一下如何使用stl向量。您的代码可能会更加健壮。

有很多教程。这里有一个可以告诉你如何使用它们。 http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html < / p >

答案可能取决于您计划如何使用该函数。对于最简单的答案,让我们确定您真正需要的不是数组,而是一个向量。向量很好,因为它看起来很无聊,普通的值可以存储在常规指针中。之后我们将看看其他选择以及为什么你需要它们:

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与使用普通vector的工作原理相同。本例还通过添加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现在“指向”修改后的arr的开头。

这样做的真正好处是,它在vector和普通C数组以及许多其他类型的集合上工作得同样好

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

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

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

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

struct Marks{
int list[5];
}

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

typedef struct Marks marks;
marks marks_list;

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

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

在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;
}
最简单的方法是通过引用返回,即使你不写 '&'符号,由

引用自动返回
     void fillarr(int arr[5])
{
for(...);


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

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

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

  1. 如果你想从一个函数返回一个一维数组,你必须声明一个函数返回一个指针,如下面的例子所示:
int * myFunction()    {
.
.
.
}
  1. c++不提倡将局部变量的地址返回给函数外部,因此必须将局部变量定义为静态变量。

将这些规则应用于当前问题,我们可以编写如下程序:

# 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

只需要定义一个类型[]作为返回值,就像:

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


string[] x = {one, two};




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


return x;
}
< p >。 . . 函数调用:< / p >
string[] y;
y = functionReturnValueArray(stringOne, stringTwo)

这是一个相当老的问题,但我将提出我的2分,因为有很多答案,但没有一个以清晰和简洁的方式显示所有可能的方法(不确定是否简洁,因为这有点失控。TL;😉博士)。

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

然而,像这样使用数组就是让它衰减为指针,并让编译器将其处理为数组就像。如果你传递一个数组,比如函数期望它有5个元素,但你的调用者实际上传递了一些其他的数字,这可能会导致微妙的错误。

有几种方法可以更好地处理这个问题。传入std::vectorstd::array(不确定在2010年问这个问题时std::array是否存在)。然后,您可以将对象作为引用传递,而无需复制/移动对象。

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

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

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

只是,这看起来很丑,而且超级难读。我现在用一些在2010年还没有的东西来帮助它,我也用它来做函数指针:

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

这将把类型移动到预期的位置,使更具可读性。当然,如果你只打算使用5个元素,使用模板是多余的,所以你当然可以硬编码:

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

正如我所说,我的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()还不存在,尽管可以很容易地实现。这将允许以一种更安全的方式遍历数组,因为它们在C数组上有意义,而不是指针。

至于访问数组,您可以将它传递给另一个具有相同参数类型的函数,或者为它创建一个别名(这没有多大意义,因为在该作用域中已经有了原始的数组)。访问数组引用就像访问原始数组一样。

void other_function(type_t<int(&)[5]> x) { /* do something else */ }


void fn()
{
int array[5];
other_function(fillarr(array));
}

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
}

总而言之,如果要对数组进行迭代,最好不要允许数组衰减为指针。这是一个坏主意,因为它使编译器无法保护你,避免搬起石头砸自己的脚,并使你的代码更难阅读。总是尝试帮助编译器帮助你尽可能长时间地保存类型,除非你有很好的理由不这样做。

编辑

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

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

您可以传递结束指针,而不是传递大小,它将指向数组的结束之后的位置。这很有用,因为它更接近于std算法,后者采用开始指针和结束指针,但现在返回的只是必须记住的东西。

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

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

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

注意,返回值已经失去了它的原始类型,并降级为指针。因此,现在您必须自己确保不会使数组溢出。

你可以传递一个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的工作方式非常相似(c++11),但它们在此上下文中不起作用。

还有:

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


return f;
}


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

实际上,当你在函数中传递一个数组时,指向原始数组的指针被传递到函数形参中,因此对该函数中数组所做的更改实际上是在原始数组上进行的。

#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';
}

运行它,您将看到更改

这里有一个完整的例子来解决这类问题

#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;
}

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

为了避免这种情况,我必须动态地创建数组并继续。大概是这样的。

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


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








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

#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]<<" ";


}

为什么不“return”;数组作为参数?

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[])
{
//...
}

一个简单而详细的例子,如果我忘记了概念,需要帮助,我可以参考这里。

#include <iostream>
using namespace std;
int *ReturnArray(int arr[], int size)
{
static int MinMax[2] = {0, 0}; // must use static, else address would be deleted after the return is reached
MinMax[0] = arr[0];
MinMax[1] = arr[size - 1];
return MinMax;
}
int main()


{
int arr[] = {1, 2, 3};
int size = sizeof(arr) / sizeof(*arr);
int *ans;                     // pointer to hold returned array
ans = ReturnArray(arr, size); // only pointer can receive the return, not an array
cout << "Min: " << ans[0] << " Max: " << ans[1];
return 0;
}