別激動,我知道有人看到我address刮號了(reference)就很激動
address是address,reference是reference!
這就是我這篇要說的
在大學時被算是誤導的工程師
正文開始
在這一篇曾發生了一件有趣的是
我使用char * MyWord帶到so檔時,用了兩種方式改變他的值
1.strcpy
2."string\x00"
但只有第一種成功的改變了值,我也做了一份表格
現在回頭看一定被C/C++的工程師笑到抬不起頭(淚奔~
這邊就要甩鍋給大學我的導師了
相信大部分大一資工的學生第一個接觸的都是C語言(吧?
好了,這時候一定會有人跟你說傳"值"傳"址"
這時候我們直覺的轉譯過了就是 Call By Value, Call By Address
好啦,誤導就這麼開始惹(好啦,就是我,我承認我被誤導了)
從此我就深信,我們把值或址帶入了function,也成功的完成我們需求
但事實卻非如此,這時候要開始解釋了
Call By Value, Call By Address, Call By Reference倒底有什麼不同
我們以
int a = 3;
int *p = &a;
為例
3是value
&a是address
*p是reference
等等等等等!*p不就是&a,那也是address阿???
首先,我們宣告了a,於是產生了一個記憶體區塊,假設叫 0x000055934cffe670 (x64下分配為8byte,x86(32)下分配為4byte)
這時候0x000055934cffe670保存了一個叫3的值,合理!
再來是*p了,一樣進行了宣告,於是產生了一個區塊,假設叫 0x00005566945d5206。
而裡面的值就是0x000055934cffe670,也就是,你讓*p reference到 &a
好了,我們來個程式碼玩玩吧
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void CallString (const char *);
void CallStrcpy (char *);
void CallInt (int *);
#define PAUSE printf("Press Enter key to continue..."); fgetc(stdin);
int main (void)
{
const char *Input = "ILoveHelloWorld!!";
printf ("Input before:%s\n", Input);
CallString (Input);
printf ("Input after :%s\n\n", Input);
char InputAry [] = "IAlsoLoveHelloWorld\x00";
printf ("Input before:%s\n", InputAry);
CallStrcpy (InputAry);
printf ("Input after :%s\n\n", InputAry);
int *MyInt = (int*)malloc(sizeof(int*));
*MyInt = 3;
printf ("Input before:%d\n", *MyInt);
CallInt (MyInt);
printf ("Input after :%d\n\n", *MyInt);
printf ("%p", MyInt);
return 0;
}
void CallString (const char *MyString)
{
MyString = "ChangeHelloWorld";
}
void CallStrcpy (char *MyString)
{
int InputLength = strlen(MyString) + 1;
const char *Str = "strcpyString";
int StrLength = strlen(Str) + 1;
if (StrLength > InputLength)
{
printf ("Output String too long\n");
return;
}
strcpy (MyString, Str);
}
void CallInt (int *MyInt)
{
*MyInt = 4;
}
結果:
如果前面的結果你看的懂的話,這裡你應該就了解為什麼第一個結果並沒有改變了
如果不了解的話,就表示,你把function當成Call By Address事實上它是Call By Reference
這兩個有差嗎?,在你的說明中都是0x000055934cffe670這address阿
雖然都是address但意義差很多阿
我們從第三個說起吧,
void CallInt (int MyInt)
{
MyInt = 4;
}
void CallInt (int *MyInt)
{
*MyInt = 4;
}
我們知道上面是傳值,所以不會改變原來的值
但下面傳的是址,所以更改後就會改變原來的值
但如果我說上面和下面都是傳值呢?你信嗎?
什麼!!你的意思是說大學老師就在騙我?
不是der,是你在自以為的把傳址翻成address,造成了盲點(好啦,是我自以為)
也是我一直以來不懂的點,現在八門全開惹
我一直以為下面是把Address傳給function…嗯…對啦,它是把Address傳給function啦
等等我在鬼打牆了!!
先解釋上面那個吧,假設我傳了value 3到上面的function,
所以funtion的MyInt產生了一個記憶體區塊0x0...(略)保存值剛送過來的3
然後在這0x0...(略)的區塊內,不斷的計算value,所以當結束後,你main的值不會被改變,因為0x000055934cffe670的值至始至終都沒被變過
好那下面的程式碼又是什麼意思,
我把0x000055934cffe670這個址傳給function,
然後function的*MyInt產生了一個記憶體區塊0x1...(略)保存剛送來的址(我們也可以稱它為值)
所以當你在進行計算時,是使用0x1...(略)存的值 0x000055934cffe670這址 的值 3,
所以自始自終沒有所謂的 Call By Address,那只能稱為reference。
我們來做個實驗吧,把上面的程式碼改一下。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void CallString (const char *);
void CallStrcpy (char *);
void CallInt (int *);
#define PAUSE printf("Press Enter key to continue..."); fgetc(stdin);
int main (void)
{
const char *Input = "ILoveHelloWorld!!";
printf ("Input Address:%p\n", &Input);
printf ("*Input Address:%p\n", Input);
printf ("Input before:%s\n", Input);
CallString (Input);
printf ("Input Address:%p\n", &Input);
printf ("*Input Address:%p\n", Input);
printf ("Input after :%s\n\n", Input);
char InputAry [] = "IAlsoLoveHelloWorld\x00";
printf ("InputAry Address:%p\n", &InputAry);
printf ("*InputAry Address:%p\n", InputAry);
printf ("InputAry before:%s\n", InputAry);
CallStrcpy (InputAry);
printf ("InputAry after :%s\n\n", InputAry);
int *MyInt = (int*)malloc(sizeof(int*));
*MyInt = 3;
printf ("MyInt Address:%p\n", &MyInt);
printf ("*MyInt Address:%p\n", MyInt);
printf ("Input before:%d\n", *MyInt);
CallInt (MyInt);
printf ("MyInt Address:%p\n", &MyInt);
printf ("*MyInt Address:%p\n", MyInt);
printf ("Input after :%d\n\n", *MyInt);
return 0;
}
void CallString (const char *MyString)
{
printf ("MyString Address:%p\n", &MyString);
printf ("*MyString Address:%p\n", MyString);
MyString = "ChangeHelloWorld";
printf ("*MyString Address:%p\n", MyString);
}
void CallStrcpy (char *MyString)
{
int InputLength = strlen(MyString) + 1;
const char *Str = "strcpyString";
int StrLength = strlen(Str) + 1;
if (StrLength > InputLength)
{
printf ("Output String too long\n");
return;
}
printf ("MyString Address:%p\n", &MyString);
printf ("*MyString Address:%p\n", MyString);
strcpy (MyString, Str);
printf ("*MyString Address:%p\n", MyString);
}
void CallInt (int *MyInt1)
{
printf ("MyInt1 Address:%p\n", &MyInt1);
printf ("*MyInt1 Address:%p\n", MyInt1);
*MyInt1 = 4;
printf ("*MyInt1 Address:%p\n", MyInt1);
}
結果:
看到了嗎?至始自終就是傳值(不過這值存的是址)
從第一個function可以看到function和main接這input址的poiter各自擁有一個address
所以你在function把MyString保存的值(址)改成另一個address時,只是把function保存的值(址)改掉而已,並沒有改掉main裡面的值(址)
所以回到main依然是把裡面的值(址)保存的值帶回來,
而第二個function則是把address裡的值(址)所保存的值直接改掉,
所以回到main時,去取該string時自然就被改變了
第三個也可以看到改的都是值(址)裡面的值。
好了,
int main (void)
{
int *MyInt = (int*)malloc(sizeof(int*));
*MyInt = 3;
printf ("Input before:%d\n", *MyInt);
CallInt (MyInt);
printf ("Input after :%d\n\n", *MyInt);
return 0;
}
void CallInt (int *MyInt1)
{
int NewInt = 4
MyInt1 = &NewInt;
}
請問,main的after值是多少呢?
如有錯誤請留言告知。
一個被自己雷到的工程師,
如今大徹大悟