[C/C++] 指標相加 = ?or 相減 = offset

最近看到網路上討論 C/C++ 題目,某公司主管給新進人員面試的 C/C++ 考題,如下:
int main(void)
{
     int *a,*b;
     a=1;
     b=1;
     printf("%d\n",a+b);
     return 0;
}
請問上面這個題目,哪裡有出問題,這是面試官問新進人員的題目之一,看也知道這程式丟到 Dev-C++ 是不會過的,*a *b 都是宣告為整數指標型態,可是在 a=1 或 b=1 在 Dev-C++ 裡面是編譯不過的,但是那寫法是沒有錯的,就像你設定 a=0 或者是 a=NULL 是一樣意思,不過最好是不要這樣寫,assignment 這樣寫不太好,可以改成 a = (int *)1; b = (int *)1; 這樣就可以順利編譯通過,再來 printf(“%d\n”,a+b); 這行錯很大,指標相加會爆炸吧,如果程式這樣寫,不把 OS 搞掛,那我還會覺得懷疑呢,正確寫法是指標加上 offset(位移),這樣才是可以正確執行的,所以我們把程式改成下面:
int main(void)
{
     int *a,*b;
     a = (int *)1;
     b = (int *)1;
     printf("%d\n",a+(int)b);
     return 0;
}
最後的執行結果是 5,(int) b 就相當於 sizeof(*b) 也等於 sizeof(int *) 答案都是四,所以就是 1+4 =5,指標是不能相加的,只能透過 offset 方式來讓指標指向不同 base,但是如果是指標相減,那就是求 offset 的意思喔,看一下底下例子
int main(void)
{
    int *a,*b;
    a = (int *)0x5566;
    b = (int *)0x5570;
    printf("%d %d %d %d %d\n", a, b, (int)a+(int)b, a+(int)b, sizeof(int *));
    printf("%d\n", a - b);
    printf("%d\n", ((int)b - (int)a)/sizeof(int *));
    return 0;
}
要算 offset 也非常容易,只要先轉成 10 進位相減在除以 sizeof(int *) 這樣就可以求出結果了,a-b 除以四其實 -2.5 取補數,所以是 -3,如果是 b-a 就是整數3了,只是位移 3 個 bit,其實觀念就是這樣,指標位址不能相加,但是指標位址可以相減 = Offset,觀念大致上是這樣,最後補上完整程式,大家可以 run 一次看看就知道了
#include "string.h"
#include "stdlib.h"
#include "stdio.h"

int main(void)
{
    int *a, *b;
    a = (int *)1;
    b = (int *)1;
    printf("%d %d %d\n", a + (int)b, (int)(a + (int)b), (int)a + (int)b); 
    a = (int *)0x5566;
    b = (int *)0x5570;

    printf("%d %d %d %d %d\n", a, b, (int)a+(int)b, a+(int)b, sizeof(int *));
    printf("%d\n", a - b);
    printf("%d\n", ((int)b - (int)a)/sizeof(int *));
    
    a = (int*)0x1000;
    b = a + 3;
    printf("%d %d %p %p \n", a, b, a, b);
    
    system("pause");
    return 0;
}
  • Brian

    遇到同好,討論一下 🙂
    int main(void)
    {
    int *a,*b;
    a = (int *)1;
    b = (int *)1;
    printf(“%d\n”,a+(int)b);
    return 0;
    }

    printf 結果是 5 沒錯,不過我的見解是 (int)b 不代表這是 sizeof(*b),
    而是 1 + sizeof(*a)*(int)b = 1 + 4*1 = 5;
    我想應該是筆誤。

  • definite

    > 正確寫法是指標加上 offset(位移),這樣才是可以正確執行的,所以我們把程式改成下面:

    這樣還是太複雜,把 * 拿掉不就完了嘛? 😛

  • gene

    int main(void)
    {
    short *a;
    int *b;
    a = (int *)2;
    b = (int *)3;
    printf(“%dn”,a+(int)b);
    printf(“%dn”,(int)a+b);
    printf(“%dn”,(int)a+(int)b);
    return 0;
    }

    印出來是
    8
    11
    5