前些日子,在QQ群裡面,發現一些朋友在討論函數返回後,為什麼值可以傳遞和地址傳遞的情況;我也感到很好奇,
於是就跟了一下。
int* sum(int x,int y){ int a; a=x|y; return &a;}
很顯然這段代碼,存在一些問題;但是在VC2008中編譯一切正常,運行狀態也一切正常。
下面是我的測試代碼:
#include <stdio.h>int* sum(int x,int y){ int a; a=x+y; return &a;}int getsum(int x,int y){ return x+y;}int main(void){ int *x; int a; x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); a=getsum(1,2); x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); *x=100; printf("*x=%d; x=%u\n",*x,x); getchar(); return 0;}
運行結果如下所示:
這個就是啟動並執行結果?但是為什麼呢? 而且兩次調用sum函數返回的地址完全一樣。
為了測試,我決定將代碼再進行異常改動。
#include <stdio.h>int* sum(int x,int y){ int a; a=x+y; return &a;}int getsum(int x,int y){ int* p; p=sum(10,2); printf("*x=%d; x=%u\n",*p,p); return *p; }int main(void){ int *x; int a; x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); a=getsum(1,2); x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); *x=100; printf("*x=%d; x=%u\n",*x,x); getchar(); return 0;}
代碼依然堅挺的活著,而且順利的運行,如下所示,只是在getsum裡面調用sum函數,得到的地址與main函數中得到的不一樣。
而且可以發現,無論怎麼調用,在main函數中調用sum,返回的地址一直是一樣的? 這是怎麼回事呢?
如果是這樣的話,那麼是否可以用這種方法動態分配地址呢? 是否可以我們free 一下看看。很不幸的是,失敗了?
提示:可能是heap——棧——異常中斷了程式。
為什麼會這樣呢?
原因可能是:
1、C程式在啟動並執行過程中,其地址空間是固定的;雖然是可重新導向的,但是在“他”自己的線性空間,其地址空間是固定的,
也就是所函數調用的壓棧的空間,其棧基址是固定的。
2、由於壓棧順序是一致的,而且每次壓棧時變數的offset是一定的。從左往右壓棧,或者從右往左壓棧都一樣會得到這個結果。
因此就出現了上面的情況。
那麼怎樣說明這個過程的不正常呢? 雖然他看起來能編譯、連結和運行,結果也很正常。
#include <stdio.h>int *x;int* sum(int x,int y){ int a; a=x+y; return &a;}void getsum(){ x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); //第二個輸出}int main(void){ int a; x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); //第一個輸出 getsum(); printf("*x=%d; x=%u\n",*x,x); //第三個輸出 *x=100; printf("*x=%d; x=%u\n",*x,x); //第四個輸出
getchar(); return 0;}
可以發現,第一個輸出,第二輸出的 *x的值一樣; 而第二個、第三個、第四個則是x的只一樣。這又是為什麼呢?
我們在改一下:
#include <stdio.h
int *x;int* sum(int x,int y){ int a; a=x+y; return &a;}
void getsum(){ x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); //第二個輸出}int main(void){ int a; x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); //第一個輸出 getsum(); printf("*x=%d; x=%u\n",*x,x); //第三個輸出 *x=100; printf("*x=%d; x=%u\n",*x,x); //第四個輸出 x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); //第五個輸出 getchar(); return 0;}
又或者這樣測試一下:
#include <stdio.h>int *x;int* sum(int x,int y){ int a; a=x+y; return &a;}int* sum1(int x,int y){ int a; a=x+y; return &a;}void getsum(){ x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); //第二個輸出}int main(void){ int a; x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); //第一個輸出 getsum(); printf("*x=%d; x=%u\n",*x,x); //第三個輸出 *x=100; printf("*x=%d; x=%u\n",*x,x); //第四個輸出 x=sum1(10,2); printf("*x=%d; x=%u\n",*x,x); //第五個輸出 getchar(); return 0;}
我們再改一下:
#include <stdio.h>int *x;int* sum(int x,int y){ int a; a=x+y; return &a;}int* sum1(int c,int d){ int a; a=c+d; *x=60; return x;}void getsum(){ x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); //第二個輸出}int main(void){ int a; x=sum(10,2); printf("*x=%d; x=%u\n",*x,x); //第一個輸出 getsum(); printf("*x=%d; x=%u\n",*x,x); //第三個輸出 *x=100; printf("*x=%d; x=%u\n",*x,x); //第四個輸出 x=sum1(10,2); printf("*x=%d; x=%u\n",*x,x); //第五個輸出 getchar(); return 0;}
輸出結果如下所示:
發現x的地址可以一直引用。
如果你要做一些壞事的話,這裡就是一個可以利用的地方。 可以通過這個全域的x變數,來修改傳遞給函數的參數值。
這個實驗就不做了。
有興趣的可以試一下。