2017-01-02 77 views
0
#include<stdio.h> 

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

是不是p =(int *)(p + 1);指向数组的下一个元素? (即3?)所以输出应该是2,3。但输出是2,0。为什么?为什么输出2,0而不是2,3?

+3

不,因为'p'是一个char *指针。给char *指针加1不同于给int *指针加1。 –

+0

Little Endian机器。 –

+1

这是我猜想的endianness .....你增加了p,它会移动到下一个字节...然后它是0,因为在你的MSBare首先存储... – coderredoc

回答

3

您正在增加char指针p到下一char存储器位置 - 这就是0填充字节的数目2,其中,作为一个int需要4个存储器位置(其它3以零填充)中的一个。

总之,只需更换char *p;int *p;并摆脱所有铸件p = (char*)((int*)(p)); - 您的程序应该只是工作。 (为了让工作保持不-有用铸造,改变p = (int*)(p+1);p = (char *) (((int *) p) + 1);,使增量发生在一个整数的指针,而不是一个字符指针)

在小端内存模型,比如在当前使用PC的int数字在内存中占用4个字节 - 第一个是最不重要的(因此,对于小于256(2^8)的数字,它们包含整数)。

你在记忆中,这字节序列:'02 00 00 00 03 00 00 00 04 00 00 00'

当您使用 “字符*” 指针,编译器知道字符的大小数据元素是1个字节。在增加它时,它只进入相邻的字节,即“0”。

在“printf”调用中,您访问“char * p”中的单字节数为0的内容,编译器在调用“printf”时填充该值,以使该函数仍然看到“0” - 但在其他编辑器和系统中,它可能会打印垃圾或段错误,因为printf的“%d”参数所预期的3个字节不会存在。

+1

3和4可以很容易地是7和8.只有暗示在这里。 – StoryTeller

+0

您对垃圾或分段错误的评论是错误的。在缺省参数提升规则下,单字节被计算并转换为'int',这些规则适用于具有省略号的函数的参数 - 例如'printf'。 –

2

这是因为p是数据类型指针的错误种类。

当您增加p时,它不会将其值增加1 * sizeof(int),它会将其增加1 * sizeof(char)

arr在字节级的内容,假设int是4个字节和little endian字节顺序:

2 0 0 0 3 0 0 0 4 0 0 0 

p是第一套,你有这样的:

2 0 0 0 3 0 0 0 4 0 0 0 
^------ p 

当您将p设置为(int*)(p + 1)时,您只会将p增加1。在此处演员阵容没有帮助。所以,你得到这样的:

2 0 0 0 3 0 0 0 4 0 0 0 
    ^------ p 

所以提领p读相应位置内存1个字节,所以你有0。

如果你想通过int的大小来增加p,你需要转换p本身,然后添加到它:

p = `(int*)(p) + 1` 

然后你会得到你所期望的结果。

1

这就是为什么指针的类型应该是相同的数据类型,因为它是指向用于Pointer Arithmatics

添加1到特定的数据类型的指针起见将添加的字节数到存储器中的数据的地址到一个指针当前所指,现在将指向到p +(X-字节)的地址和去引用它会给你的值在该地址

例如

声明的一个指针类型int像

int *p = new int[5]; 

数组中的每个元素(如果填充数组)将存储在内存中,存储器中的空间为4个字节(地址方面和32位系统)。 然后将1添加到像p = p+1这样的指针将会带您前往它前面4个字节地址处的数组中的下一个元素。 对于任何其他类型的指针,情况也是如此,只是区别在于它将跳转到地址空间中的那么多字节,就像数据类型指针本身一样。

现在你可以说指针只是指向内存,所以不论我们声明任何类型的指针都不应该有任何区别。是的,这是真的,但不建议任何时候,因为当你使用指针,指针算术非常肯定会在那里使用。为了确切地跳转内存地址,我们声明与指向的数据具有相同数据类型的指针

+0

** C **语言现在有**新** – Michi

相关问题