亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

C語言中的參數傳遞機制詳解

2020-01-26 14:11:45
字體:
來源:轉載
供稿:網友

C中的參數傳遞

本文嘗試討論下C中實參與形參的關系,即參數傳遞的問題。

C語言的參數傳遞

值傳遞

首先看下列代碼:

#include <stdio.h> int main(){  int n = 1;  printf("實參n的值:%d,地址:%#x/n", n, &n);  void change(int i);//函數聲明  change(n);  printf("函數調用后實參n的值:%d,地址:%#x/n", n, &n);  return 0;} void change(int i){  printf("形參i的值:%d,地址:%#x/n",i,&i);  i++;  printf("自增操作后形參i的值:%d,地址:%#x/n",i,&i);} 

編譯后執行結果如下:

實參n的值:1,地址:0x5fcb0c形參i的值:1,地址:0x5fcae0自增操作后形參i的值:2,地址:0x5fcae0函數調用后實參n的值:1,地址:0x5fcb0c 

可以看到,在調用函數 change 時,會在內存中單獨開辟一個空間用于存放形式參數 i ,實參 n 的值會復制給形參 i 。對于形參的任何操作都不會影響到主調函數中的實參 n 。這種參數傳遞方式是便是典型的值傳遞。

上例中的參數類型是int型,實際上,對于整形(int、short、long、long long)、浮點型(float、double、long double)、字符型(char)等基本類型的參數都是值傳遞。

指針參數

在下面的例子中,函數的參數類型是一個指針:

#include <stdio.h> void change(int * i){  printf("形參i的值:%#x,地址:%#x/n",i,&i);  (*i)++;//通過指針修改其所指空間的值  i++;//讓指針指向下一塊內存空間  printf("自增操作后形參i的值:%#x,地址:%#x/n",i,&i);} int main(){  int n = 1;  int * p = &n;  printf("n的值:%d,地址:%#x/n", n, &n);  printf("實參p的值:%#x,地址:%#x/n", p, &p);  change(p);  printf("函數調用后實參p的值:%#x,地址:%#x/n", p, &p);  printf("函數調用后n的值:%d,地址:%#x/n", n, &n);  return 0;} 

編譯后執行結果如下:

n的值:1,地址:0x5fcb0c實參p的值:0x5fcb0c,地址:0x5fcb00形參i的值:0x5fcb0c,地址:0x5fcae0自增操作后形參i的值:0x5fcb10,地址:0x5fcae0函數調用后實參p的值:0x5fcb0c,地址:0x5fcb00函數調用后n的值:2,地址:0x5fcb0c 

指針是C語言中的一種特殊類型,它本身占用一定的內存空間,而存儲的值卻是某個內存地址。上例中,函數change的參數是指向int型變量的指針,實參p是指向變量n的一個指針,在調用函數change時,指針型的形參i也會得到一塊內存空間,其值由實參p復制而來,都是主調函數中變量n的地址。對于指針類型,一般不會太關注其本身而更多的是考慮它所指向的值,所以,在change函數內是通過指針來操作指針所指的內容(主調函數中的變量n)。這樣,便實現了在被調函數內操作主調函數中數據的效果。

雖然通過指針型參數傳遞可以達到讓被調函數內的操作作用于主調函數內數據的效果,但從實參和形參的角度來看,這種參數傳遞并沒有和一般的傳遞方法有什么本質的區別,也是值傳遞方式。

當參數傳遞方式是值傳遞時,形參和實參都存儲在各自的內存空間中,相互獨立互不影響,它們之間唯一的聯系便是在形參初始化時會使用實參的值。

數組參數

在C語言中,數組名可以看作一個指向數組首元素的指針常量,那么當數組作為參數是又是如何傳遞呢?實際上,當函數形參是數組類型時,作為形參的數組名便不再代表數組,而是被編譯器解析成一個指針。通過下面的例子可以看出,數組類型的形參只是在函數簽名中看上去是一個數組,但在函數體內,它已經徹底淪為一個指針。

