【C進階】28、指標和陣列分析

bryson發表於2021-12-30

Summary

1)陣列是一段連續的記憶體空間,陣列的元素個數為 #define DIM(a) (sizeof(a) / sizeof(*a))

2)指標是一種特殊的變數與整數的運算規則為
p + n; <--> (unsigned int)p + n * sizeof(*p)
當指標p指向一個陣列裡的元素時,p + 1將指向當前元素的下一元素p - 1將指向當前元素的上一元素

3)指標之間只支援減法運算;參與減法運算的指標必須型別相同
注意:只有當2個指標指向同一個陣列中的元素時,指標相減才有意義,意義為指標所指元素的下標差;當2個指標指向的元素不在同一個陣列時未定義
p1 - p2; <--> ((unsigned int)p1 - (unsigned int)p2) / sizeof(type);

4)char* pEnd = s + DIM(s); pEnd指向了陣列s中最後一個元素的後一位置,雖然這個位置不屬於陣列,但在C語言中,仍然認為這個邊界位置是屬於陣列的,這個知識點在STL中也有應用。

5)指標也可以進行關係運算(<, <=, >, >=),但前提是同時指向同一個陣列中的元素
兩個指標間可以進行比較運算(==,!=),但兩個指標的型別必須相同

6)for (p = pBegin; p < pEnd; p++) ,p指向了陣列的首元素,pEnd在C語言中被認為是陣列的元素,所以p和pEnd都指向了同一個陣列裡的元素,型別相同,能夠進行比較

指標和陣列分析

陣列是一段連續的記憶體空間
陣列的空間大小為 sizeof(arr_type) * arr_size
陣列名可看做指向陣列第一個元素的指標常量

1、指標的運算

問題:對於陣列int a[5],a + 1的意義是什麼?結果是什麼?指標運算的意義是什麼,結果又是什麼?

結論:
指標是一種特殊的變數與整數的運算規則為
p + n; <--> (unsigned int)p + n * sizeof(*p)
當指標p指向一個陣列裡的元素時,p + 1將指向當前元素的下一元素p - 1將指向當前元素的上一元素

#include <stdio.h>

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

輸出:
a = 0xBFCEEF78
a = 0xBFCEEF7C
p = 0x0
p = 0x4

指標之間只支援減法運算;參與減法運算的指標必須型別相同
p1 - p2; <--> ((unsigned int)p1 - (unsigned int)p2) / sizeof(type);
注意:只有當2個指標指向同一個陣列中的元素時,指標相減才有意義,意義為指標所指元素的下標差;當2個指標指向的元素不在同一個陣列時未定義

#include <stdio.h>

int main()
{
    char s1[] = {'H', 'e', 'l', 'l', 'o'};
    char s2[] = {'H', 'e', 'l', 'l', 'o'};    
    char* p0 = s1;
    char* p1 = &s1[3];
    char* p2 = s2;
    int i = 0;
    int* p = &i;
    
    
    printf("%d\n", p0 - p1);    // 下標差:-3
    printf("%d\n", p0 + p2);    // error
    printf("%d\n", p0 - p2);    // undefined behavior
    printf("%d\n", p0 - p);     // error
    printf("%d\n", p0 * p2);    // error
    printf("%d\n", p0 / p1);    // error
    
    return 0;
}
輸出:(指標之間的+ * / 都不允許,不同型別指標的減法運算也不允許)
test.c:17: error: invalid operands to binary + (have ‘char *’ and ‘char *’)
test.c:19: error: invalid operands to binary - (have ‘char *’ and ‘int *’)
test.c:20: error: invalid operands to binary * (have ‘char *’ and ‘char *’)
test.c:21: error: invalid operands to binary / (have ‘char *’ and ‘char *’)

p0 - p2的輸出為5,但並不知道這是什麼意思
#include <stdio.h>

// 計算陣列的大小
#define DIM(a) (sizeof(a) / sizeof(*a))      

int main()
{
    int s1[] = {'H', 'e', 'l', 'l', 'o'};
    int s2[] = {'H', 'e', 'l', 'l', 'o'};    
    int* p0 = s1;
    int* p1 = &s1[3];
    printf("p1 - p0 = %d\n\n", p1 - p0);        // 3


    char s[] = {'H', 'e', 'l', 'l', 'o'};
    char* pBegin = s;
    char* pEnd = s + DIM(s);
    char* p = NULL;
    
    
    printf("pBegin = %p\n", pBegin);
    printf("pEnd = %p\n", pEnd);
    
    printf("Size: %d\n", pEnd - pBegin);    // 5
    
    for (p = pBegin; p < pEnd; p++)         // 指標比較,指標運算
    {
        printf("%C", *p);
    }
    printf("\n");
    
    return 0;
}

輸出:
p1 - p0 = 3

pBegin = 0xbf9ff2a7
pEnd = 0xbf9ff2ac
Size: 5
Hello

分析:

  • char* pEnd = s + DIM(s); pEnd指向了陣列s中最後一個元素的後一位置,雖然這個位置不屬於陣列,但在C語言中,仍然認為這個邊界位置是屬於陣列的,這個知識點在STL中也有應用。
  • for (p = pBegin; p < pEnd; p++) ,p指向了陣列的首元素,pEnd在C語言中被認為是陣列的元素,所以p和pEnd都指向了同一個陣列裡的元素,型別相同,能夠進行比較

2、指標的比較

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

#include <stdio.h>   

int main()
{
    int a[5] = {0};
    int* p0 = a;
    int* p1 = &a[1];
    char* p2;
    
    
    printf("%d\n", p1 < p0);    // ok, 0
    printf("%d\n", p1 < p2);    // undefined    

    printf("%d\n", p1 != p0);   // ok, 1 
    printf("%d\n", p1 == p2);   // undefined
    
    return 0;
}

以上程式碼在編譯時已經warning:
test.c:14: warning: comparison of distinct pointer types lacks a cast
test.c:17: warning: comparison of distinct pointer types lacks a cast

本文總結自“狄泰軟體學院”唐佐林老師《C語言進階課程》。
如有錯漏之處,懇請指正。

相關文章