使用char *输出以指向int数组

时间:2018-08-10 12:10:51

标签: c pointers

用C编写的以下程序的输出是什么?

2 0还是0 2,为什么?

int main()
{
    int arr[]={2,3,4};  // predefined pointer
    char *p;
    p=(char *)arr;

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

    printf("%d\n",*p);
    printf("%p\n",p);

    return 0;

}

2 个答案:

答案 0 :(得分:6)

结果取决于系统的endianness以及int的大小(还取决于字节中的位数,但是现在我们假设它是8 )。

字节序决定字节类型(例如整数)的顺序。基于x86的处理器是 little-endian ,这意味着最低有效字节在前,而其他处理器是 big-endian ,这意味着最高有效字节在前。

例如,对于类型为int且值为2的变量,并假设int为32位,大端字节系统上的内存如下所示:

-----------------
| 0 | 0 | 0 | 2 |
-----------------

在小端系统上,它看起来像这样:

-----------------
| 2 | 0 | 0 | 0 |
-----------------

继续研究当您使用char *并将其指向一个int(或int数组的成员)时发生的情况。通常,使用指向一种类型的指针指向另一种类型并通过另一种指针读取值是严格的别名冲突,这会调用undefined behavior,但是C标准对字符类型有例外,以允许您访问对象表示形式中的字节。因此,在这种情况下是允许的。

执行此操作时:

p=(char *)arr;

它使p指向数组arr的第一个成员的第一个字节。

在大端系统上:

-----
| . | p
-----
  |
  v
-------------------------------------------------
| 0 | 0 | 0 | 2 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 4 | arr
-------------------------------------------------
|    arr[0]     |    arr[1]     |    arr[2]     |
-------------------------------------------------

在小端上:

-----
| . | p
-----
  |
  v
-------------------------------------------------
| 2 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | arr
-------------------------------------------------
|    arr[0]     |    arr[1]     |    arr[2]     |
-------------------------------------------------

因此,当您读取*p的值时,在大字节序系统上将得到0,在小字节序系统上将得到2。

当您执行p=p+1时,您将指向p的地址增加1个字符,即1个字节,所以现在看起来像这样:

大端:

-----
| . | p
-----
  |----
      v
-------------------------------------------------
| 0 | 0 | 0 | 2 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 4 | arr
-------------------------------------------------
|    arr[0]     |    arr[1]     |    arr[2]     |
-------------------------------------------------

小尾数法

-----
| . | p
-----
  |----
      v
-------------------------------------------------
| 2 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | arr
-------------------------------------------------
|    arr[0]     |    arr[1]     |    arr[2]     |
-------------------------------------------------

现在*p在大端和小端系统上都包含值0。但是,这假设int是32位的。如果int为16位,则如下所示:

大端:

-----
| . | p
-----
  |----
      v
-------------------------
| 0 | 2 | 0 | 3 | 0 | 4 | arr
-------------------------
|arr[0] |arr[1] |arr[2] |
-------------------------

小尾数法

-----
| . | p
-----
  |----
      v
-------------------------
| 2 | 0 | 3 | 0 | 4 | 0 | arr
-------------------------
|arr[0] |arr[1] |arr[2] |
-------------------------

在这种情况下,*p在递增后在大字节序系统上为2,在小字节序系统上为0。

答案 1 :(得分:1)

int arr[]={2,3,4};

如果您的系统支持小字节序,则如下所示,如果大字节序输出可能会有所不同。

 arr[2]      arr[1]   |------------arr[0]-----------------------------|  
 ----------------------------------------------------------------------
|     4      |   3    | 0000 0000 | 0000 0000 | 0000 0000 | 0000 0010  | 
 ----------------------------------------------------------------------
           0x108    0x104       0x103      0x102       0x101       0x100 -- assume arr base address starts from 0x100
                                                                     arr
MSB                                                                  LSB

现在,当您这样做

char *p;
p=(char *)arr;

这里p char指针arr类型,强制转换为char*,这意味着指针p指向一个字节的内存一次定位,即第一次0x1000x101

陈述时

printf("%d\n",*p);

执行它会打印0x100-0x101的{​​{1}}位置中存在的数据,因此它会打印2

接下来要做的是

2

指针p=p+1; 递增1个字节,即现在p指向p的存储位置,并且在执行语句0x101时它会打印{{1 }}位置printf("%d\n",*p);,因此它打印0x101-0x102

此外,在使用0时,您还应将指针变量的类型转换为0,并转换为printf("%p") and casting to (void *)

%p