#include <stdio.h> void arrArg(int arr[]){  printf("形參arr的值:%#x,地址:%#x/n", arr, &arr);  printf("sizeof(arr):%d, sizeof(int *):%d/n",sizeof(arr), sizeof(int *));  printf("sizeof(arr[0]):%d,sizeof(int):%d/n", sizeof(arr[0]), sizeof(int));  printf("*arr:%d,arr[0]:%d/n", *arr, arr[0]);  printf("*(arr+1):%d,arr[1]:%d/n", *(arr+1), arr[1]);  printf("arr+1:%#x,&arr[1]:%#x/n",arr+1, &arr[1]);  arr++;  printf("自增操作后形參arr的值:%#x,地址:%#x/n",arr, &arr);  printf("自增操作后,*arr:%d, arr[0]:%d/n",*arr, arr[0]);} int main(){  int a[] = {1,2,3};  printf("實參a的值:%#x,地址:%#x/n",a,&a);  printf("sizeof(a):%d,sizeof(a[0]):%d/n",sizeof(a),sizeof(a[0]));  arrArg(a);  return 0;} 

編譯后執行結果如下:

實參a的值:0x5fcb00,地址:0x5fcb00sizeof(a):12,sizeof(a[0]):4形參arr的值:0x5fcb00,地址:0x5fcae0sizeof(arr):8, sizeof(int *):8sizeof(arr[0]):4,sizeof(int):4*arr:1,arr[0]:1*(arr+1):2,arr[1]:2arr+1:0x5fcb04,&arr[1]:0x5fcb04自增操作后形參arr的值:0x5fcb04,地址:0x5fcae0自增操作后,*arr:2, arr[0]:2 

可以看出,雖然形參arr被聲明為int型數組,但在函數內部,arr已不再擁有數組的性質,而擁有了指向int型的指針的性質:

arr的大小是指針的大小(8),而非數組的大?。〝到M的大小是所有元素大小的總和,上例中:4×3=12)
arr可以被修改,而數組名不可以被修改
arr與a的內存地址不同但值相同(都是數組首元素地址),所以,在函數被調用時,真正被傳遞的值是數組首元素的地址,并以此地址初始化了一個指向實參數組首元素的指針作為形參。因為實際的形參是一個指針,所以這種情況也是屬于值傳遞。同時,與指針參數效果一樣,在函數內對“數組”的修改會直接作用于外部。

由此我們看到,數組作為參數與指針作為參數并沒有什么區別,因為編譯器會自動將形參中的數組名轉換為一個指針。所以,以下面代碼中的兩個函數簽名是等效的:

void func(int arr[]){ }void func(int * p){ } 

實際上,如果我們同時定義了它們,編譯器會報“redefinition”錯誤而無法編譯。

此外需要注意的是,雖然我們可以將形參聲明成一個數組,但在編譯器看來它只是一個指針而已,因此形參中有關數組長度的信息會被自動忽略,在實際調用時實參數組的長度與形參指定的數組長度沒有任何關系,而且在函數內也無法通過 sizeof(arr)/sizeof(arr[0]) 得到數組的長度。

//形參arr的指定長度5無意義,會被編譯器忽略,未防止誤解建議不寫void arrArg(int arr[5]){ // sizeof(arr)是指針類型的大小而非數組大小,因此len不是數組長度  int len = sizeof(arr)/ sizeof(arr[0]);} 

自定義類型參數

數組這種“組合”類型在作為參數傳遞時被解析為指針方式傳遞,那么當結構體(struct)、共同體(union)以及枚舉類型作為參數傳遞時是否也是如此呢?

枚舉類型本質上是int,所以當形參被聲明為枚舉類型時,在編譯器看來就是int型,以下面代碼中的兩個函數簽名是等效的,編譯器會報“redefinition”錯誤:

enum week{ Mon, Tues, Wed, Thurs, Fri, Sat, Sun }; void func(enum weekday){} void func(int i){} 

下面是結構體和共同體分別作為參數時的示例:

