2011-12-31 99 views
2

当运行此代码:指针在C,整数指针字符指针

int arr[3] = {2,3,4}; 
char *p; 
p = (char*)arr; 
printf("%d", *p); 
p = p+1; 
printf("%d", *p); 

输出是2和0。第二个结果是稍微混乱。有人可以解释为什么发生这种情况?

+3

这是功课吗?如果是这样 - 相应地标记它。 – littleadv 2011-12-31 11:08:28

+3

当你*运行这段代码时发生了什么?推理:在发布问题之前,向我们展示您尝试过的内容以及结果是个好主意。 – 2011-12-31 11:11:10

+0

输出是2和0.第二个结果有点混乱。因此,这个问题。我是一位心脏外科医生,他正在努力帮助我的儿子完成作业。不幸的是,上帝并没有让我们所有人都成为C专家。 – user1124236 2011-12-31 11:12:57

回答

9

让我们打破这:

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

创建的3个整数的数组。假设你的系统是32位小尾数,这是它的外观在内存:

02 00 00 00 03 00 00 00 04 00 00 00 

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

p现在指向arr但它是一个指针char*。换句话说,p指向02

printf("%d", *p); 

您打印为intp引用的位置。所以,当你提领p(写*p)您正在访问的char(因为p是类型char*的)由p引用。这是02

p = p+1; 

p现在指向0002后,因为pchar*。所以当你加1时,它会在内存中移动1 * sizeof(char) = 1 * 1 = 1字节。

printf("%d", *p); 

您打印为intp引用的位置。因此,当您使用取消引用p(通过书写*p)您正在访问p引用的char(因为p的类型为char*)。这是00

如果你想打印3而不是0你有你的指针类型更改为int*而不是char*,通过在内存1 * sizeof(int) = 1 * 4 = 4字节使指针移动。

+0

非常感谢!!! :-) – user1124236 2011-12-31 11:28:05

+3

我还要强调,当读取'int'类型的值时,就好像它们是'char是合法的,确切的结果取决于实施。在别处编译时可能会得到另一个结果。 @Cicada必须对平台做出假设才能提供答案。 – Kos 2011-12-31 11:30:43

+0

假设int是32位,如果平台是32位或64位(甚至16位),则无关紧要。在一个翻转的笔记上,对endianness的思考对我来说发生得非常晚,我曾经假设只存在小端类型。来自6502,z80和8088,令人惊讶的是这些数字可以用不同的方式表示。 – bestsss 2011-12-31 17:20:19

4

你得到的结果将取决于你的实现和它的字节顺序的大小int

假设32位整型,8位字符和豆蔻端环境(比如86),arr会是这样的记忆:

<arr[0]> <arr[1]> <arr[2]> 
02 00 00 00 03 00 00 00 04 00 00 00 
^^  ^
p p+1 ... p+4 

如果你把一个字符指针到内存的开始,打印出第一个元素,应输出2。如果增加该指针,则会输出0。您需要将其增加几次以“看”3.

请注意,在具有相同类型大小的大端环境中,您的程序将输出两个零,因为布局可能是:

<arr[0]> <arr[1]> <arr[2]> 
00 00 00 02 00 00 00 03 00 00 00 04 
^^  ^
p p+1 ... p+4 
1

这里是一个贴,可以让你了解这个问题更好:http://codepad.org/ClrrwjKY

正如你所看到的,连续整数的值出现三个零分开。这是因为一个整数是4个字节长,而一个char只有1个字节长。因此,当int数组转换为char时,可以逐字节(或char by char)而不是四个字节(int by int)迭代它。

2

这是因为所谓的endianness

当你创建了int arr[3] = {2, 3, 4};它就会在内存中创建一个数组如下

Big endian: 
    0 1 2  3  4 5 6  7  8 9 10  11 
    +---+---+---+--------+---+---+---+--------+---+---+---+--------+ 
    | | | | ..0010 | | | | ..0011 | | | | ..0100 | 
    +---+---+---+--------+---+---+---+--------+---+---+---+--------+ 

    <--  2  --><--  3  --><--  4  --> 

Little endian: 
     0  1 2 3 4 5 6  7  8  9 10 11 
    +--------+---+---+---+---------+---+---+---+--------+---+---+---+ 
    | ..0010 | | | | ..0011 | | | | ..0100 | | | | 
    +--------+---+---+---+---------+---+---+---+--------+---+---+---+ 

    <--  2  --><--  3  --><--  4  --> 

要了解更多,你需要修改你的程序如下:

int main(void) 
{ 

    int arr[3] = {2, 3, 4}; 
    char *p = (char*) arr; 
    int i; 
    int size = (int)sizeof(arr); 

    for (i=0; i<size ; i++) { 
     printf("%d", *p); 
     p++; 
    } 

    return 0; 
} 

而且,检查您硬件的字节顺序,您可以使用以下功能。仅由1 作为阵列

void endian(void) 
{ 
     int i = 1; 

     if (*(char *) &i == 1) 
       printf("Little endian \n"); 
     else 
       printf("Big endian \n"); 

     return; 
} 
0

这里为“p”为一个字符指针.. P + 1倍的增量p的电流值是整数,以便通过一个访问数组一个的每个值,就必须通过2. 递增字符数组如果整数数组的地址因此1000 ,

arr[0] is at 1000 
    arr[1] is at 1002 
    arr[2] is at 1004 

和改编的值是ARR [0]的地址; 所以最初

p=arr=1000 

当p递增,p是1001而ARR [1]是1002

..所以为了访问所有的值你就必须增加p的值的两倍每次..