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