#include <stdio.h> struct Date{  int year;  int month;  int day;}; void changeStruct(struct Datedate){  printf("形參date的地址:%#x/n", &date);  date.year ++;  date.month = 12;  date.day = 31;  printf("形參date的值:%d-%d-%d/n",date.year,date.month,date.day);} union Data{  int i;  float f;  double d;}; void changeUnion(unionDatadata ){  printf("形參data的地址:%#x/n", &data);  printf("形參data的值,d.i:%d, d.f:%f, d.d:%f/n",data.i,data.f,data.d);  data.d = 2017.4;  printf("函數調用后,形參data的值,d.i:%d, d.f:%f, d.d:%f/n",data.i,data.f,data.d);} int main(){  printf("結構體參數傳遞示例:/n");  struct Datedate = {2017,4,2};  printf("實參date的地址:%#x/n", &date);  printf("實參date的值:%d-%d-%d/n",date.year,date.month,date.day);  changeStruct(date);  printf("函數調用后,實參date的值:%d-%d-%d/n",date.year,date.month,date.day);   printf("共用體參數傳遞示例:/n");  unionDatadata={.i=2017};  printf("實參data的地址:%#x/n", &data);  printf("實參data的值,d.i:%d, d.f:%f, d.d:%f/n",data.i,data.f,data.d);  changeUnion(data);  printf("函數調用后,實參data的值,d.i:%d, d.f:%f, d.d:%f/n",data.i,data.f,data.d);   return 0;} 

編譯后運行,輸出如下:

結構體參數傳遞示例:實參date的地址:0x5fcb00實參date的值:2017-4-2形參date的地址:0x5fcae0形參date的值:2018-12-31函數調用后,實參date的值:2017-4-2共用體參數傳遞示例:實參data的地址:0x5fcaf0實參data的值,d.i:2017, d.f:0.000000, d.d:0.000000形參data的地址:0x5fcab0形參data的值,d.i:2017, d.f:0.000000, d.d:0.000000函數調用后,形參data的值,d.i:-1717986918, d.f:-0.000000, d.d:2017.400000函數調用后,實參data的值,d.i:2017, d.f:0.000000, d.d:0.000000 

我們發現,C中的自定義類型作為參數傳遞時,和基本類型一樣,也是按值傳遞。

小結

C語言中,參數類型為字符型、整型、浮點型以及枚舉型、結構體(struct)和共同體(union)時,都是常規的值傳遞。而指針作為一種特殊的類型,其值為一個地址,所指向的基類型可以任意其他類型(包括void)甚至可以指向函數,所以,指針作為參數時雖然本質上屬于值傳遞,但因為傳遞的是一個地址,可以讓被調函數通過對指針所指內容的操作直接作用于外部數據,屬于參數傳遞中特殊的值傳遞方式。雖然可以把形參聲明為數組,但實際的形參卻是指針,因此,數組作為參數的傳遞方式也是特殊的值傳遞。

