你知道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)用方式的原理是什么呢?其實(shí)非常簡單。
先舉個傳值調(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ǔ)和b的值傳遞給了Add函數(shù)中的x和y。此時,我們稱:a和b是“實(shí)際參數(shù)”,簡稱實(shí)參;x和y是“形式參數(shù)”,簡稱形參。傳值調(diào)用的方式,會把實(shí)參的值傳遞給形參,也就是說,把a(bǔ)中的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)用有點(diǎn)多此一舉,但是還是分析一下原理:我們把a(bǔ)和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)典的例子進(jìn)行更加深入的講解。這個例子就是:寫一個函數(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)試,這次我進(jìn)入到Swap函數(shù)內(nèi)部看一眼。
按照前面的分析,此時x和y拿到了a和b的值,接下來進(jìn)行交換:
代碼執(zhí)行到第10行,此時可以發(fā)現(xiàn),x和y其實(shí)已經(jīng)交換了,但是a和b并沒有變化?這又是為什么呢?
此時再回到main函數(shù),發(fā)現(xiàn)a和b的值并沒有被交換。
發(fā)現(xiàn)這個問題后,我們可以干一件事,使用下面的代碼,把a(bǔ)、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(bǔ)的值傳遞給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)用,實(shí)參的值傳遞給形參后,形參只是實(shí)參的一份臨時拷貝,改變形參的值并不影響實(shí)參的值!
那Swap函數(shù)的正確實(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);
為什么以上的代碼就能實(shí)現(xiàn)“交換”的效果呢?這就是傳址調(diào)用的神奇之處!
分析一下:把a(bǔ)的地址傳遞給p1,把b的地址傳遞給p2,此時p1就指向了a,p2就指向了b,這時再對p1和p2解引用,就能把a(bǔ)和b的值給修改了!
我們還是通過調(diào)試來觀察一下細(xì)節(jié):
進(jìn)入到函數(shù)內(nèi)部:
再回到main函數(shù):
成功交換了a和b的值!
用途
根據(jù)以上的講解,可以總結(jié)一下傳值調(diào)用和傳址調(diào)用的用途:
- 傳值調(diào)用適用于不需要修改函數(shù)外部變量的場景。
- 傳址調(diào)用適用于需要修改函數(shù)外部變量的場景。
這是因?yàn)?,傳值調(diào)用時,形參是實(shí)參的一份臨時拷貝,改變形參并不影響實(shí)參,所以在函數(shù)內(nèi)部沒有能力改變外面的變量的值;傳址調(diào)用就不一樣了,形參保存了函數(shù)外部變量的地址,就可以通過解引用的方式,修改函數(shù)外部變量的值了。
總結(jié)
1.傳值調(diào)用適用于不需要修改函數(shù)外部變量的場景,因?yàn)楹瘮?shù)內(nèi)部變量和外部變量并沒有建立聯(lián)系,是獨(dú)立的空間。
2.傳址調(diào)用適用于需要修改函數(shù)外部變量的場景,因?yàn)楹瘮?shù)內(nèi)部存儲了指向函數(shù)外部變量的指針,建立了聯(lián)系,可以通過解引用的方式改變函數(shù)外部的變量。
以上就是你知道C語言函數(shù)調(diào)用常用的2種方式嗎的詳細(xì)內(nèi)容,更多關(guān)于C語言函數(shù)調(diào)用的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于C++讀入數(shù)字按位取出與進(jìn)制轉(zhuǎn)換問題(典型問題)
這篇文章主要介紹了關(guān)于C++讀入數(shù)字按位取出與進(jìn)制轉(zhuǎn)換問題,是一個非常典型的問題,本文通過實(shí)例舉例給大家介紹的非常詳細(xì),需要的朋友可以參考下2020-02-02C++新特性詳細(xì)分析基于范圍的for循環(huán)
C++11這次的更新帶來了令很多C++程序員期待已久的for?range循環(huán),每次看到j(luò)avascript,?lua里的for?range,心想要是C++能有多好,心里別提多酸了。這次C++11不負(fù)眾望,再也不用羨慕別家人的for?range了。下面看下C++11的for循環(huán)的新用法2022-04-04關(guān)于C++虛函數(shù)與靜態(tài)、動態(tài)綁定的問題
這篇文章主要介紹了C++虛函數(shù)與靜態(tài)、動態(tài)綁定,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-10-10QT結(jié)合百度Ai實(shí)現(xiàn)車牌識別
當(dāng)下的人工智能勢頭很盛,本文主要介紹了QT結(jié)合百度Ai實(shí)現(xiàn)車牌識別,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03