陣列 1 的各不相同(或許會有你的盲點)

2021-05-27 22:26:56 字數 4339 閱讀 4826

在討論這個問題前, 我們先看一段**。這段**,大家都會很容易看懂, 但是真正能夠明白的我不知道有幾。

/*   ** 1-1   */

#include int main() 

; int *ptr=(int *)(&a+1);

printf("%d,%d",*(a+1),*(ptr-1));

return 0;

}

輸出結果為: 2, 5

討論:

當我第一眼看到這個**的時候, 我的第一直覺答案是2, 1. 但是當執行結果出來以後, 我蒙了。為什麼會是2, 5 呢。後來我就測試了輸出他的位址(原來最終問題,通過檢視記憶體才是王道),我就發現了問題的所在。主要的原因就在於 &a + 1 這裡。

這裡給出我檢視記憶體運**況的**:

/*     **1-2     */

#include int main() ;	

printf("c = %p, c+1 = %p, &c+1 = %p\n", c, c+1, &c+1);

/* 陣列名c 的位址, 陣列名c + 1 的位址, 陣列名位址 + 1 的位址*/

return 0;

}

執行結果: c = 0022ff18, c+1 = 0022ff1c, &c+1 = 0022ff30

通過這個輸出結果, 我們不難看出,c+1 的位址是在陣列位址(c 的位址)的基礎上加了1 個int。但是,&c + 1 的位址是在陣列位址(c 的位址)的基礎上加了6 個int 。而這6 個int 就是整個陣列的長度。這不是偶然,這是必然。就是說,在陣列位址的基礎上加 1 就相當於再加了乙個陣列(跳過乙個陣列的長度)。

這樣我們就不難解釋上面** 1-1,為什麼結果是2, 5 。

int *ptr=(int *)(&a+1);

這裡的ptr 位址實際上就是跳到整個陣列的最末端,然後新開始的乙個陣列(即元素5 後面的乙個位置)。所以,當輸出*(ptr-1) 就是5 。

討論了一維陣列的情況, 下面我們接著看看二維陣列。

按理說,把一維陣列弄明白了二維陣列就很簡單,這裡因為筆者在後面寫二維陣列的時候也遇到了點麻煩,所以就多多囉嗦一下。

下面我們看一段測試**:

/*       ** 2 - 1    */

#include int main() 

, };

// 陣列名的不同 +1

printf("結果1\n");

printf("** a = %d\n", **a);

printf("a = %p\n", a);

printf("&a = %p\n", &a);

printf("a+1 = %p\n", a+1);

printf("&a+1 = %p\n", &a+1);

printf("\n");

// 陣列起始單元的不同+1

printf("結果2\n");

printf("* a[0] = %d\n", *a[0]);

printf("&a[0] = %p\n", &a);

printf("a[0]+1 = %p\n", a[0]+1);

printf("&a[0]+1 = %p\n", a[0]+1);

printf("\n");

// 陣列中間單元不同+1

printf("結果3\n");

printf("a[0][1] = %d\n", a[0][1]);

printf("&a[0][1] = %p\n", &a[0][1]);

printf("&a[0][1]+1 = %p\n", &a[0][1]+1);

return 0;

}

輸出結果為:

結果1** a        = 1

a          = 0022ff18                   // 陣列名

&a         = 0022ff18                  // 陣列名位址

a+1        = 0022ff24                 // 陣列名加1 , 結果為跳轉到下一行(即第二行,這裡跳過3 個int)開頭。

&a+1       = 0022ff30                // 陣列名位址加1, 按照上文介紹,跳轉到下乙個陣列的位置(即跳過整個數                                          組,如果是加2 , 那麼就跳過2 個陣列空間的位置。),這裡就跨過了6 個int 的空間。

結果2* a[0]      = 1                            

&a[0]      = 0022ff18             // 陣列中第一行行名位址

a[0]+1     = 0022ff1c            // 陣列中第一行行名加1, 結果為跳轉到同行的下乙個元素位置(跳過1 個int)

&a[0]+1    = 0022ff24           // 陣列中第一行行名位址加1, 結果為跳轉一行的位址,到下一行的行頭位置                                           (即跳轉了3 個int 位置)。

結果3a[0][1]    = 2

&a[0][1]   = 0022ff1c           // 陣列中位置為[0][1]  的位址

&a[0][1]+1 = 0022ff20         // 陣列中位置為[0][1]  的位址加1 ,結果跳轉了1 個int 的位置。跳轉到同行的下一                                      個元素位置。是本行的行末位置,那麼就跳轉到下一行的開頭位置。

這段**有點多, 都是printf(); 這個不重要,重要的是輸出的內容。分析就在答案的後面注釋。

從這裡的結果, 我們可以看出結果3中的 &a[0][1]+1 = 0022ff20 與結果1, 結果2中的 &a+1       = 0022ff30 , &a[0]+1    = 0022ff24  運算方式是不同的。這是因為,結果1和結果2 中是對陣列名位址加1, 而結果3 不是 對陣列名位址加1, 他只是陣列中間的乙個元素位址。如果要進一步深究,我們可以再把指標帶進來考慮就可以更加清晰明白。

指標的操作,就相當於上面結果3 的操作結果一樣。他的操作都是按部就班,不會存在因為加1 而跳轉乙個陣列的長度的情況。下面我們看看測試**:

/*    ** 3 -1     */

#include int main()

, };

int *p1 = *a; // 取a 的位址

int *p2 = a[0]; // 取a[0] 的位址

int *p3 = &a[0][1]; // 去a[0][1] 的位址

printf("p1 = %p \n", p1);

printf("p1+1 = %p \n", p1+1);

printf("p2 = %p \n", p2);

printf("p2+1 = %p \n", p2+1);

printf("p3 = %p \n", p3);

printf("p3+1 = %p \n", p3+1);

return 0;

}

輸出結果:

p1   = 0022ff0c

p1+1 = 0022ff10

p2   = 0022ff0c

p2+1 = 0022ff10

p3   = 0022ff10

p3+1 = 0022ff14

從這個結果可以看出指標的跳轉是按位置跳轉的。一次只能跳轉偏移個數個位置。

比如: int *p = a;            p + 3;  就表示跳轉從當前p 的位置, 跳轉到之後的第三個位置。

總結:

綜上所訴,筆者最想表達的是,在陣列名取位址然後增加偏移量時, 他是按照整個陣列再進行跳轉。即跳過整個陣列的長度的偏移量倍。

Unity 產生各不相同的隨機數

1.網上很多方法都說用時間種子來解決,但是在極短的時間內,這種方法沒效 random r new random datetime.now.millisecond random counter new random unchecked int datetime.now.ticks ctr random...

oracle查詢多條條件各不相同的資料

object object employeeservice.querybysqluniqueresult select select count from pm overtime where empid employee.getid and overtype 3 and overdate to da...

Unity菜鳥 產生各不相同的隨機數

1.網上很多方法都說用時間種子來解決,但是在極短的時間內,這種方法沒效 random r new random datetime.now.millisecond random counter new random unchecked int datetime.now.ticks ctr random...