顯示廣告
隱藏 ✕
看板 Programming
作者 Knuckles(阿德)
標題 [轉錄][C++] Call by Address (Call by Pointer)
時間 2010年03月08日 Mon. AM 12:56:53


※ 本文轉錄自 Knuckles_note 看板

看板 Knuckles_note
作者 Knuckles(阿德)
標題 [C++] Call by Address (Call by Pointer)
時間 2010年03月07日 Sun. AM 12:15:06


看完上一篇 Call by Value 後

我們知道了一般傳址呼叫的問題就是輸出值只能有一個
而我們希望在副程式中,可以修改主程式變數的值

方法就是: function 的輸入值由原本變數的值 改為 變數的記憶體位址

不過記憶體位址,其實也只是個整數值,所以這也是 Call by Value 的一種
只是 Value 是指 Pointer 的值,所以也有人稱這方法為 Call by Pointer

先介紹一下指標的用法


^L指標簡介

指標的定義很簡單,就是用來儲存記憶體位址的變數

跟一般變數沒兩樣,只是他是用來存位址而已

^L指標簡介

指標的定義很簡單,就是用來儲存記憶體位址的變數

當我們宣告一個普通的整數變數時
	
	
	
在記憶體中長這樣:
	
	
	
	
	
	
Address
	
    Name  Value
	
int a = 5;
	
	
	
	
0x00000100  a       5
	
	
	
	
	
	
 ↑
	
	
	
	
	
位址是系統自動給定的,不能自己設
	
	
	
	
	
0x開頭代表後面的數字使用16進位
	
	
	
	
	
若是32位元的電腦,位址最大值為 32 bits = 4 bytes
	
	
	
	
	
所以用16進位會有8位數 (2^32 = 16^8)
	
	
	
	
	
之後為了方便解說,省略前面的0 → 0x100

^L指標簡介

指標的定義很簡單,就是用來儲存記憶體位址的變數

當我們宣告一個普通的整數變數時
	
	
	
在記憶體中長這樣:
	
	
	
	
	
	
Address
	
    Name  Value
	
int a = 5;
	
	
	
	
0x100       a       5
	
	
	
	
	
	

如果我們想要把 a 的位址存起來
就要先宣告一個指標變數                          
	
	
	
	
	
	
   ↙因為前一個變數 int,大小為 4 bytes
	
int* p_a;
	
	
	
	
0x104       p_a
	

	
  ↑
	
雖然指標存的都是記憶體位址
	
但為了要記錄指向位址的大小,所以也有型態之分
	
這邊因為是用來指向一個 int 變數的指標,所以用 int*
	
代表p_a用來存一個int變數的位址
	
     

^L指標簡介

指標的定義很簡單,就是用來儲存記憶體位址的變數

當我們宣告一個普通的整數變數時
	
	
	
在記憶體中長這樣:
	
	
	
	
	
	
Address
	
    Name  Value
	
int a = 5;
	
	
	
	
0x100       a       5
	
	
	
	
	
	

如果我們想要把 a 的位址存起來
就要先宣告一個指標變數                          
	
	
	
	
	
	

	
int* p_a;
	
	
	
	
0x104       p_a

然後使用取址運算子 & 取得 a 的位址後存進 p_a

	
p_a = &a;
	
	
	
	
0x104       p_a   0x100

^L指標簡介

指標的定義很簡單,就是用來儲存記憶體位址的變數

當我們宣告一個普通的整數變數時
	
	
	
在記憶體中長這樣:
	
	
	
	
	
	
Address
	
    Name  Value
	
int a = 5;
	
	
	
	
0x100       a       5
	
	
	
	
	
	

如果我們想要把 a 的位址存起來
可以簡寫成這樣:            
	
	
	

	
	
	
	
	
	

	
int* p_a = &a;
	
	
	
	
0x104       p_a   0x100

^L指標簡介

指標的定義很簡單,就是用來儲存記憶體位址的變數

當我們宣告一個普通的整數變數時
	
	
	
在記憶體中長這樣:
	
	
	
	
	
	
Address
	
    Name  Value
	
int a = 5;
	
	
	
	
0x100       a       5
	
	
	
	
	
	

如果我們想要把 a 的位址存起來
可以簡寫成這樣:            
	
	
	

	
	
	
	
	
	

	
int* p_a = &a;
	
	
	
	
0x104       p_a   0x100

當我想要利用指標 p_a 存取 a 的值時,就利用取值運算子 *

	
int b = *p_a; // 讀取 a 的值
	
	
0x108       b       5
	
*p_a  = 10;   // 寫入 a 的值
	
	
0x100       a       10

^L指標簡介

指標的定義很簡單,就是用來儲存記憶體位址的變數

重新復習一下
	
	
	
	
	
Address  Name  Value

	
宣告一個整數變數
	
int a = 5;
	
0x100    a       5

	
宣告一個指標變數
	
int* p_a;
	
0x104    p_a  

	
取得一個普通變數的位址
	
p_a = &a;
	
0x104    p_a   0x100

	
利用指標讀取變數的值
	
int b = *p_a;
	
0x108    b       5
	

	
利用指標寫入變數的值
	
