在指標算術中進行額外的縮放

在指標運算中,要新增或減去指標的整數不是解釋為地址的變化,而是解釋為要移動的元素的數量。

#include <stdio.h>

int main(void) {
    int array[] = {1, 2, 3, 4, 5};
    int *ptr = &array[0];
    int *ptr2 = ptr + sizeof(int) * 2; /* wrong */
    printf("%d %d\n", *ptr, *ptr2);
    return 0;
}

此程式碼在計算分配給 ptr2 的指標時進行了額外的縮放。如果 sizeof(int) 是 4,這在現代 32 位環境中是典型的,則表示式代表“array[0] 之後的 8 個元素”,這是超出範圍的,並且它呼叫未定義的行為

要讓 ptr2 指向 array[0] 之後的 2 個元素,你應該簡單地新增 2。

#include <stdio.h>

int main(void) {
    int array[] = {1, 2, 3, 4, 5};
    int *ptr = &array[0];
    int *ptr2 = ptr + 2;
    printf("%d %d\n", *ptr, *ptr2); /* "1 3" will be printed */
    return 0;
}

使用加法運算子的顯式指標演算法可能會令人困惑,因此使用陣列下標可能會更好。

#include <stdio.h>

int main(void) {
    int array[] = {1, 2, 3, 4, 5};
    int *ptr = &array[0];
    int *ptr2 = &ptr[2];
    printf("%d %d\n", *ptr, *ptr2); /* "1 3" will be printed */
    return 0;
}

E1[E2](*((E1)+(E2))) 相同( N1570 6.5.2.1,第 2 段),&(E1[E2]) 相當於 ((E1)+(E2))(N1570 6.5.3.2,腳註 102)。

或者,如果首選指標運算,則將指標轉換為定址不同的資料型別可以允許位元組定址。但請注意: endianness 可能會成為一個問題,並且轉換為指向字元的指標以外的型別會導致嚴格的別名問題

#include <stdio.h>

int main(void) {
    int array[3] = {1,2,3};  // 4 bytes * 3 allocated
    unsigned char *ptr = (unsigned char *) array;  // unsigned chars only take 1 byte
    /*
     * Now any pointer arithmetic on ptr will match
     * bytes in memory.  ptr can be treated like it
     * was declared as: unsigned char ptr[12];
     */

    return 0;
}