1. 程式人生 > >【C++】陣列作為引數傳遞的那些事兒

【C++】陣列作為引數傳遞的那些事兒

先看程式碼:

#include <cstdio>

void foo(int array[2])
{
    printf("int array[2]:\t\t%x %d\n", &array, sizeof(array));
}
void bar(int array[])
{
    printf("int array[]:\t\t%x %d\n", &array, sizeof(array));
}
void baz(int (&array)[2])
{
    printf("int (&array)[2]:\t%x %d\n", &array
, sizeof(array)); } int main() { int a[2] = {1, 2}; printf("main::a[2]:\t\t%x %d\n", a, sizeof(a)); foo(a); bar(a); baz(a); return 0; }

輸出:

main::a[2]:             28feb8 8
int array[2]:           28fea0 4
int array[]:            28fea0 4
int (&array)[2]:        28feb8 8

解說:

foo和bar的傳值方式是相同的,都是一個int*, 即一個整型指標,這可以從foo和bar裡打印出的array地址和main中的不同和sizeof(array)僅為sizeof(int*)看出,只不過是外型有點兒區別。

編譯器是不知道你要傳遞的是一個數組或是單一一個整型的地址的,這是因為C中陣列的記憶體模型是連續儲存(它並不知道傳遞的(首)地址之後的空間可否訪問)。

所以寫為foo或bar的樣式僅僅是對人的一種暗示,暗示傳遞的是一個數組,括號裡的2編譯器是不會把他當回事兒的①。

採用foo中的樣式,程式碼編寫者在函式中獲知傳遞的陣列的大小,但這種暗示功能很弱,而且易使人產生誤解。

比如以上的函式foo,傳遞大小為1個元素的陣列(即單一一個整型的地址):

int x[1];
foo(x);

或傳遞一個大小為100的陣列:

int x[100];
foo(x);

編譯器都不會有任何抱怨,所以在程式碼工程量很大的時候,你無法保證陣列傳值的安全性,另外一個問題是如果你寫的是商業性質的庫,你無法保證客戶(二次開發者)能安全地使用你的程式碼。

採用bar中樣式,實質和foo相同,空括號給人的暗示就是它能接受的引數是一個數組,而且是一個長度不確定的一維整型陣列,這相對於foo來說更為實際和真實一些(因為foo可能造成欺騙性的程式碼,原因見上)。

所以這種傳陣列的方式被多數人所採用,但一般還需多加一個引數來指定陣列的大小,如:

void bar(int array[], int size);

或效仿STL的做法,傳遞陣列的首地址和超尾指標(在遍歷陣列元素時很方便,且更快速、安全):

void bar(int* beg, int* end);

至於baz,它不同於foo和bar。前面已經說過,foo和bar實質是相同的,傳的都是一個int*,且傳值方式都是按值傳遞(C中只有按值傳遞)。

而baz卻是按引用傳遞,傳遞的是一個”編譯器認可的,大小為2”②的陣列的引用。

foo和bar都可以改寫為:

void theFact(int* array);

void theFact(int* array, int size);

按照此邏輯是不是baz可改寫為這樣呢?

void baz2(int* const& array); // a其實是一個int* const型指標,所以要加上const作為修飾

答案是否定的,注意上面的②,只有在C++中,函式”按引用”傳遞陣列並”指定其大小時”,[]中的數字才有意義(對編譯器而言)。所以baz2 != baz:

int x[100];

baz(x); // 編譯錯誤
baz2(x); // 可以通過

要理解這和foo, bar的不同首先要理解C++中對引用的定義: 引用就是物件本身,不存在沒有引用物件的引用。所以在baz中,形參array就是實參main中的a,一切a所有的特性都是array的特性,所以sizeof(array) == sizeof(a),而且&baz::array == main::a(地址相同)。

①: C99中允許使用static陣列引數修飾詞,如:

void foo(int x[static 10]); // x陣列至少含有10個連續元素

上句中的10此時並不是可有可無的,它是編譯器優化陣列訪問的一種暗示。

相關推薦

C++陣列作為引數傳遞那些事兒

先看程式碼: #include <cstdio> void foo(int array[2]) { printf("int array[2]:\t\t%x %d\n", &array, sizeof(array)); } vo

C++關於字串引數傳遞的小技巧

