2

我已经使用指针进行了类型转换,intchar没有使用指针,所以我发布了这个问题。

#include <stdio.h>
int main() {
    int a[4] = { 1, 2, 6, 4 };
    char *p;
    p = (char *)a;   // what does this statement mean?
    printf("%d\n",*p);
    p = p + 1;        
    printf("%d",*p);  // after incrementing it gives 0 why?
}

第一次调用printf给出数组的第一个元素。在p=p+1它给出之后0。为什么?

4

6 回答 6

5

让我们想象一个相当典型的平台,其中一个字节为 8 位,内存使用 little-endian 字节顺序排列,anint表示内存中的 4 个字节。在这个平台上,值的1布局如下:

00000001 00000000 00000000 00000000
^
the first element of 'a'

p被声明为指向char(not int) 的指针,并被初始化为指向数组的第一个元素a。这个平台上的 Achar代表一个字节。int上面解释为 a的值char如下所示:

00000001 -------- -------- --------
|      |
 ------
 char is only 8 bits wide

因此,无论我们读取一个字节还是四个字节,即,无论我们读取*p还是a[0],值都是1。但是,当您增加p指向 的指针时char,它现在指向内存中的下一个字符,即下一个字节:

00000001 00000000 00000000 00000000
00000001 00000000 -------- --------
^        ^        ^        ^
p       p+1      p+2      p+3       ...

a[1]指向下一个int( 2),p[1]指向下一个char,即0.


在旁注中,您实际上偶然发现了一种方法来确定给定处理器是使用小端还是大端字节顺序。如果系统是大端(最高有效字节在前),那么您的第一个printf将打印 0。这是因为内存布局会发生变化:

0000000 00000000 00000000 00000001
^
the first element of 'a'

0000000 -------- -------- --------
^
p

如果您有多个以 big-endian 顺序排列的代表值 1 的字节,并且您只读取第一个字节,则可以使用它的值(10)来测试机器的字节序:

int n = 1;
if(*(char*)&n == 1)
    // little endian
else
    // big endian
于 2012-08-05T07:27:32.717 回答
2

确切地说,firstprintf没有给出数组的第一个元素,它给出了第一个元素的前8 位,恰好等于第一个元素的数值。第二个 printf 给出了第一个元素的下 8 位,在这种情况下为 0。

1 = 00000000 00000000 00000000 00000001(32 位)

于 2012-08-05T07:09:08.330 回答
2

你有一个由四个整数组成的数组。您尝试将它们作为字符的“数组”来访问。这就是铸造的意思。

至于第二个printf打印零,请记住整数是四个字节,而字符只有一个。因此增加指针pp指向第一个整数的第二个字节,即零。如果你有一个更大的数字(即超过 255),那么第二个字节也会有一个值。但请注意,这仅适用于小端的 Intel 类型机器,在大端机器上都printf将打印零。

于 2012-08-05T07:10:43.070 回答
1
int a[4] = { 1, 2, 6, 4 };

将 a 声明为数组。a此时存储数组第一个元素的地址。

char *p;

将p 声明pointercharacter

p = (char *)a;

现在因为p&a两家商店的地址。因此,存储在a(address数组的第一个元素的) 的地址被分配给p。类型转换是按照p声明的那样完成的char *

它的作用是,假设存储的地址a是 100并假设它int占用 2 个字节并char在内存中占用 1 个字节

a+1 would return a+size of int(2) = 102

p+1 would return p+size of char(1) = 101 

这将把输出解释为

A. 存储的两个字节a包含数组的第一个元素。

B.一个字节存储在p是整数的第一个字节的字符表示1,即0

希望这可以帮助。

于 2012-08-05T07:16:03.087 回答
0

如果您使用类似英特尔的处理器,则堆栈上的字节将使用小端格式存储。此外,可能 int 类型(在您的计算机上)的大小为 4 个字节,而 char 的长度为 1 个字节(您可以使用 c 运算符“sizeof”验证这一点),因此整数数组的第一个元素是:

0x04 0x00 0x00 0x00

出于这个原因,当您使用 char 指针查看整数数组的值时,您每次向前推进一个字节(而不是 4 个字节),您已经获得了明显的结果。

我希望这有帮助!

于 2012-08-05T07:19:53.587 回答
0

a 是指向内存数组的指针。该内存可能以小端二进制补码格式排列为 16 字节的连续块。

当你转换它时,你基本上只是说“好吧,我知道这是一个指向整数数组的指针,但现在我们要将数据重新解释为一个字符数组”。char 通常是一个字节。因此,当您向指针添加 1 时,您增加了指针指向的位置。因为它是一个char数组,所以它在数组中向下移动了一个字节,它位于int的中间,包含0。

澄清一下,根据我对您计算机架构的假设

小端号码(最低显著字节至上):
= 1以二进制小数00000010000000000000000000000000 = 2用二进制小数00000110000000000000000000000000 = 6十进制00000100000000000000000000000000 00000001000000000000000000000000二进制以十进制二进制= 4

您的整数数组如下所示:

00000001000000000000000000000000000000010000000000000000000000000000001100000000000000000000000000000001000000000000000000000000

变量“a”指向第一个整数,它是 32 位(即,“*a”是00000001000000000000000000000000)。如果将变量“a”加一,则指针递增,因此 *(a+1) 指向第二个 int 00000010000000000000000000000000)。

现在,您将变量“a”转换为“char*”指针。所以,现在,变量“p”指向同一个地方,但是因为它是一个字符指针,指向第一个字符,它是 8 位(即,“*p”是00000001数组的第一个字节)。

最后,当你增加“p”时,你增加了指针。因为“p”是一个指向字符的指针,它前进了一个字节,所以“*(p+1)”是00000000

于 2012-08-05T07:23:02.167 回答