1. 程式人生 > >C++中陣列作為函式引數或返回值

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採用按值傳遞方式,如果想要改變其值,需要採用引用方式傳值

參考資料