1樓:匿名使用者
如果一個函式以一維陣列為引數,我們可以這樣宣告這個函式
void func(int* a) ;void func(int a) ;void func(int a[3]) ;
實際上,這三種形式是等價的,在使用陣列做引數時,編譯器會自動將陣列名轉換為指向陣列第一個元素的指標,為什麼呢?這要從引數的傳遞方式說起,引數有三種傳遞方式,按值傳遞,按指標傳遞,按引用傳遞,分別如下
void test(int a) ;void test(int* a) ;void test(int& a) ;
第一種方式傳遞的是a的一個副本
第二種方式傳遞的是指向a的指標的一個副本
第三種方式傳遞的是指向a的引用的一個副本
既然都是副本,那麼就存在拷貝到過程,但是,陣列是不能直接拷貝的,也就是不能像下面這樣
int a[3] = ;int b(a) ; // errorint b[3] ;b = a ; // error
不能用一個陣列初始化另一個陣列,也不能將一個陣列直接賦值給另外一個陣列,如果想複製陣列,唯一的辦法就是逐個元素複製。int a[3] = ;int b[3] ;for (int i = 0; i < 3; ++i)
既然陣列不能拷貝,那麼引數該如何傳遞呢?於是編譯器就將陣列名轉換成了指向第一個元素的指標,指標是可以拷貝的。但是這也引發了另外一個問題。
我們無法只通過陣列名得知陣列元素的個數。看下面的**
void test(int a[3])}
明明只傳遞了三個元素的陣列,為什麼輸出5個元素?前面已經說了,陣列被轉換成了指向第一個元素的指標,所以上面的**和下面的相同
void test(int* a) //我只知道a是個指標,跟本不知道a指向多少個元素}
編譯器根本不知奧陣列a有多少個元素,它甚至不知道a是陣列!如何解決呢,一種辦法是再加一個引數,指定元素個數
void test(int* a, int n)}
另外一種辦法是傳遞陣列的引用,這才是本文的重點,唉,前面這麼多廢話:(
void test(int (&a)[3])}
這樣寫陣列a就不會被轉換為指標了,而且有了元素個數的資訊,呼叫的時候,也必須傳遞一個含有3個元素的陣列
int a[3] = ;test(a) ; // okint b[1] = ;test(b) ; // error, can not convert parameter a from int[1] to int(&)[3]
1、對於一維陣列來說,陣列作為函式引數傳遞,實際上傳遞了一個指向陣列的指標,在c編譯器中,當陣列名作為函式引數時,在函式體內陣列名自動退化為指標。此時呼叫函式時,相當於傳址,而不是傳值,會改變陣列元素的值。
例如:void fun(int a); 若在fun函式中有a[i]++;等語句,那麼對應的陣列元素會被修改,呼叫時直接用fun(a);即可。
2、對於高維陣列來說,可以用二維陣列名作為實參或者形參,在被呼叫函式中對形引數組定義時可以指定所有維數的大小,也可以省略第一維的大**明,如:
void fun(int array[3][10]);
void fun(int array[10]);
二者都是合法而且等價,但是不能把第二維或者更高維的大小省略,如下面的定義是不合法的:
void fun(int array);
因為從實參傳遞來的是陣列的起始地址,在記憶體中按陣列排列規則存放(按行存放),而並不區分行和列,如果在形參中不說明列數,則系統無法決定應為多少行多少列,不能只指定一維而不指定第二維,下面寫法是錯誤的:
void fun(int array[3]);
實引數組維數可以大於形引數組,例如形引數組定義為:
void fun(int array[3][10]);
而實引數組定義為:
int array[5][10];
這時形引數組只取實引數組的一部分,其餘部分不起作用。
可以看到,將二維陣列當作引數的時候,必須指明所有維數大小或者省略第一維的,但是不能省略第二維或者更高維的大小,這是由編譯器原理限制的。學編譯原理的時候應該 知道編譯器是這樣處理陣列的:
對於陣列 int p[m][n];
如果要取p[i][j]的值(i>=0 && i p + i*n + j; 從以上可以看出,如果我們省略了第二維或者更高維的大小,編譯器將不知道如何正確的定址,即這裡的n值是在形參定義的時候就要明確知道的。但是我們在編寫程式的時候卻需要用到各個維數都不固定的二維陣列 作為引數,這就難辦了,編譯器不能識別阿,怎麼辦呢?不要著急,編譯器雖然不能識別,但是我們完全可以不把它當作一個二維陣列,而是把它當作一個普通的指標,再另外加上兩個引數指明各個維數,然後我們為二維陣列手工定址,這樣就達到了將二維陣列作為函式的引數傳遞的目的,根據這個思想,我們可以把維數固定 的引數變為維數隨即的引數,例如: void fun(int array[3][10]); void fun(int array[10]); 變為:void fun(int **array, int m, int n); 在轉變後的函式中,array[i][j]這樣的式子是不對的(不信,大家可以試一下),因為編譯器不能正確的為它定址,所以我們需要模仿編譯器的行為把array[i][j]這樣的式子手工轉變為: *(*array + n*i + j); 在呼叫這樣的函式的時候,需要注意一下,如下面的例子: int a[3][3] = , , }; fun(a, 3, 3); 根據不同編譯器不同的設定,可能出現warning 或者error,可以進行強制轉換如下呼叫: fun((int**)a, 3, 3); c語言中,陣列名作為函式呼叫的實參時,下面敘述正確的是()。 2樓:匿名使用者 正確的b 例如:f(int data); f(int *data); 其實是等價的,都是一個指標傳遞。上面兩種無論那種都可以傳遞一個陣列名,作為實參。 實參傳遞給的陣列名,就是陣列的首地址。 因此通過陣列名,傳遞其實就是把陣列的首地址給了形參,因此通過地址就可以改變實引數組相應的值。 在c語言中,用陣列名作為函式呼叫時的實參,實際上傳遞給形參的是____________。 3樓:足壇風行者 首地址。 因為陣列名傳遞的是陣列的地址也就是第一個元素的地址。例如: a[3]這個陣列,3指個數,a[0]指第一個元素,全部元素指a[0]~a[2];那陣列名a規定的就是首地址。 擴充套件資料 c語言中函式引數傳遞的三種方式: 1、傳值,就是把你的變數的值傳遞給函式的形式引數,實際就是用變數的值來新生成一個形式引數,因而在函式裡對形參的改變不會影響到函式外的變數的值。 2、傳地址,就是傳變數的地址賦給函式裡形式引數的指標,使指標指向真實的變數的地址,因為對指標所指地址的內容的改變能反映到函式外,也就是能改變函式外的變數的值。 3、傳引用,實際是通過指標來實現的,能達到使用的效果如傳址,可是使用方式如傳值。說幾點建議:如果傳值的話,會生成新的物件,花費時間和空間,而在退出函式的時候,又會銷燬該物件,花費時間和空間。 4樓:匿名使用者 實引數組的首地復址。 在用數制組名作函式引數時,不是進行值的傳送,即不是把實引數組的每一個元素的值都賦予形引數組的各個元素。因為實際上形引數組並不存在,編譯系統不為形引數組分配記憶體,陣列名就是陣列的首地址,函式得到一個函式值,即為該字元陣列的首地址。 因此在陣列名作函式引數時所進行的傳送只是地址的傳送,也就是說把實引數組的首地址賦予形引數組名。形引數組名取得該首地址之後,也就等於有了實在的陣列。實際上是形引數組和實引數組為同一陣列,共同擁有一段記憶體空間。 5樓:匿名使用者 陣列名傳遞的是陣列的地址也就是第一個元素的地址 所以選 d 6樓:天雨下凡 選擇d.實引數組的首地址 7樓:匿名使用者 d首地址 ~~~~~~~~ 8樓:yeara洛 d.實引數組的首地址 函式宣告指函式原型宣告,只有函式名,函式型別,引數個數和型別,無函式體。一般放在主函式前。逗號結尾。函式定義,除上述外,去掉結尾逗號,加函式體。可放在main函式後面,也可放在main函式前面。放在main函式前面則不要寫函式原型宣告。 雲澹楓卿 函式宣告格式如 int max int 函式呼叫是你... 毋惜苼 在c語言中,實參將值傳給函式中的形參,實現了自上而下的值傳遞,就可以呼叫函式了。舉個淺顯一點的例子吧 include void main int swap int x,int y 在主函式中,將實參a,b的值傳遞給被呼叫函式中的形參x,y,即將a,b分別代入x,y中計算,即達到了呼叫的目的。... 瓜瓜魚 c語言 函式前加void是表示函式的返回值為空,void表示空。返回值為空表示此函式可以沒有return語句,或者使用return 語句。返回值概念 乙個函式的函式名既是該函式的代表,也是乙個變數。由於函式名變數通常用來把函式的處理結果資料帶回給呼叫函式,即遞迴呼叫,所以一般把函式名變數稱為...請問C語言中函式定義,函式宣告和函式呼叫的區別
在呼叫函式時,函式是怎樣傳值的,c語言函式呼叫時,實參和形參是如何傳遞的?什麼時候要寫指標型變數?求高手指點
函式呼叫前加(void)作用,C語言 函式前加void是什麼意思