詳解C語言函數(shù)返回值解析
詳解C語言函數(shù)返回值解析
程序一:
int main() { int *p; int i; int*fun(void); p=fun(); for(i=0;i<3;i++) { printf("%d\n",*p); p++; } return 0; }; int* fun(void) { static int str[]={1,2,3,4,5}; int*q=str; return q; } //不能正確返回
雖然str是在動態(tài)變量區(qū),而該動態(tài)變量是局部的,函數(shù)結(jié)束時不保留的。
程序二:
int main() { char *p; char*fun(void); p=fun(); printf("%s\n",p); return 0; }; char * fun(void) { char *str="hello"; return str; } //可以正確返回
但是,字符串"hello"不是變量,而是一個常量,編譯程序在處理這種常量時,通常把它放在了常量區(qū)中。而常量區(qū)則是始終存在的。
后一個例子中函數(shù)fun的返回值就是一個指向這種常量區(qū)的指針。
函數(shù)返回指針,要使主程序可以使用這個指針來訪問有意義的數(shù)據(jù),關鍵就是要保證在使用這個指針值的時候,該指針所指向的地方的數(shù)據(jù)仍然有意義。
還有,如果指針是指向函數(shù)的指針,那么這個指針就是指向程序代碼區(qū)的。這也是一種應用的情況。
另外,如果明白了它的原理,程序員還可以發(fā)明出一些其他靈活的使用方法,當然,那都屬于“怪”方法,一般不提倡的。
程序三:
int main() { int a,b; int max; int fun (int a,int b); scanf("%d%d",&a,&b); max=fun (a,b); printf("\n%d\n",max); return 0; }; //http://www.bianceng.cn int fun(int a,int b) { int max; if(a>b) max=a; else max=b; return max; } //可以正確返回
程序三:
這個例子中,返回的不是變量max的地址,返回的是它的值。
return后面的東西,看做一個表達式,返回的是這個表達式的值。
例如,入口如果a是3,b是5,則此時(執(zhí)行return語句時)max里面存的是5。而return語句的功能就是把max里面的5取出來,放到“返回值寄存器”中。
主程序是從“返回值寄存器”得到這個5的(此時max變量已經(jīng)不存在了)。
你前面的第二個例子中,同樣,指針變量str在函數(shù)結(jié)束后已經(jīng)不存在了。但是在return語句中,把指針變量str里面的值(等于字符串"hello"存放處的地址)送到“返回值寄存器”中了。
動態(tài)變量str不存在了,但常量區(qū)中的字符串"hello"還存在。主程序根據(jù)返回的地址就可以找到該字符串。
程序四:
int main() { char *p; char *fun(void); p=fun(); printf("%x\n",p); printf("%s\n",p); return 0; } char* fun(void) { // char str[]={'a','b','c','d','e','f','\0'}; char str[]="hello"; printf("%x\n",str); return str; } //不能正確返回
char str[]="hello"; 是在動態(tài)變量區(qū)中開辟了可以容納6個字符的數(shù)組,數(shù)組名叫str。同時將字符串"hello"(原存放于常數(shù)空間)拷貝到這個數(shù)組空間中去作為數(shù)組的初始化值。
此時若執(zhí)行return str; 其中的str是數(shù)組名。C語言規(guī)定,表達式中如果是數(shù)組名,則該表達式的值就等于這個數(shù)組的地址。所以返回的是這個數(shù)組的地址,請注意:并不是字符串常量"hello"的地址!而函數(shù)結(jié)束時,雖然常數(shù)空間并不破壞,但這個數(shù)組空間是破壞了的,而你返回的卻不是常數(shù)空間里的地址而正是已經(jīng)破壞了的數(shù)組的地址。
而char *str="hello"; 是在動態(tài)變量區(qū)中開辟了一個可以存放一個指針值的變量,名叫str。同時將原存放于常數(shù)空間的字符串"hello"的地址賦給這個指針變量作為初始值。
此時若執(zhí)行return str; 其中的str是指針變量名。C語言規(guī)定,表達式中如果是變量名,則該表達式的值就等于這個變量的值(指針變量的值就是地址)。所以返回的是變量str的值,而變量str的值就等于字符串常量"hello"的地址。而函數(shù)結(jié)束時,變量str破壞了的,但常數(shù)空間中的字符串并不破壞。主程序根據(jù)返回的地址就可以找到該字符串。
【總結(jié)】
常規(guī)程序中,函數(shù)返回的指針通常應該是:
(1)指向靜態(tài)(static)變量;
(2)指向?qū)iT申請分配的(如用malloc)空間;
(3)指向常量區(qū)(如指向字符串"hello");
(4)指向全局變量;
(5)指向程序代碼區(qū)(如指向函數(shù)的指針)。
除這5項以外,其它怪技巧不提倡。
函數(shù)內(nèi)的變量,沒有關鍵字static修飾的變量的生命周期只在本函數(shù)內(nèi),函數(shù)結(jié)束后變量自動銷毀。當返回為指針的時候需要特別注意,因為函數(shù)結(jié)束后指針所指向的地址依然存在,但是該地址可以被其他程序修改,里面的內(nèi)容就不確定了,有可能后面的操作會繼續(xù)用到這塊地址,有可能不會用到,所以會出現(xiàn)時對時錯的情況,如果需要返回一個指針而又不出錯的話只能調(diào)用內(nèi)存申請函數(shù)
返回結(jié)構(gòu)體:
#include <stdio.h> typedef struct { int a; int b; int c; }str; str change(str s) { s.a += 1; s.b += 1; s.c += 1; return s; } int main(void) { str s1, s2; s1.a = 1; s1.b = 1; s1.c = 1; s2 = change(s1); printf("s1.a = %d\ts1.b = %d\ts1.c = %d\n",s1.a, s1.b, s1.c); printf("s2.a = %d\ts2.b = %d\ts2.c = %d\n",s2.a, s2.b, s2.c); return 0; } //可以返回
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關文章
C語言實現(xiàn)求解素數(shù)的N種方法總結(jié)
哈嘍各位友友們,今天又學到了很多有趣的知識,現(xiàn)在迫不及待的想和大家分享一下!本文將手把手帶領大家探討利用試除法、篩選法求解素數(shù)的n層境界!都是精華內(nèi)容,可不要錯過喲2023-01-01C++關于構(gòu)造函數(shù)可向父類或者本類傳參的講解
今天小編就為大家分享一篇關于C++關于構(gòu)造函數(shù)可向父類或者本類傳參的講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12如何判斷一個數(shù)是否為2的冪次方?若是,并判斷出來是多少次方?
本篇文章是對如何判斷一個數(shù)是否為2的冪次方?若是,并判斷出來是多少次方的實現(xiàn)方法,進行了詳細的分析介紹,需要的朋友參考下2013-05-05Vscode配置C/C++環(huán)境使用minGW(保姆級配置過程)
本文主要介紹了Vscode配置C/C++環(huán)境使用minGW(保姆級配置過程),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02