指针的分配?

时间:2014-08-30 15:53:23

标签: c pointers

int arr[]={1,2,3};
char* p;
p=arr;

这是程序的一个片段,它可以工作。

任何人都可以解释如何将int变量地址分配给char指针?

5 个答案:

答案 0 :(得分:0)

这样可行,因为char指针的大小与int指针的大小相同。但是,当应用某些指针算法时,您将无法获得有效结果。这意味着如果您想访问数组的第二个元素 - p[1],那么只有一个字节会添加到p地址。如果p的类型为int,则会添加4个字节(因为这是int的大小),第二个元素将被正确访问。

#include <stdio.h>

int main(void)
{
    int arr[] = {1,2,3};
    char* p;
    p = arr;
    printf("%d\n", p[0]);
    printf("%d\n", p[1]);

    int* pp = arr;
    printf("%d\n", pp[0]);
    printf("%d\n", pp[1]);

    return 0;
}

输出:

1
0  - as you can see that is not the value from arr[1]
1
2

由于我的英特尔处理器是小端,内存中的arr[0]存储如下:

01 00 00 00
^
p[0]
等于*(p + 1)的

p[1]将向p指针添加一个字节,因为p的大小为char。

01 00 00 00
   ^
   p[1]

printf("%d\n, p[1]);给出0.请注意,如果您使用的是大端机器,则打印p[0]的结果会有所不同(例如0)。

但是,您的编译器应该警告您正在做什么。

  

警告:从不兼容的指针类型分配[启用   默认]

答案 1 :(得分:0)

将char点指定给整数数组的地址时,可能会发生很多事情,具体取决于整数的大小。下面是在32位Windows OS下编译的数组的内存位置。您可能还想将其转换为p =(char *)arr。

01 00 00 00 02 00 00 00 03 00 00 00

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

答案 2 :(得分:0)

您的代码无效。在C语言中,如果没有显式转换,则int *指针不能分配给char *指针。 C语言禁止分配不兼容的指针类型。 (即它禁止在这些类型之间进行隐式转换)。您的编译器可能会发出一条诊断消息,告诉您完全相同的事情。您的代码包含约束违规 - 它不是有效的C代码。

很久以前,这种转换在C语言的古老非标准化版本中是合法的。出于这个原因,默认情况下,C编译器对于这种无效代码是相当宽容的。他们发出诊断消息作为&#34;警告&#34;,但继续编译代码,这误导了一些人相信代码是有效的。

许多C编译器为您提供了其他选项,使其在检测此类错误时更加明确。例如,在GCC中,您必须指定-pedantic-errors开关以使用&#34;错误&#34;报告此约束违规。消息。

如果编译器接受了代码,其行为与编写p = (char *) arr时的行为相同,即它使p指向arr数组的开头。这就是它的全部内容。如果您尝试通过指针p访问数组数据,则只需重新解释 arr占用的内存作为char的序列。您将看到的将取决于许多依赖于实现的因素。 (即你没有通用的答案&#34;为什么我看到0?为什么我在那里看到2?&#34;问题。)例如,重新解释的数据会看起来 big-endian little-endian 平台之间存在差异。

答案 3 :(得分:0)

您的编译器应该警告您这是不兼容的。

分配后,让我们说arr的地址是1000,arr [0]将在地址1000,arr [1]将在地址1004,arr [2]将在地址1008

现在p指向arr,所以它指向地址1000,所以每次你想访问arr [1]你都必须使用*(p + 4),因为char只有1个字节(同样要小心如果它是一个小端或大端机)

虽然它不兼容,但你可以使用它,但是当你使用这个任务时你应该小心。

gdb输出。

(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'

答案 4 :(得分:0)

是的,您可以将任何类型的变量地址分配给任何类型的指针(但是您可能会收到有关分配不兼容指针类型的警告)。这是因为任何类型的sizeof指针都是相同的。

例如: -

int main(void)
{
    char *c;
    int *i;
    float *f;
    printf("%d %d %d",sizeof(c),sizeof(i),sizeof(f)); //  Output: 4 4 4
}

这样的副作用:

考虑以下示例:

int main(void)
{
     int i1=127;
     int i2=128;

     char *c1=&i1;
     char *c2=&i2; 

     printf("%d %d",*c1,*c2);  //Output : 127 -128
}

为了理解这个输出,你需要考虑变量的二进制值。

让我们从i1开始: - i1的二进制值是

00000000 00000000 00000000 01111111

并通过将此内存的地址分配给char指针使char指针c1指向第一个字节(Little Endian方法)。

现在i2的二进制值是

00000000 00000000 00000000 10000000

这里再次c2指向第一个字节,但为什么输出是-128? 因为第一个字节是10000000,符号位是1,这意味着数字是负数 现在执行2的补码

的反向操作
10000000 ---> 01111111(minus one) --->10000000(one's complement)