使用C指针与char数组

时间:2012-11-14 19:11:14

标签: c arrays pointers character-arrays

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。 有人可以解释一下原因吗?非常感谢

6 个答案:

答案 0 :(得分:12)

二进制

以二进制表示的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,因为你已经覆盖了第二个字节00000010和00000001

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

答案 1 :(得分: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。

答案 2 :(得分:2)

在你想知道为什么你看到的是“奇怪的”之前,请考虑你正在运行代码的平台,以及其中的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 。你的是什么?

答案 3 :(得分:1)

由于您通过int指针对char进行别名,并且char为8位宽(一个字节),因此赋值:

c[1] = 1;

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

在一个小端机器和一个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并且赋值不会改变其他字节。

答案 4 :(得分:0)

这取决于机器是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也是:因为你的c 1将具有右边第二个字节的地址。 如下图所示,

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

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

答案 5 :(得分:0)

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

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

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

现在我们通过char *c = (char *)&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十进制。