我們通過依次考察C語言中各種數據類型發現: C語言中只有值傳遞!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久噜噜噜久久中文字免| 亚洲国产精品成人av| 亚洲欧美国产精品久久久久久久| 97视频在线观看视频免费视频| zzijzzij亚洲日本成熟少妇| 亚洲欧美国产va在线影院| 色狠狠久久aa北条麻妃| 91视频88av| 日韩精品亚洲元码| 国产亚洲精品高潮| 中文字幕日韩综合av| 91久久久久久久久| 国语自产偷拍精品视频偷| 日韩一区二区三区在线播放| 日韩在线观看免费av| 久久国产精品偷| 欧美大奶子在线| 欧美日韩国产成人| 欧美日韩一区免费| 亚洲国产天堂久久综合网| 欧美日韩另类在线| 97香蕉久久夜色精品国产| 欧美视频在线观看 亚洲欧| 国产精品国语对白| 欧美亚洲日本网站| 国产一区二区三区直播精品电影| 欧美极品美女视频网站在线观看免费| 日韩欧美成人精品| 国产性猛交xxxx免费看久久| 超在线视频97| 久久五月天色综合| 欧美激情视频一区二区三区不卡| 午夜免费久久久久| 日韩视频欧美视频| 欧美壮男野外gaytube| 成人欧美一区二区三区在线湿哒哒| 日韩在线视频二区| 欧美成人精品一区| 久久男人av资源网站| 欧美久久精品午夜青青大伊人| 欧美午夜片欧美片在线观看| 亚洲欧美制服丝袜| 91青草视频久久| 国产91精品黑色丝袜高跟鞋| 91在线免费视频| 久久久国产视频91| 久久久999精品视频| 亚洲精品91美女久久久久久久| 国产精品丝袜高跟| 久久影院中文字幕| 久久久精品在线| 日本免费一区二区三区视频观看| 一本一道久久a久久精品逆3p| 91av福利视频| 亚洲精品欧美极品| 全亚洲最色的网站在线观看| 亚洲无亚洲人成网站77777| 国产精品专区h在线观看| 国产成人97精品免费看片| 亚洲一区二区久久| 亚洲综合色激情五月| 欧美黑人巨大xxx极品| 97激碰免费视频| 亚洲国产精久久久久久久| 91高潮精品免费porn| 在线观看精品自拍私拍| 最近2019年手机中文字幕| 日韩欧美亚洲综合| 国产精品aaa| 欧美一区深夜视频| 日韩在线视频观看正片免费网站| 欧美性生活大片免费观看网址| 国产精品专区h在线观看| 在线观看国产欧美| 日韩视频在线免费观看| 久久精品中文字幕一区| 97不卡在线视频| 亚洲精品国精品久久99热| 日韩av一卡二卡| 欧美日韩美女在线观看| 欧美美女操人视频| 亚洲第一偷拍网| 欧美日韩高清区| 久久精品国产免费观看| 国内精品久久久久久久久| 久久久欧美一区二区| 国内精品小视频在线观看| 亚洲一区二区三区久久| 青草青草久热精品视频在线观看| 欧美日韩国产一区中文午夜| 成人免费观看49www在线观看| 精品香蕉一区二区三区| 91免费人成网站在线观看18| 亚洲国产精久久久久久久| 日韩动漫免费观看电视剧高清| 国产精品久久久久久久久| 91在线观看免费高清完整版在线观看| 欧美日韩免费一区| 日韩在线播放视频| 日韩中文在线中文网在线观看| 亚洲18私人小影院| 国产精品高清网站| 色琪琪综合男人的天堂aⅴ视频| 亚洲欧洲自拍偷拍| 国产亚洲精品一区二555| 国产精品wwww| 疯狂做受xxxx高潮欧美日本| 91日本在线视频| 日韩av电影手机在线观看| 亚洲精品一区二区久| 久久夜精品香蕉| 亚洲精品视频中文字幕| 国产成人精品av在线| 国产精品96久久久久久| 91久久精品美女| 高清欧美性猛交xxxx黑人猛交| 性欧美长视频免费观看不卡| 这里只有精品在线观看| 欧美精品九九久久| 日韩欧美视频一区二区三区| 38少妇精品导航| 国产精品成人av在线| 欧美日韩福利电影| 北条麻妃一区二区在线观看| 中文字幕久久亚洲| 亚洲第一福利视频| 国产成人精品视频在线观看| 91av国产在线| 国产亚洲欧洲高清| 91丝袜美腿美女视频网站| 欧美成人午夜剧场免费观看| 日韩精品福利网站| 亚洲欧洲国产精品| 日韩精品亚洲元码| 国产精品国产三级国产aⅴ9色| 亚洲人成亚洲人成在线观看| 中文字幕av一区| 国产日韩精品视频| 成人免费观看网址| 日本精品视频在线观看| 亚洲人成网7777777国产| 一区二区日韩精品| 亚洲精品国产精品乱码不99按摩| 国产成+人+综合+亚洲欧洲| 国产精品69久久| 成人综合网网址| www欧美xxxx| 中文字幕久热精品视频在线| 亚洲图片在线综合| 日韩欧美亚洲范冰冰与中字| 久久精品视频va| 欧美电影《睫毛膏》| 欧美午夜无遮挡| 草民午夜欧美限制a级福利片| 久久久噜噜噜久久| 亚洲第一福利视频| 欧美成年人视频网站| 国产精品视频免费在线| 亚洲国产女人aaa毛片在线| 欧美色播在线播放| 色妞一区二区三区| 国内精品在线一区| 欧美孕妇毛茸茸xxxx| 成人免费观看a|