*p_a  = 10;  
	
0x100    a       10

^L指標簡介

指標的定義很簡單,就是用來儲存記憶體位址的變數

總之,就是記得三個東西

	
宣告指標用 int*   就是指向變數的型態再加個 *

	
對變數取址用 &
	
  取得變數的位址

	
對指標取值用 *    取得指向變數的值


接著來看我們要怎麼用指標來解決上一篇提到的 swap() 問題

^LCall by Address

#include <iostream>
	
	
	
這是 Call by Value 的寫法
using namespace std;

void swap(int,int);
	
	
	


int main()
	
	
	
	

{
	
int a=3,b=4;
	
	
	

	
swap(a,b);
	
cout << "a=" << a
	
     << ",b=" << b << endl;
	


	
return 0;
	
	
	

}

void swap(int a, int b)
{
	
int c = a;
	
a = b;
	
b = c;
}

^LCall by Address

#include <iostream>
	
	
	
1. 副程式的輸入值改為變數的位址
using namespace std;

void swap(int,int);
	
	
	


int main()
	
	
	
	

{
	
int a=3,b=4;
	
	
	

	
swap(&a,&b);
	
	
	
← 利用取址運算子 &,傳入 a,b 的位址
	
cout << "a=" << a
	
     << ",b=" << b << endl;
	


	
return 0;
	
	
	

}

void swap(int a, int b)
	
	

{
	
int c = a;
	
a = b;
	
b = c;
}

^LCall by Address

#include <iostream>
	
	
	
2. 副程式輸入變數的型態改為 指標
using namespace std;

void swap(int*,int*);
	
	
	
← swap() 將傳入兩個指標

int main()
	
	
	
	

{
	
int a=3,b=4;
	
	
	

	
swap(&a,&b);
	
	
	
← 利用取址運算子 &,傳入 a,b 的位址
	
cout << "a=" << a
	
     << ",b=" << b << endl;
	


	
return 0;
	
	
	

}

void swap(int* p_a, int* p_b)
	
	
← swap() 宣告兩個指標 p_a, p_b
{
	
int c = a;
	
a = b;
	
b = c;
}

^LCall by Address

#include <iostream>
	
	
	
3. 副程式中,利用指標來存取指向變數的值
using namespace std;

void swap(int*,int*);
	
	
	
← swap() 將傳入兩個指標

int main()
	
	
	
	

{
	
int a=3,b=4;
	
	
	

	
swap(&a,&b);
	
	
	
← 利用取址運算子 &,傳入 a,b 的位址
	
cout << "a=" << a
	
     << ",b=" << b << endl;
	


	
return 0;
	
	
	

}

void swap(int* p_a, int* p_b)
	
	
← swap() 宣告兩個指標 p_a, p_b
{
	
int c = *p_a;
	
*p_a = *p_b;
	
	
	
← 將指標加上取值運算子 * 來存取main()的變數值
	
*p_b = c;
}

^LCall by Address

#include <iostream>
	
	
	

using namespace std;
	
	
	
在程式還沒有執行時
	
	
	
	
	

void swap(int*,int*);
	
	
	
在記憶體中長這樣:

int main()
	
	
	
	
main() 的變數:
{
	
	
	
	
	
Address  Name  Value
	
int a=3,b=4;
	
	
	
0x100    a     3
	
swap(&a,&b);
	
	
	
0x104    b     4
	
cout << "a=" << a
	
     << ",b=" << b << endl;
	


	
return 0;
	
	
	

}

void swap(int* p_a, int* p_b)
	
	
swap() 的變數:
{
	
	
	
	
	
Address  Name  Value
	
int c = *p_a;
	
	
	
0x200    p_a
	
*p_a = *p_b;
	
	
	
0x204    p_b
	
*p_b = c;
	
	
	
0x208    c
}

^LCall by Address

#include <iostream>
	
	
	

using namespace std;
	
	
	
當程式呼叫了 swap() 時
	
	
	
	
	

void swap(int*,int*);
	
	
	


int main()
	
	
	
	
main() 的變數:
{
	
	
	
	
	
Address  Name  Value
	
int a=3,b=4;
	
	
	
0x100    a     3    ──┐傳出 0x100
	
swap(&a,&b); 
	
	
	
0x104    b     4    ──┼───┐傳出 0x104
	
cout << "a=" << a
	
	
 
	
	
	
	

	
     << ",b=" << b << endl;
	
 
	
	
	
	

	
	
	
	
	
 
	
	
	
	

	
return 0;
	
	
	
 
	
	
	
	

}
	
	
	
	
	
 
	
	
	
	

	
	
	
	
	
 
	
	
	
	

void swap(int* p_a, int* p_b)
	
	
swap() 的變數:
	
	
	

{
	
	
	
	
	
Address  Name  Value
	
	

	
int c = *p_a;
	
	
	
0x200    p_a   0x100  ←┘
	

	
*p_a = *p_b;
	
	
	
0x204    p_b   0x104  ←────┘
	
*p_b = c;
	
	
	
0x208    c
}

^LCall by Address

#include <iostream>
	
	
	

using namespace std;
	
	
	
