【问题标题】:How different is array from a pointer in C? [duplicate]数组与 C 中的指针有何不同? [复制]
【发布时间】:2016-10-18 12:20:55
【问题描述】:

在下面的程序中,

#include<stdio.h>
int main(){
  int a = 1025;
  int *p;
  p = &a;

  char *p0;
  p0 = (char *)p;


  //print("\n%d %d", *p0, *(p0+1));
  printf("\n%d and %d", *p0, p0[1]);

}

输出:

1 和 4


char & int是C中的算术类型,要理解类型转换后的输出,我需要理解1025的二进制表示,即00000000 00000000 00000100 00000001Intelarch 的小字节序将占用第一个字节 00000001

问题:

对于上述用java编写的程序,不能使用数组表示法访问int的每个字节。

在上面的 C 程序中,数组表示法可以交替用于访问int 的每个字节。

根据这个程序,数组与 C 中的指针有什么不同?

【问题讨论】:

  • 数组是元素的连续序列。
  • @JoachimPileborg 与 Java 中的一维数组相同
  • 您的程序中没有数组。 p[x] 只是 *(p + x) 的简写。
  • @overexchange 您链接的评论描述了算术值的转换,而不是指针。
  • "我需要了解1025的二进制表示" 二进制表示也可以是00000001 00000100 00000000 00000000。这就是你所拥有的,因为你得到了输出1 4。这是因为 CPU 字节序。

标签: c arrays


【解决方案1】:

array - 实际存在于内存中的一系列连续元素。它有一个地址,通常认为是数组第一个元素的地址。

指针 - 包含地址的变量。指针中包含的地址可能指向也可能不指向实际内存。

这样想 - 你的家有一个地址。它存在于某处,您可以在其中放入东西——它是一个数组。您可以将任何地址放在信封上并尝试邮寄。由于多种原因,它可能会也可能不会正确交付 - 信封上写的街道地址是一个指针。而且你不能在那篇文章中存储任何东西。

【讨论】:

    【解决方案2】:

    对于上面用java编写的程序,不能使用数组表示法来访问int的每个字节。

    你是对的

    在上面的 C 程序中,数组表示法可以交替用于访问 int 的每个字节。

    是的,您可以声明一个char 指针,将其指向int 的第一个字节,然后使用数组表示法访问int 变量的每个字节。

    声明数组的方式相同

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

    并将其用作指针

    char *prt;
    prt = arr;
    

    相当于

    ptr = & ( arr[0] ); // The address of the first element of arr
    

    根据这个程序,数组与 C 中的指针有何不同?

    为了简化(根据这个程序),数组是指向数组第一个元素的指针。

    p0 是一个指向数组的指针,数组的元素是p0[0], p0[1],...

    澄清更多:

    您可以将变量声明为指针或数组。

    在您的代码中,您没有声明数组。

    但是当您使用 p0[1] 时,您将 p0 视为一个数组。

    最后:

    我引用...

    了解类型转换后的输出

    https://stackoverflow.com/a/6752688/1579327

    将较大的类型转换为较小的类型的结果是未定义的(取决于实现)如果较小的类型是有符号的并且较大类型的值不适合较小的类型。

    【讨论】:

    • 拒绝是什么意思?可以分享一下java代码吗?顺便说一句,上面的查询中没有数组
    • 我的意思是“数组表示法不能用于访问 int 的每个字节”(编辑答案)
    • 是什么意思?阅读Michael Walz 所说的内容。
    • Yes 表示您所说的是真实的。我试图澄清更多。查看我的最后一次编辑。
    【解决方案3】:

    严格回答标题中的问题——数组不是指针:


    • int arr[10]:

      • 使用的内存量为sizeof(int)*10字节

      • arr&amp;arr 的值必然相同

      • arr 指向一个有效的内存地址,但不能设置为指向任何其他内存地址(即,它用作常量“标签”)


    • int* ptr = malloc(sizeof(int)*10):

      • 使用的内存量为sizeof(int*) + sizeof(int)*10字节

      • ptr&amp;ptr 的值不一定相同(实际上它们大多不同)

      • ptr 可以设置为指向有效和无效的内存地址(即,您可以在运行时随意更改它)

    【讨论】:

    • 通过“值”,我的意思是,如果您将它们转换为 void*size_t
    【解决方案4】:

    虽然它们不是同一个东西,但在C中数组和指针之间有着密切的关系。数组下标操作a[i]是根据指针算法定义的:

    a[i] == *(a + i)
    

    也就是说,从该地址获取数组基本类型的地址 a,偏移i 元素,然后取消引用结果。例如,如果aint 的数组,则表达式a + 1 的计算结果为存储在a 之后的下一个整数对象 的地址,该地址可能是2、4 或 8 个字节。

    数组不是指针;但是,除非它是 sizeof 或一元 &amp; 运算符的操作数,或者是用于在声明中初始化另一个数组的 字符串文字表达式 类型为“N-element array of T”将被转换(“decay”)为类型为“pointer to T”的表达式,表达式的值将是第一个元素的地址大批。

    所以,给定代码

    int a[10];
    a[2] = 2;
    

    a[2] = 2 语句中,表达式 a 不是sizeof 或一元&amp; 运算符的操作数,因此它是从@ 类型转换(“衰减”)的987654338@ 到int *,它的计算结果是a 的第一个元素的地址。然后,我们从该地址偏移 2 个 int 类型的元素,并将值 2 分配给该位置。请注意,此转换适用于 表达式 a,而不是它所引用的数组对象。

    那么这一切与你的代码有什么关系呢?

    在 C 中,非位域对象由一个或多个字节的连续序列组成。 char 类型的对象根据定义占用 1 个字节,因此任何多字节类型(intlongfloatdouble 等)的对象都可以视为char 的数组(或unsigned char)。

    一张图片可能会有所帮助 - 我获取了您的代码并使用了我编写的一个小实用程序来转储内存中每个对象的内容:

           Item        Address   00   01   02   03
           ----        -------   --   --   --   --
              a 0x7ffffa8a29cc   01   04   00   00    ....
    
              p 0x7ffffa8a29c0   cc   29   8a   fa    .)..
                0x7ffffa8a29c4   ff   7f   00   00    ....
    
             p0 0x7ffffa8a29b8   cc   29   8a   fa    .)..
                0x7ffffa8a29bc   ff   7f   00   00    ....
    

    1025 的二进制表示是0x0401。如您所见,对象a 有4 个字节宽,包含字节序列{0x01, 0x04, 0x00, 0x00}。这是在 x86 系统上,它是 little-endian,因此 least 有效字节在序列中排在第一位。

    pp0 都存储a 的地址。我在一个 64 位系统上,所以指针值是 8 个字节宽。

    *p0 计算为a 中第一个字节的值,在本例中为0x01p0[1] 等价于*(p0 + 1),并计算为p0 之后的第二个字符值的值,在本例中为0x04

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多