http://home.netcom.com/~tjensen/ptr/cpoint.htm
這裡有很多資料可以看 !!
先看以下的例子 :
int i = 10 ;
int *j = &i ;
printf("(%p)(%p)\n",j,&i) ;
得到的答案是 : (0022FEC0)(0022FEC0)
* 跟 & 像是 反矩陣的關係一樣 , *(&i) 其實就是 i , * 是 dereference 的 操作 ,
int *j 的意思是 , j 是個指標變數 , 它的內容是一個放著 integer內容 的記憶體位址 ,
要去存取個記憶體內容 ,必須使用 * 這個方式 , 所以 , int *j = &i ; 代表 j 是一個指標 ,
它的內容是一個放著 integer 內容的記憶體位址, 而那個位址是變數 i 的位址 !!!!!!
從 printf 看的到 , j and &i 是一樣的值 , *j 是去 存取 那個 integer 的值 ,
*(&i) 也是 , 既然 i = 10 , 所以 *j 以及 also *(&i) 都等於 10 了 !!
我們不能作以下的事 : int *j ; *j = 10 ;
這是因為 int *j 宣告 j 是一個指標變數 , 內容是一個 integer 內容的記憶體位址 , 如果你沒有使用
malloc 去取得合法記憶體 , *j = 10 這個指令 , 會根據 j 當時記憶體位址 把 10 放進去 !!
但是這個位址不是合法取得 , 你把 10 塞進去那塊記憶體會讓程式有當掉風險 !!
j = (int*) malloc(sizeof(int)) ; 會取得一塊 integer size 的記憶體, 把此記憶體位址填入 j 的內容 ;
*j = 10 就是 從 j 內容的記憶體位址找出來 , 把 10 這個數字寫到那一塊記憶體進去 !!
以下是各種範例 !!
Case 1 :
int ptr[3][3] = {0,1,2,
3,4,5,
6,7,8} ;
printf("(%d)(%d)(%d)(%d)\n",*(*ptr),*(*ptr+1),*(*(ptr+1)),*(*(ptr+1)+1) ) ;
得到 : (0)(1)(3)(4)
因為 指標的 dereference , *ptr 相當於 ptr[0] , *(ptr+1) 相當於 ptr[1] ,
所以 , *(*ptr) = *(ptr[0]) = ptr[0][0] ...
*(*ptr+1) = *(ptr[0]+1) = ptr[0][1] ...
*(*(ptr+1)) = *(ptr[1]) = ptr[1][0] ...
*(*(ptr+1)+1) = *(ptr[1]+1) = ptr[1][1] ...
有點像是代數......
Case 2 :
int *m[3] ;
int idx,idy,width=5,height=3 ;
m[0] = (int*) malloc(width * height * sizeof(int)) ;
for(idx=0;idx<height*width;idx++)
{
*(m[0] + idx) = idx ;
}
for(idx=1;idx<height;idx++)
{
m[idx] = m[idx-1] + width ;
}
for(idx=0;idx<height;idx++)
{
for(idy=0;idy<width;idy++)
{
printf("(%d)",m[idx][idy]) ;
}
printf("\n") ;
}
Ans :
(0)(1)(2)(3)(4)
(5)(6)(7)(8)(9)
(10)(11)(12)(13)(14)
這個例子太簡單,不解釋 !!
Case 3 :
typedef struct node_
{
int level ;
int *ptr[1] ;
} node ;
node* x ;
x = (node*) malloc(sizeof(node) + 10 * sizeof(int*)) ;
x->level = 10 ;
for(idx=0;idx<=x->level;idx++)
{
printf("(%p)==>",&(x->ptr[idx]) ) ;
}
Ans :
(003E2514)==>(003E2518)==>(003E251C)==>(003E2520)==>(003E2524)==>(003E2528)==>(0
03E252C)==>(003E2530)==>(003E2534)==>(003E2538)==>(003E253C)==>
這個是很有用的指標用法, skip list 就是使用這個技巧,注意到 int *ptr[1]
這個語法是否怪怪的? 指標陣列的陣列長度為 1 ? 不就跟 int *ptr 一樣 ?
不一樣 !! 一個是指標陣列 , int *ptr 只是一個指標 ,
正常來說,我們在作 linked list 只需要 sizeof(node) 的記憶體,但是 skip list 需要有彈性高度的指標,
例如本例中的 10 , 注意 , 這個用法一定要將 int* ptr[1] 放在結構最後面,不在最後一定錯 !!
還有 , 假如指標有 4 bytes 的話, x 指標所指的空間有 : 8 + 10 * 4 = 48 bytes !!
也就是說 , x 有 11 個 integer pointer , 不是 10 個喔 ,原先的 node 結構是一個 ,
後面我們多加 十個指標空間給 x , total 是 48 bytes 連續空間 ,本例中, 記憶體裡面有一個 integer level,
加上十一個指標 : ptr[0] ~~ ptr[10] , 透過這種方法,可以操作彈性的指標陣列個數 !!
skip list 需要節省空間 , 必須彈性設定每個 node 高度 , 這個指標陣列用法是 excellent solution !!
注意 , int *ptr[0] 是相同意思 , 不過有些 compiler 會失敗 ! int *ptr[1] 則適用於每種 compiler !!
Case 4 :
typedef struct people_
{
char sex[9] ;
int age ;
char *name ;
char *phone[3] ;
} people ;
people Mars ;
strcpy(Mars.sex,"Male") ;
Mars.age = 10 ;
Mars.name = (char*) malloc(20) ;
strcpy(Mars.name,"Mars") ;
Mars.phone[0]= (char*) malloc(20) ;
Mars.phone[1]= (char*) malloc(20) ;
Mars.phone[2]= (char*) malloc(20) ;
strcpy(Mars.phone[0],"111-111-1111") ;
strcpy(Mars.phone[1],"222-222-2222") ;
strcpy(Mars.phone[2],"333-333-3333") ;
size_t offset ;
offset = offsetof(people,sex[0]) ;
char *sex = (char *) ( (char *)(&Mars) + offset) ;
printf("offset=(%d),sex=(%s)\n",offset,sex) ;
offset = offsetof(people,age) ;
int age = *(int *) ( (char *)(&Mars) + offset) ;
printf("offset=(%d),age=(%d)\n",offset,age) ;
offset = offsetof(people,name) ;
char *name = *(char **) ( (char *)(&Mars) + offset) ;
printf("offset=(%d),,name=(%s)\n",offset,name) ;
int idx,idy ;
char *phone ;
for(idx=0;idx<3;idx++)
{
offset = offsetof(people,phone[idx]) ;
phone = *(char **) ( (char *)(&Mars) + offset) ;
printf("offset=(%d),,phone=(%s)\n",offset,phone) ;
} //for
Ans :
offset=(0),sex=(Male)
offset=(12),age=(10)
offset=(16),,name=(Mars)
offset=(20),,phone=(111-111-1111)
offset=(24),,phone=(222-222-2222)
offset=(28),,phone=(333-333-3333)
offsetof return 第二個參數在 structure 裡面的 offset , age offset = 12 , not 10 ,
因為 memory alignment 讓 compiler 強迫每個變數的記憶體位址都必須是其變數長度的倍數 ,
integer 長度是 4 , 所以其記憶體必須 locate 在可以整除於 4 的位址 !! compiler 在 sex and age
中間塞了 2 個 byte 沒用的空間 !!
想一個問題 , 在 intel cpu 架構 , 一條 cache line 有 64 bytes !! 如果 一個變數沒有這樣調整的話,
你可能有一個 integer 變數 , 其前兩個 bytes 在 x cache line 最尾巴兩個空間, 後兩個 bytes
在另一個 y cache line 的最前面 , 此時 , concurrency 如何作 ? 你只能用 lock ,
integer 在同一個 cache line 時 , 同時間有讀有寫的 concurrency 對它不是問題 ,
可以做 atomic 存取, 這就是 compiler 對變數作 memory alignment 的原因 !!!
char *sex = (char *) ( (char *)(&Mars) + offset) ;
&Mars 是 structure 記憶體所在 , (char *)(&Mars) 把它變成一個 char * 的指標 ,
我舉個例子為啥這樣做 :
int* px = (int*) malloc(10 * sizeof(int)) ;
char* py = (char*) malloc(10 * sizeof(char)) ;
px所指的 integer 空間 跟 (px+1) 所指的 integer 空間 記憶體相差 4 bytes(如果 sizeof(int) = 4 的話) ,
py所指的 char 空間 跟 (px+1) 所指的 char 空間 記憶體相差 1 byte only !!!
所以, ( (char *)(&Mars) + offset) 可以順利得到從 &Mars 移動 offset bytes 空間的記憶體位址 !!
把這記憶體位址給 sex , 工作就完成了 !!!
offset = offsetof(people,age) ;
int age = *(int *) ( (char *)(&Mars) + offset) ;
這裡舉個例子 :
int ix = 10 ;
int iy = *(&ix) ; // iy = 10 , of course
從任何一個變數記憶體 dereference 出來的 , 就是其變數的值 !! 也就是說 , ix = *(&ix) ,
也就是說 , *& = 1 , 所以 ,
int age = *(int *) ( (char *)(&Mars) + offset) ;
把這個 ( (char *)(&Mars) + offset) address dereference 成 int , 就這樣而已 !!!
int idx,idy ;
char *phone ;
for(idx=0;idx<3;idx++)
{
offset = offsetof(people,phone[idx]) ;
phone = *(char **) ( (char *)(&Mars) + offset) ;
printf("offset=(%d),,phone=(%s)\n",offset,phone) ;
} //for
phone = *(char **) ( (char *)(&Mars) + offset) ;
( (char *)(&Mars) + offset) 這個 address 被 dereference 出來是
phone[0] or phone[1] or phone[2] , 也就是說 , 這個 address 內容放的是指標 !!!
舉個例子 :
char *ps1,*ps2 ;
ps1 = malloc(10) ;
strcpy(ps1,"12345");
ps2 = *(char**)(&ps1) ;
printf("(%s)\n",ps2) ;
這個例子可以清楚解釋我的想法 !!
int *ps1,*ps2 ;
ps1 = ps2 ;
printf("(%p)(%p)\n",ps1,ps2) ;
address of ps1 and address of ps2 is different ,
但是它們內容相同 , called by pointer 就是這個觀念 !!!!
留言列表