【C】 28_指標和陣列分析(上)

TianSong發表於2019-05-10

陣列的本質

  • 陣列是一段連續的記憶體空間
  • 陣列的空間大小為 sizeof(array_type) * array_size【array_size:陣列的元素個數】
  • 陣列名可看作指向陣列第一個元素的常量指標

問題:

1. a + 1 的意義是什麼?結果是什麼
2. 指標運算的意義是什麼?結果又是什麼?

程式設計實驗: a + 1 的結果是什麼?

#include <stdio.h>

int main()
{
    int a[5] = {0};
    int* p = NULL;
    
    printf("a = 0x%X
", (unsigned int)(a));
    printf("a + 1 = 0x%X
", (unsigned int)(a + 1));
    
    printf("p = 0x%X
", (unsigned int)(p));
    printf("p + 1 = 0x%X
", (unsigned int)(p + 1));

    return 0;
}
輸出:
a = 0xBFD627C8
a + 1 = 0xBFD627CC
p = 0x0
p + 1 = 0x4

分析:
p + 1 ==> 0 + 1 * sizeof(*p) ==> 0 + 1 * sizeof(int) ==> 0 + 4 ==> 4
a + 1 ==> 0xBFD627C8 + 1 * sizeof(*a) ==> 0xBFD627C8 + 1 * sizeof(a[0]) ==> 0xBFD627C8 + 1 * sizeof(int) ==> 0xBFD627C8 + 1 * 4 ==> 0xBFD627C8 + 4 ==> 0xBFD627CC  

指標的運算

  • 指標是一種特殊的變數,與整數的運算規則為

p+n; <--> (unsigned int)p + n * sizeof(*p)

結論:當指標指向一個同型別的陣列的元素時, p+1 將指向當前元素的下一個元素; p-1 將指向當前元素的上一個元素。

  • 指標之間只支援減法運算
  • 參與減法運算的指標型別必須相同

p1 - p2; <--> ((unsigned int)p1 - (unsigned int)p2) / sizeof(type);

注意:

1. 只有當兩個指標指向同一個陣列中的元素時,指標相減才有意義,其意義為指標所指元素的**下標差**。
2. 當兩個指標指向的元素不在同一個陣列中時,結果未定義。

以上兩條注意事項面對絕大部分的使用情況。

指標的運算是很靈活的,在特殊情況下,可以通過強制型別的轉換,實現不同型別指標間的運算,而得到巧妙的結果。    
已知一個結構體裡面的成員地址,可以反推出該結構體的首地址 :
struct _tag
{
    int aa;
    int bb;

    unsigned int* node; 
};

指標的比較

  • 指標也可以進行關係運算( <, <=, >, >= )
  • 任意關係運算的前提是同時指向同一個陣列中的元素
  • 任意兩個指標之間的比較運算( ==, != ) 無限制
  • 參與比較運算的指標型別必須相同

例項分析: 指標運算初探

#include <stdio.h>

int main()
{
    char s1[] = {`H`, `e`, `l`, `l`, `o`};
    int i = 0;
    char s2[] = {`W`, `o`, `r`, `l`, `d`};
    char* p0 = s1;
    char* p1 = &s1[3];
    char* p2 = s2;
    int* p = &i;
    
    printf("%d
", p0 - p1);
    // printf("%d
", p0 + p1);
    // printf("%d
", p0 - p2);
    // printf("%d
", p0 - p);
    // printf("%d
", p0 * p1);
    // printf("%d
", p0 / p1);

    return 0;
}
輸出:
-3

分析:
p0 - p2; 編譯無警告,無錯誤,但大部分情況下,這樣操作是沒有實際意義的

p0 + p1; error: invalid operands to binary + (have ‘char *’ and ‘char *’) // 操作符不支援 
p0 - p;  error: invalid operands to binary - (have ‘char *’ and ‘int *’)  // 指標型別不同
p0 * p1; error: invalid operands to binary * (have ‘char *’ and ‘char *’) // 操作符不支援
p0 / p1; error: invalid operands to binary / (have ‘char *’ and ‘char *’) // 操作符不支援

例項分析: 指標運算的應用

#include <stdio.h>

#define DIM(a) (sizeof(a) / sizeof(*a))

int main()
{
    char s[] = {`H`, `e`, `l`, `l`, `o`};
    char* pBegin = s;
    char* pEnd = s + DIM(s);  // key point
    char* p = NULL;
    
    printf("pBegin = %p
", pBegin);
    printf("pEnd = %p
", pEnd);
    
    printf("Size: %d
", pEnd - pBegin);
    
    for(p=pBegin; p<pEnd; p++)
    {
        printf("%c
", *p);
    }
    
    printf("
");

    return 0;
}
輸出:
pBegin = 0xbf9c17af
pEnd = 0xbf9c17b4
Size: 5
H
e
l
l
o

分析:
pEnd = s + DIM(s)  ==>
s + 5 ==> 0xbf9c17af + 5 * sizeof(*s)  ==> 0xbf9c17af + 5 * sizeof(char) ==> 0xbf9c17af + 5 * 1 ==> 0xbf9c17af + 5 ==> 0xbf9c17b4

小結

  • 陣列宣告時編譯器自動分配一片連續的記憶體空間,空間名為陣列名
  • 指標宣告是隻分配了用於容納地址值的 4 位元組空間
  • 指標和整數可以進行運算,其結果為整數
  • 指標之間只支援減法運算,其結果為陣列元素下標差
  • 指標之間支援比較運算,其型別必須相同

補充:以上實驗在32位機器中執行。

 當指標大小佔用 8 位元組時(64位機器), 使用 (unsigned int) 強制型別轉換將發生資料截斷,導致得到不正常的結果。

以上內容參考狄泰軟體學院系列課程,請大家保護原創!

相關文章