C++中数组作为函数参数或返回值

C++中数组作为函数参数或者返回值



概述


在编程任务中,经常会遇到将数组作为函数参数或者返回值,比如在前一篇的计数排序任务中,需要额外的空间来保存排序后的元素,并且将该数组返回给主函数。本文会介绍几种可行的方案,仅供参考。

数组作为函数参数


数组作为函数函数,在Java中,通过传递数据名即可获取到数组的信息,但是在C++中,这种操作行不通,如下:

#include <iostream>
using namespace std;
int sum(int arr[]){
    int length = sizeof(arr)/sizeof(arr[0]);
    int sum = 0;
    for (int i = 0 ; i < length; i++){
        sum += arr[i];
    }
    return sum;
}
int main(){
    int arr[] = {1,3,5,7,9};
    int summary = sum(arr);
    cout << summary << endl;
}

执行上述代码后发现,结果不正确,这是为什么?看下面代码:

#include <iostream>
using namespace std;
int sum(int* arr){
    int length = sizeof(arr)/sizeof(arr[0]);
    int sum = 0;
    for (int i = 0 ; i < length; i++){
        sum += arr[i];
    }
    return sum;
}
int main(){
    int arr[] = {1,3,5,7,9};
    int summary = sum(arr);
    cout << summary << endl;
}

对比这两个程序,我们发现,执行结果一直,说明两个问题,首先,数组名是数组的首地址,它被传递了,其次,sum函数内部,并未获取到正确的数组长度。因此,对于数组作为函数参数的情形,我们看采用下面代码:

#include <iostream>
using namespace std;
int sum(int* arr,int length){
    int sum = 0;
    for (int i = 0 ; i < length; i++){
        sum += arr[i];
    }
    return sum;
}
int main(){
    int arr[] = {1,3,5,7,9};
    int summary = sum(arr,5);
    cout << summary << endl;
}

C++11给出的替代方案,实际上该方案仍然使用模板参数传递了数组的长度,所以该参数必须要传入。并且编译器请选择:Having g++ following the coming C++0x ISO C++ language standard [-std=c++0x]

#include <iostream>
#include <array>
using namespace std;

template <size_t SIZE>
int sum(array<int,SIZE> arr){
    int sum = 0;
    int length = arr.size();
    for (int i = 0 ; i < length; i++){
        sum += arr[i];
    }
    return sum;
}

int main(){
    array<int,5> arr {{1,3,5,7,9}};
    int summary = sum(arr);
    cout << summary << endl;
}

数组作为函数返回值


数组作为函数返回值的情况更加复杂,传统的写法容易造成产生悬挂指针,造成空间浪费。看下面代码:

#include <iostream>
#include <array>
using namespace std;

template <size_t SIZE>
int* sum(array<int,SIZE> arr){
    int length = arr.size();
    int* returnArr = new int[length];
    for (int i = 0 ; i < length; i++){
        returnArr[i] = arr[i];
    }
    return returnArr;
}

int main(){
    array<int,5> arr {{1,3,5,7,9}};    // C++ 11 standard
    int* summary = sum(arr);
    for (int i = 0 ; i < arr.size(); i++){
        cout << summary[i] << " ";
    }
    delete[] summary;
    return 0;
}

可替代代码:

#include <iostream>
#include <array>
using namespace std;

template <size_t SIZE>
int* sum(array<int,SIZE> arr){
    int length = arr.size();
    static int returnArr[SIZE];
    for (int i = 0 ; i < length; i++){
        returnArr[i] = arr[i];
    }
    return returnArr;
}

int main(){
    array<int,5> arr {{1,3,5,7,9}};    // C++ 11 standard
    int* summary = sum(arr);
    for (unsigned int i = 0 ; i < arr.size(); i++){
        cout << summary[i] << " ";
    }
    return 0;
}

下面两段代码都是错误的,因为函数在返回后退出时,局部变量returnArr已经被删除,因此返回的结果是错误的,代码如下:

#include <iostream>
#include <array>
using namespace std;

template <size_t SIZE>
int* sum(array<int,SIZE> arr){
    int length = arr.size();
    int returnArr[SIZE];
    for (int i = 0 ; i < length; i++){
        returnArr[i] = arr[i];
    }
    return returnArr;
}

int main(){
    array<int,5> arr {{1,3,5,7,9}};    // C++ 11 standard
    int* summary = sum(arr);
    for (unsigned int i = 0 ; i < arr.size(); i++){
        cout << summary[i] << " ";
    }
    return 0;
}
#include <iostream>
using namespace std;
int* sum(int* arr,int length){
    int returnArr[length];
    for (int i = 0 ; i < length; i++){
        returnArr[i] = arr[i];
    }
    return returnArr;
}

int main(){
    int arr[] = {1,3,5,7,9};
    int length = sizeof(arr)/sizeof(arr[0]);
    int* summary = sum(arr,length);
    for (int i = 0 ; i < length; i++){
        cout << summary[i] << " ";
    }
}

