C 指针的分配?
这是一个程序的片段,它可以正常工作C 指针的分配?,c,pointers,C,Pointers,这是一个程序的片段,它可以正常工作 有人能解释一下如何将int变量地址分配给char指针吗 这是可行的,因为char指针的大小与int指针的大小相同。但是,当应用某些指针算法时,将不会得到有效的结果。这意味着,如果要访问数组的第二个元素-p[1],则只会向p地址添加一个字节。如果p的类型是int,那么将添加4个字节(因为这是int的大小),第二个元素将被正确访问 int arr[]={1,2,3}; char* p; p=arr; 由于我的英特尔处理器是little endian,内存中的ar
有人能解释一下如何将int变量地址分配给char指针吗 这是可行的,因为char指针的大小与int指针的大小相同。但是,当应用某些指针算法时,将不会得到有效的结果。这意味着,如果要访问数组的第二个元素-
p[1]
,则只会向p地址添加一个字节。如果p
的类型是int,那么将添加4个字节(因为这是int的大小),第二个元素将被正确访问
int arr[]={1,2,3};
char* p;
p=arr;
由于我的英特尔处理器是little endian,内存中的arr[0]
存储如下:
1
0 - as you can see that is not the value from arr[1]
1
2
p[1]
相当于*(p+1),将向p指针添加一个字节,因为p的大小是char
01 00 00 00
^
p[0]
和printf(“%d\n,p[1]);
给出0。请注意,如果您在big-endian机器上,打印p[0]
的结果将不同(例如0)
但是,编译器应该警告您正在执行的操作
警告:来自不兼容指针类型的分配[由启用]
默认值]
当您将字符点分配给整数数组的地址时,可能会发生许多事情,具体取决于整数的大小。下面是32位windows操作系统下编译时数组的内存位置。您可能还希望将其强制转换为p=(char*)arr 01 00 00 02 00 00 03 00 00 00 00 00
01 00 00 00
^
p[1]
您的代码无效。在C语言中,如果不进行显式转换,则无法将
int*
指针分配给char*
指针。C语言禁止分配不兼容的指针类型。(即,它禁止在此类类型之间进行隐式转换)。您的编译器可能发出了一条诊断消息,告诉您完全相同的事情。您的代码包含约束冲突-它不是有效的C代码
这种转换在很久以前是合法的,在C语言的古老的非标准化版本中。因此,默认情况下,C编译器对这类无效代码相当宽容。它们以“警告”的形式发出诊断消息,但继续编译代码,这会误导一些人相信代码是有效的
许多C编译器为您提供了额外的选项,使它们在检测此类错误时更加明确。例如,在GCC中,您必须指定-pedantic errors
开关,以使用“error”消息报告此约束冲突
如果编译器接受该代码,其行为与编写
p=(char*)arr
时相同,即它使p
指向arr
数组的开头。就这些。如果试图通过指针p
访问数组数据,只需将arr
占用的内存重新解释为char
s序列。您将看到的内容将取决于许多依赖于实现的因素。(也就是说,对于您的“为什么我在那里看到0
呢?为什么我在那里看到2
呢?”问题,没有通用的答案。)例如,在大端和小端平台之间,重新解释的数据看起来会有所不同。您的编译器应该警告您这是不兼容的
分配后,假设arr的地址为1000,arr[0]将位于地址1000,arr[1]将位于地址1004,arr[2]将位于地址1008
现在p指向arr,所以它指向地址1000,所以每次您想要访问arr[1]时,您都必须使用*(p+4),因为char仅为1字节(如果是小端或大端机器,也要小心)
虽然它不兼容,但您可以使用它,但使用此作业时应小心
gdb输出。
int arr[]={1,2,3};
// arr[0] = 1;
// arr[1] = 2;
// arr[2] = 3;
char* p;
p=(char*)arr;
// p[0] = 1
// p[1] = 0
// p[2] = 0
// p[3] = 0
// p[4] = 2
// p[5] = 0
// p[6] = 0
// p[7] = 0
// p[8] = 3
// p[9] = 0
// p[10] = 0
// p[11] = 0
是的,您可以将任何类型的变量的地址分配给任何类型的指针(但是您可能会收到关于分配不兼容指针类型的警告)。这是因为任何类型的指针的大小都是相同的 例如:-
(gdb) p *p
$8 = 1 '\001'
(gdb) p *(p+1)
$9 = 0 '\000'
(gdb) p *(p+2)
$10 = 0 '\000'
(gdb) p *(p+3)
$11 = 0 '\000'
(gdb) p *(p+4)
$12 = 2 '\002'
(gdb) p *(p+5)
$13 = 0 '\000'
(gdb) p *(p+6)
$14 = 0 '\000'
(gdb) p *(p+7)
$15 = 0 '\000'
(gdb) p *(p+8)
$16 = 3 '\003'
这种方法的副作用:
考虑以下示例:
int main(void)
{
char *c;
int *i;
float *f;
printf("%d %d %d",sizeof(c),sizeof(i),sizeof(f)); // Output: 4 4 4
}
为了理解这个输出,需要考虑变量的二进制值。
让我们从i1开始:-i1的二进制值为int main(void)
{
int i1=127;
int i2=128;
char *c1=&i1;
char *c2=&i2;
printf("%d %d",*c1,*c2); //Output : 127 -128
}
通过将这个内存的地址分配给char指针,char指针c1指向第一个字节(小端方法)
现在i2的二进制值是
00000000 00000000 00000000 01111111
这里c2再次指向第一个字节,但为什么输出是-128?
因为第一个字节是10000000,所以符号位是1,这意味着数字是负数
现在执行2的补码的反向运算
00000000 00000000 00000000 10000000
你查过p[1]了吗?它不应该是“2”printf(“%d”,*p);打印2p=(int*)(p+1);这会将*p打印为0。@user3465845:您使用的编译器是什么?@user3465845:虽然行为依赖于平台,但在任何情况下,
printf(“%d”,*p)
都无法实际打印2
。你在编什么东西。printf(“%d”,*p);以及为什么这会发生在你身上,请提供一个最少的代码示例。对我来说,它像对其他人一样打印1。@macfij:只有在小型endian机器(例如英特尔机器)上,它才会打印1
。如果您使用的是big-endian机器(例如SPARC或Power),它会打印0
@JonathanLeffler您是对的。我所说的“其他人”是指这条线索中的人。我假设他们也有基于英特尔的机器;印刷品2。为什么?我的编译器在printf(“%d”,*p)上打印了1。我不明白为什么要打印2.对不起,我的错。p=(char*)((int*)(p));printf(“%d,”,*p);这张照片2@user3465845:没有。在上述代码的上下文中,这没有任何机会“打印2”。如果您看到2,这意味着您对代码进行了一些更改,但没有向我们显示这些更改。这里没有人有心灵感应。p=(char*)((int*)(p))
在这种情况下不起作用。它什么也不做。
00000000 00000000 00000000 10000000
10000000 ---> 01111111(minus one) --->10000000(one's complement)