你知道C語言函數(shù)調(diào)用常用的2種方式嗎
本篇博客會講解C語言函數(shù)調(diào)用的2種方式,分別是:傳值調(diào)用和傳址調(diào)用。這2種函數(shù)調(diào)用方式有什么區(qū)別呢?為什么會有不同的效果呢?分別有哪些用途呢?下面我會一一展開。
區(qū)別
傳值調(diào)用,即通過傳遞變量的值來調(diào)用函數(shù)。
傳址調(diào)用,即通過傳遞變量的地址來調(diào)用函數(shù)。
比如,假設(shè)有2個變量a和b,對于變量a和b來說,test(a, b)就是傳值調(diào)用,test(&a, &b)就是傳址調(diào)用。
原理
這時你可能很好奇:這2種調(diào)用方式的原理是什么呢?其實非常簡單。
先舉個傳值調(diào)用的例子:
// 函數(shù)定義
int Add(int x, int y)
{
return x + y;
}
// 調(diào)用
int a = 3, b = 5;
int sum = Add(a, b);在上面的代碼中,我們分別把a和b的值傳遞給了Add函數(shù)中的x和y。此時,我們稱:a和b是“實際參數(shù)”,簡稱實參;x和y是“形式參數(shù)”,簡稱形參。傳值調(diào)用的方式,會把實參的值傳遞給形參,也就是說,把a中的3傳遞給x,此時x就是3,把b中的5傳遞給y,此時y就是5。在Add函數(shù)內(nèi)部,把x+y的值帶回來,也就返回3+5的值,即返回8,再把返回值賦值給sum,sum就是8。
再舉個傳址調(diào)用的例子:
// 函數(shù)定義
int Add(int* p1, int* p2)
{
return *p1 + *p2;
}
// 調(diào)用
int a = 3, b = 5;
int sum = Add(&a, &b);以上就是典型的傳址調(diào)用,但是很顯然在這個場景下,我們只想“求和”,使用傳址調(diào)用有點多此一舉,但是還是分析一下原理:我們把a和b的地址傳給了p1和p2,此時p1存儲了a的地址,p2存儲了b的地址,p1就指向了a,p2就指向了b。我們想在Add函數(shù)內(nèi)部求和,就要先對p1解引用,拿到a的值,再對p2解引用,拿到b的值,再把拿到的a和b的值加起來返回,此時sum就被賦值為函數(shù)的返回值,即8。
以上只是非常粗略的帶大家了解了傳值調(diào)用和傳址調(diào)用的區(qū)別。下面用一個經(jīng)典的例子進行更加深入的講解。這個例子就是:寫一個函數(shù),交換2個整數(shù)的值。
使用傳值調(diào)用的方式,寫出來的函數(shù)如下:
// 定義
void Swap(int x, int y)
{
int tmp = x;
x = y;
y = tmp;
}
// 調(diào)用
int a = 3, b = 5;
Swap(a, b);
下面我通過調(diào)試的方式,來帶大家看一下這個程序會如何執(zhí)行。

代碼即將執(zhí)行Swap(a, b);,此時a的值是3,b的值是5。接下來執(zhí)行這條語句:

代碼來到第17行,此時a和b的值并沒有交換?到底發(fā)生了啥?
重新開始調(diào)試,這次我進入到Swap函數(shù)內(nèi)部看一眼。

按照前面的分析,此時x和y拿到了a和b的值,接下來進行交換:

代碼執(zhí)行到第10行,此時可以發(fā)現(xiàn),x和y其實已經(jīng)交換了,但是a和b并沒有變化?這又是為什么呢?
此時再回到main函數(shù),發(fā)現(xiàn)a和b的值并沒有被交換。

發(fā)現(xiàn)這個問題后,我們可以干一件事,使用下面的代碼,把a、b、x、y的地址打印出來:
#include <stdio.h>
void Swap(int x, int y)
{
printf("&x = %p, &y = %p\n", &x, &y);
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 3, b = 5;
printf("&a = %p, &b = %p\n", &a, &b);
Swap(a, b);
return 0;
}輸出結(jié)果如下:

可以發(fā)現(xiàn),當(dāng)把a的值傳遞給x,把b的值傳遞給y時,x和y,a和b已經(jīng)是不同的空間了,此時相當(dāng)于,內(nèi)存中有4個變量,分別是a、b、x、y,由于值傳遞,x的值和a相同,y的值和b相同,此時交換了x和y,對a和b的值并沒有影響!所以函數(shù)調(diào)用結(jié)束后,a和b的值并沒有交換。
這時,我們就可以總結(jié):當(dāng)我們使用傳值調(diào)用,實參的值傳遞給形參后,形參只是實參的一份臨時拷貝,改變形參的值并不影響實參的值!
那Swap函數(shù)的正確實現(xiàn)形式是怎樣的呢?相信聰明的你已經(jīng)想到了,使用傳址調(diào)用就行了嘛!
// 定義
void Swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
// 調(diào)用
int a = 3, b = 5;
Swap(&a, &b);為什么以上的代碼就能實現(xiàn)“交換”的效果呢?這就是傳址調(diào)用的神奇之處!
分析一下:把a的地址傳遞給p1,把b的地址傳遞給p2,此時p1就指向了a,p2就指向了b,這時再對p1和p2解引用,就能把a和b的值給修改了!
我們還是通過調(diào)試來觀察一下細節(jié):

進入到函數(shù)內(nèi)部:

再回到main函數(shù):

成功交換了a和b的值!
用途
根據(jù)以上的講解,可以總結(jié)一下傳值調(diào)用和傳址調(diào)用的用途:
- 傳值調(diào)用適用于不需要修改函數(shù)外部變量的場景。
- 傳址調(diào)用適用于需要修改函數(shù)外部變量的場景。
這是因為,傳值調(diào)用時,形參是實參的一份臨時拷貝,改變形參并不影響實參,所以在函數(shù)內(nèi)部沒有能力改變外面的變量的值;傳址調(diào)用就不一樣了,形參保存了函數(shù)外部變量的地址,就可以通過解引用的方式,修改函數(shù)外部變量的值了。
總結(jié)
1.傳值調(diào)用適用于不需要修改函數(shù)外部變量的場景,因為函數(shù)內(nèi)部變量和外部變量并沒有建立聯(lián)系,是獨立的空間。
2.傳址調(diào)用適用于需要修改函數(shù)外部變量的場景,因為函數(shù)內(nèi)部存儲了指向函數(shù)外部變量的指針,建立了聯(lián)系,可以通過解引用的方式改變函數(shù)外部的變量。
以上就是你知道C語言函數(shù)調(diào)用常用的2種方式嗎的詳細內(nèi)容,更多關(guān)于C語言函數(shù)調(diào)用的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于C++讀入數(shù)字按位取出與進制轉(zhuǎn)換問題(典型問題)
這篇文章主要介紹了關(guān)于C++讀入數(shù)字按位取出與進制轉(zhuǎn)換問題,是一個非常典型的問題,本文通過實例舉例給大家介紹的非常詳細,需要的朋友可以參考下2020-02-02
關(guān)于C++虛函數(shù)與靜態(tài)、動態(tài)綁定的問題
這篇文章主要介紹了C++虛函數(shù)與靜態(tài)、動態(tài)綁定,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-10-10

