【问题标题】:using C Pointer with char array将 C 指针与 char 数组一起使用
【发布时间】:2012-11-14 19:11:13
【问题描述】:
int i=512;
char *c = (char *)&i;
c[0] =1;
printf("%d",i);

这显示“513”,它将 i 加 1。

int i=512;
char *c = (char *)&i;
c[1] =1;
printf("%d",i);

而这显示 256。将其除以 2。 有人可以解释为什么吗?非常感谢

【问题讨论】:

标签: c arrays pointers character-arrays


【解决方案1】:

二进制

用二进制表示的32位数字512,就是:

00000000000000000000001000000000

因为 2 的 9 次方是 512。通常,您从右到左读取位。

这里有一些其他的二进制十进制数:

0001 = 1
0010 = 2
0011 = 3
0100 = 4

演员表:将 Int 重新解释为字节数组

当你这样做时:

int i = 512;
char *c = (char *)&i;

您可能知道,您将 4 字节整数解释为字符数组(8 位字节)。如果没有,这是发生了什么:

&i

获取变量i的地址。

(char *)&i

将其重新解释(或强制转换)为指向 char 类型的指针。这意味着它现在可以像数组一样使用。由于您知道 int 在您的机器上至少是 32 位的,因此可以使用 c[0], c[1], c[2], c[3] 访问其字节。

根据系统的endianness,可能会布置数字的字节:最高有效字节在前(大端),或最低有效字节在前(小端)。 x86 处理器是小端的。这基本上意味着数字 512 的布局如上例所示,即:

00000000 00000000 00000010 00000000
    c[3]     c[2]     c[1]     c[0]

我已经根据它们在内存中的布局方式将这些位分组为单独的 8 位块(字节)。请注意,您也可以在此处从右到左阅读它们,因此我们可以保持二进制数系统的约定。

后果

现在设置c[0] = 1有这个效果:

00000000 00000000 00000010 00000001
    c[3]     c[2]     c[1]     c[0]

十进制为2^9 + 2^0 == 513

设置c[1] = 1有这个效果:

00000000 00000000 00000001 00000000
    c[3]     c[2]     c[1]     c[0]

这是十进制的2^8 == 256,因为您已经用 00000001 覆盖第二个字节 00000010

请注意在 big endian 系统上,bytes 将以与 little endian 系统相反的顺序存储。这意味着如果你在其中一台机器上运行它,你会得到完全不同的结果。

【讨论】:

  • 感谢您的精彩解释,但我只剩下一件事让我感到困惑.. code (char *)&i code 如何被解释为 4 字节整数?跨度>
  • 不是。它将 4 字节整数解释为一组字节 (char)。基本上,您将获取i 的地址,然后将其cast 转换为指向charpointer。这意味着它可以被解释为一个字节数组。
【解决方案2】:

记住 char 是 8 位,512 是位表示是
512 = 10 0000 0000

当你做char *c = (char *)&i; 你做:

c[1] = 10
c[0] = 0000 0000

当你做 c[0] = 1 你让它10 0000 0001 是513。

当您执行 c[1] = 1 时,您将其设为 01 0000 0000,即 256。

【讨论】:

    【解决方案3】:

    在您想知道为什么您看到的是“奇怪”之前,请考虑一下您运行代码的平台,以及其中的 endianness

    然后考虑以下

    int main(int argc, char *argv[])
    {
        int i=512;
        printf("%d : ", i);
        unsigned char *p = (unsigned char*)&i;
        for (size_t j=0;j<sizeof(i);j++)
            printf("%02X", p[j]);
        printf("\n");
    
        char *c = (char *)&i;
        c[0] =1;
        printf("%d : ", i);
        for (size_t j=0;j<sizeof(i);j++)
            printf("%02X", p[j]);
        printf("\n");
    
        i = 512;
        c[1] =1;
        printf("%d : ", i);
        for (size_t j=0;j<sizeof(i);j++)
            printf("%02X", p[j]);
        printf("\n");
        return 0;
    }
    

    在我的平台上(Macbook Air、OS X 10.8、Intel x64 Arch)

    512 : 00020000
    513 : 01020000
    256 : 00010000
    

    将您在上面看到的内容与您希望阅读的有关endianness 的内容结合起来,您可以清楚地看到我的平台是little endian。那你的呢?

    【讨论】:

      【解决方案4】:

      由于您通过char 指针对int 进行别名处理,并且char 是8 位宽(一个字节),因此分配:

      c[1] = 1;
      

      i 的第二个字节设置为000000001。字节 1、3 和 4(如果 sizeof(int) == 4)将保持不变。以前,第二个字节是000000010(因为我假设您使用的是基于x86 的计算机,这是一种小端架构。)所以基本上,您将唯一设置为一个位置的位向右移动。那是除以 2。

      在 little-endian 机器和 32 位 int 编译器上,您最初在 i 中有这四个字节:

        c[0]      c[1]      c[2]     c[3]
      00000000  00000010  00000000 00000000
      

      分配后,i 被设置为:

        c[0]      c[1]      c[2]     c[3]
      00000000  00000001  00000000 00000000
      

      因此它从 512 变为 256。

      现在你应该明白为什么 c[0] = 1 会导致 513 :-) 想想哪个字节被设置为 1 并且分配根本不会改变其他字节。

      【讨论】:

        【解决方案5】:

        这是因为你的机器是little endian,这意味着最低有效字节首先存储在内存中。

        你说int i=512;512 是十六进制的 0x00000200(为简单起见,假设是 32 位操作系统)。让我们看看i 是如何以十六进制字节存储在内存中的:

          00 02 00 00  // 4 bytes, least-significant byte first
        

        现在我们通过 char *c = (char *)&amp;i; 将相同的内存位置解释为字符数组 - 相同的内存,不同的解释

          00 02 00 00
        c[0][1][2][3]
        

        现在我们将c[0] 更改为c[0] =1;,内存看起来像

          01 02 00 00
        

        这意味着如果我们再次将其视为小端 int(通过执行 printf("%d",i);),它是十六进制 0x00000201,即 513 十进制。

        现在,如果我们返回并将c[1] 更改为c[1] =1;,您的记忆现在变为:

          00 01 00 00
        

        现在我们回过头来把它解释为小端序int,它是十六进制的0x00000100,也就是十进制的256

        【讨论】:

          【解决方案6】:

          这取决于机器是little endian还是big endian,数据如何以位存储。更多信息请阅读endianness

          C 语言不保证这一点。

          512 in binary :
          
              =============================================
              0000 0000 | 0000 0000 | 0000 0010 | 0000 0000   ==>512
              =============================================
                12          34          56          78       
          

          (0x12345678 假设这个 int 的地址)

          char *c =(char *)&i now c[0] either point to 0x78 or 0x12
          Modifying the value using c[0] may result to 513 if it points to 0x78
              =============================================
              0000 0000 | 0000 0000 | 0000 0010 | 0000 0001   ==> 513
              =============================================
          
          or, can be 
          
              =============================================
              0000 0001 | 0000 0000 | 0000 0010 | 0000 0000  ==>2^24+512
              =============================================
          

          对于 256 也类似:因为您的 c1 将具有右起第二个字节的地址。 如下图,

              =============================================
              0000 0000 | 0000 0000 | 0000 0001 | 0000 0000  ==>256
              =============================================
          

          所以它在我们的系统中实现了数字的表示

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-01-26
            • 1970-01-01
            • 2018-04-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-19
            相关资源
            最近更新 更多