下面代码在int returnArr[length]前增加了static,这保证了数组在返回后没有被删除,但是此时报错:|error: storage size of ‘returnArr’ isn’t constant|

#include <iostream>
using namespace std;
int* sum(int* arr,int length){
    static int returnArr[length];
    for (int i = 0 ; i < length; i++){
        returnArr[i] = arr[i];
    }
    return returnArr;
}

int main(){
    int arr[] = {1,3,5,7,9};
    int length = sizeof(arr)/sizeof(arr[0]);
    int* summary = sum(arr,length);
    for (int i = 0 ; i < length; i++){
        cout << summary[i] << " ";
    }
}

下面的代码能够解决上述问题:

#include <iostream>
using namespace std;
int* sum(int* arr,int length){
    int* returnArr = new int[length];
    for (int i = 0 ; i < length; i++){
        returnArr[i] = arr[i];
    }
    return returnArr;
}

int main(){
    int arr[] = {1,3,5,7,9};
    int length = sizeof(arr)/sizeof(arr[0]);
    int* summary = sum(arr,length);
    for (int i = 0 ; i < length; i++){
        cout << summary[i] << " ";
    }
    delete[] summary;
    return 0;
}

其它可行方案


在刘汝佳的《算法竞赛入门经典》教材中指出,当需要返回数组时,可以将将需要返回的数组提前作为参数传递进来,最后通过获取该数组的内容来获取其内容,这是可行的,但是该参数必要要使用引用的形式传递,否则会造成错误,代码如下:

#include <iostream>
#include <array>
using namespace std;

template <size_t SIZE>
void sum(array<int,SIZE> arr,array<int,SIZE>& returnArr){
    int length = arr.size();
    for (int i = 0 ; i < length; i++){
        returnArr[i] = arr[i];
    }
    return;
}

int main(){
    array<int,5> arr {{1,3,5,7,9}};    // C++ 11 standard
    array<int,5> returnArr;
    sum(arr,returnArr);
    for (unsigned int i = 0 ; i < returnArr.size(); i++){
        cout << returnArr[i] << " ";
    }
    return 0;
}

错误代码如下,returnArr在传递时没有以引用形式传递:

#include <iostream>
#include <array>
using namespace std;

template <size_t SIZE>
void sum(array<int,SIZE> arr,array<int,SIZE> returnArr){
    int length = arr.size();
    for (int i = 0 ; i < length; i++){
        returnArr[i] = arr[i];
    }
    return;
}

int main(){
    array<int,5> arr {{1,3,5,7,9}};    // C++ 11 standard
    array<int,5> returnArr;
    sum(arr,returnArr);
    for (unsigned int i = 0 ; i < returnArr.size(); i++){
        cout << returnArr[i] << " ";
    }
    return 0;
}

从上面的代码中,我们可以看到,std::array在出传递过程中,是以值方式传递,因此,想要在函数内部改变它,并且将结果返回给主调函数,必须用引用方式传值:

#include <iostream>
#include <array>
using namespace std;

template <size_t SIZE>
void sum(array<int,SIZE> arr){
    int length = arr.size();
    for (int i = 0 ; i < length; i++){
        arr[i] = 0;
    }
    return;
}

int main(){
    array<int,5> arr {{1,3,5,7,9}};    // C++ 11 standard
    sum(arr);
    for (unsigned int i = 0 ; i < arr.size(); i++){
        cout << arr[i] << " ";
    }
    return 0;
}
//输出结果为: 1 3 5 7 9

如果改成引用传值:

#include <iostream>
#include <array>
using namespace std;

template <size_t SIZE>
void sum(array<int,SIZE>& arr){
    int length = arr.size();
    for (int i = 0 ; i < length; i++){
        arr[i] = 0;
    }
    return;
}

int main(){
    array<int,5> arr {{1,3,5,7,9}};    // C++ 11 standard
    sum(arr);
    for (unsigned int i = 0 ; i < arr.size(); i++){
        cout << arr[i] << " ";
    }
    return 0;
}
//输出结果: 0 0 0 0 0

总结


数组作为函数参数或函数返回值,如何将数组的长度返回决定了函数执行正确与否,本文给出了合适的替换方案,并且给出了示例代码,需要指出,我们应该重视C++ 11中引入的array的使用。最后,如果数组常长度不确定,建议采用vector,这在C++ 11中被认为是可变长度的数组。

  • 在std::array中,由于使用了template参数,使得在编译时获取到数组的长度,因此加static关键字即可返回正确的数组内容
  • 在传统的语法中,只能在堆区分配空间才能解决数组作为参数返回问题,但是要注意释放指针空间,否则会造成悬挂指针。
  • 如果长度不确定,可以考虑vector作为替代
  • std::array采用按值传递方式,如果想要改变其值,需要采用引用方式传值

参考资料


  1. std::array http://en.cppreference.com/w/cpp/container/array
  2. 我的github: https://github.com/JunpengCode?tab=repositories

猜你喜欢

转载自blog.csdn.net/jpzhu16/article/details/79950684