C - Call By Value?Call By Address(reference)?

別激動,我知道有人看到我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值是多少呢?

 

如有錯誤請留言告知。

一個被自己雷到的工程師,

如今大徹大悟