在對函式進行字串傳遞操作時,一次不要傳遞太多的字串。可以先傳遞一個字串,然後在函式中將該字串複製給其他字串。 如對於下面的函式: void turn_ps(string password,str

C++陣列

一維陣列 char arr[5] 型別 陣列名[陣列長度] 陣列可以初始化,也可以不初始化,也可以部分初始化。比如char arr[5] = {90,91};只初始化了前2個元素,char arr[3];沒有初始化,char arr[2] = {45,78};所有都初始化

關於將陣列作為引數傳遞給函式的簡單使用

簡單的方式可以將陣列作為一個全域性變數,然後就可以在函式中使用了. 另外的一種方式為: function1(int a[]) { cout<<a[0]<<end

C語言陣列引數傳遞

在學習C語言的過程中遇到陣列作為引數傳遞的問題 一維陣列:#include <stdio.h> int test2(int a[]){ for(int i=0;i<5;i++){ printf("%d",a[i]); } } int main()

C++陣列中連續子陣列的最大和

題意:Find the contiguous subarray within an array (containing at least one number) which has the largest sum. For example, given the

關於二維陣列作為引數傳遞給函式的問題

剛碰到要寫一個函式func,要傳入一個二維陣列給該函式,於是寫成func(int a[][]);但馬上又發現將二維陣列傳給函式時必須指定第二維的維數,因為函式傳遞的是一個指向一個一維陣列的指標,這個一維陣列中儲存有著若干元素的陣列,所以函式必須要知道這個指標所指向物件的資訊

JavaScript函式的引數傳遞和遞迴呼叫

引數傳遞 傳遞函式 這裡主要分享下,如果將一個函式作為引數進行傳遞 function box(sum,num3) //把函式本身作為引數傳遞,而不是函式的返回值 { return sum(num3); } functio

C# 陣列排序和取值練習

1.從鍵盤接收一行用逗號分隔的5個整數,儲存至有5個元素的陣列中。 2.分別輸出正序和逆序的結果。 3/輸出陣列最大值和平均值,平均值保留1位小數。 4.存在非法輸入時顯示提示訊息並可重新輸入資料。 5.按下回車鍵退出,任意鍵繼續輸入。 輸出結果如圖所示。 -------

C++將結構作為引數傳遞並返回

#include"iostream.h" #include"stdio.h" #include"string.h" struct Date { int day,month,year; }; Dat

C 作為函式引數的多維陣列

我們都知道一維陣列作為函式引數的情況,作為函式引數的一維陣列名——實際傳遞的是指向陣列第一個元素的指標。 多維陣列名作為函式引數的傳遞方式和一維陣列名相同——實際傳遞的也是指向第一個元素的指標。 但是,兩者之間不同的是,多維陣列的每個元素本身就是另外一個數組,(例如二位陣

C#呼叫C++ 平臺呼叫P/Invoke 結構體--輸入輸出引數、返回值、返出值、結構體陣列作為引數

【1】結構體作為輸入輸出引數 C++程式碼: typedef struct _testStru1 { int iVal; char cVal; __int64 llVal; }testS

qt訊號,使用自定義的結構作為引數傳遞

錯誤   解決辦法: 方法1:註冊改向量 1、註冊位置:在第一次使用此類連結跨執行緒的signal/slot之前,一般在當前類的建構函式中進行註冊; 2、註冊方法:在當前類的頂部包含:#include <QMetaType>,建構函式中加入程

c++ 二維動態陣列初始化及作為引數傳遞

學習c++動態二維陣列寫的程式碼,程式已經在VS2010上跑過了,是ok的包括動態二維陣列的建立,初始化,以及作為形參傳遞#include <iostream> #include<vector> using namespace std; typede

C++如何統計一個字串中某個字元出現的個數?將C-風格字串作為引數的函式

目錄 預備的基礎知識  將C-風格字串作為引數的函式 C-風格字串與常規char陣列之間的區別  統計某個字串中含有字元個數的程式   預備的基礎知識  C-風格字串由一系列字元組成,以空值字元結尾('\0') 將

C++函式如何傳遞二維陣列?二維陣列是怎麼通過指標進行傳遞

舉例子: int data[3][4] ={ {1,2,3,4} , {5,6,7,8} , {9,10,11,12} }; int total = sum(data,3); 請自己先嚐試寫出sum函式的原型 思考過後,請繼續看下面詳細分析:

C++如何使用函式進行陣列求和?傳遞陣列指標的簡單示例程式碼

cookies[Arsize] 如果是輸出輸出地址的長度,比如sizeof cookies,這時輸出的是整個陣列長度 假如傳遞給了指標arr, sizeof arr 就輸出的是指標的長度 可能理解比較抽象,我們採用實際程式碼舉例: 程式碼中有詳細註釋 //通用的統計陣列的和的

聯網處理之如何把json作為引數傳遞,要用RequestBody

先來看一個例子,通過json傳值來獲取登入資訊,下圖的postman的演示: 注意:用的Post方式,Body中用raw選項,傳的是json資料 聯網框架okhttp+retrofit+Rxjava

C#BackgroundWorker類傳遞引數

要傳遞多個不同型別的引數: private void Test(){ int a = 123; string b = "456"; bool c = true; Ba

C++筆記函式中引數傳遞

函式中引數是如何傳遞的呢? 在《C++Primer》一書中提到: “Each time we call a function, its parameters are created and initialized by the arguments passed in the