當 swap() 執行完時
	
	
	
	
	

void swap(int*,int*);
	
	
	


int main()
	
	
	
	
main() 的變數:
{
	
	
	
	
	
Address  Name  Value
	
int a=3,b=4;
	
	
	
0x100    a     4   
	
swap(&a,&b); 
	
	
	
0x104    b     3   
	
cout << "a=" << a
	
	
 
	
	
	

	
     << ",b=" << b << endl;
	
 
	
	
	

	
	
	
	
	
 
	
	
	

	
return 0;
	
	
	
 
	
	
	

}
	
	
	
	
	
 
	
	
	

	
	
	
	
	
 
	
	
	

void swap(int* p_a, int* p_b)
	
	
swap() 的變數:
	
	
雖然 swap() 無法存取 main() 的 a,b
{
	
	
	
	
	
Address  Name  Value
	
但因為有取得 a,b 的位址
	
int c = *p_a;
	
	
	
0x200    p_a   0x100    所以可以利用取值運算子 *
	
*p_a = *p_b;
	
	
	
0x204    p_b   0x104    存取指向變數的值
	
*p_b = c;
	
	
	
0x208    c       3      所以 main() 中a,b的值就被 swap() 改掉了
}

^LCall by Address

#include <iostream>
	
	
	

using namespace std;
	
	
	

	
	
	
	
	

void swap(int*,int*);
	
	
	


int main()
	
	
	
	
main() 的變數:
{
	
	
	
	
	
Address  Name  Value
	
int a=3,b=4;
	
	
	
0x100    a     4    
	
swap(&a,&b);
	
	
	
0x104    b     3    
	
cout << "a=" << a 
	
	
 
	
	
	

	
     << ",b=" << b << endl;
	
執行結果顯示: a=4,b=3
	
	

	
	
	
	
	
成功的將 a,b 的值互換了
	
	
	

	
return 0;
	
	
	
 
	
	
	

}
	
	
	
	
	
 
	
	
	

	
	
	
	
	
 
	
	
	

void swap(int* p_a, int* p_b)
	
	
swap() 的變數:
	
	

{
	
	
	
	
	
Address  Name  Value
	

	
int c = *p_a;
	
	
	
0x200    p_a      
	
*p_a = *p_b;
	
	
	
0x204    p_b      
	
*p_b = c;
	
	
	
0x208    c          
}

^LCall by Address

#include <iostream>
	
	
	
懂是懂了,可是用指標當輸入變數好麻煩
using namespace std;
	
	
	
呼叫的時候要取址,使用的時候要取值
	
	
	
	
	
感覺很容易就會寫錯,有沒有更好的方法呢?
void swap(int*,int*);
	
	
	

	
	
	
	
	
當然是有囉,就是下篇要講的 Call by Reference
int main()
	
	
	
	

{
	
	
	
	
	

	
int a=3,b=4;
	
	
	

	
swap(&a,&b);
	
	
	

	
cout << "a=" << a
	
	
 
	
	
	

	
     << ",b=" << b << endl;
	
	

	
	
	
	
	
	
	

	
return 0;
	
	
	
 
	
	
	

}
	
	
	
	
	
 
	
	
	

	
	
	
	
	
 
	
	
	

void swap(int* p_a, int* p_b)
	
	
	

{
	
	
	
	
	

	
int c = *p_a;
	
	
	

	
*p_a = *p_b;
	
	
	

	
*p_b = c;
	
	
	

}


--
※ 來源: DISP BBS (http://disp.twbbs.org)
※ 作者: Knuckles  來自: 114.45.56.117  時間: 2010-03-07 00:15:06
※ 編輯: Knuckles  來自: 114.45.56.117  時間: 2010-03-07 03:02:18
※ 編輯: Knuckles  來自: 114.45.56.117  時間: 2010-03-07 03:08:45
※ 編輯: Knuckles  來自: 114.45.56.117  時間: 2010-03-07 03:09:29
※ 編輯: Knuckles  來自: 118.168.102.236  時間: 2010-03-07 15:36:53
※ 編輯: Knuckles  來自: 118.168.102.236  時間: 2010-03-07 16:24:56
--
※ 來源: DISP BBS (http://disp.twbbs.org)
※ 作者: Knuckles  來自: 118.168.102.236  時間: 2010-03-08 00:56:53
※ 看板: Programming 文章推薦值: 4 目前人氣: 0 累積人氣: 1887 
分享網址: 複製 已複製
( ̄︶ ̄)b iloveyouever, unshing, ken888686 說讚!
ott 轉錄至看板 ott 時間:2010-03-12 04:27:36
uefangsmith 轉錄至看板 uefacool 時間:2010-03-26 00:45:00
1樓 時間: 2010-04-01 00:26:45 (台灣)
  04-01 00:26 TW
call by pointer 本質上還是call by value
iloveyouever 轉錄至看板 my_time_my_heart 時間:2010-08-01 19:46:31
iloveyouever 轉錄至看板 my_time_my_heart 時間:2010-08-01 19:46:35
r)回覆 e)編輯 d)刪除 M)收藏 ^x)轉錄 同主題: =)首篇 [)上篇 ])下篇