c中的数组名到底是什么?

c中的数组名到底是什么?,c,arrays,pointers,memory-address,C,Arrays,Pointers,Memory Address,我很难理解C中数组名称的类型和用法。这可能是一篇很长的文章,但请耐心听我说 我理解以下语句声明a为int[]类型,即整数数组 int a[30]; 而a也指向数组的第一个元素,像*(a+2)这样的东西是有效的。因此,使a看起来像指向整数的指针。但是实际上int[]和int*的类型是不同的;前者是数组类型,后者是指向整数的指针 int a[30]; 当传递给函数时,类型为int[]的变量也会转换为类型为int*的变量;正如在C中一样,数组是通过引用传递的(除了sizeof操作符) 这一点让我心

我很难理解C中数组名称的类型和用法。这可能是一篇很长的文章,但请耐心听我说

我理解以下语句声明
a
int[]
类型,即整数数组

int a[30];
a
也指向数组的第一个元素,像
*(a+2)
这样的东西是有效的。因此,使
a
看起来像指向整数的指针。但是实际上
int[]
int*
的类型是不同的;前者是数组类型,后者是指向整数的指针

int a[30];
当传递给函数时,类型为
int[]
的变量也会转换为类型为
int*
的变量;正如在
C
中一样,数组是通过引用传递的(除了
sizeof
操作符)

这一点让我心神不定。请查看以下代码:

int main()
{
    int (*p)[3];
    int a[3] = { 5, 4, 6 };

    p = &a;

    printf("a:%d\t&a:%d\n",a,&a);
    printf("%d",*(*p + 2));
}
输出:

a:2686720       &a:2686720
6
那么,上面的代码是如何工作的呢?我有两个问题:

  • a
    &a
    具有相同的值。为什么?
  • 什么是
    int(*p)[3]做什么?它声明了一个指向数组的指针,我知道这一点。但是,指向数组的指针与指向数组第一个元素的指针和数组的名称有何不同
  • 有人能澄清一下吗?我有很多困惑

    我知道我应该使用
    %p
    作为占位符,而不是使用
    %d
    来打印指针变量的值。因为使用整数占位符可能会打印截断的地址。但我只想让事情简单一些

  • a对应于指向数组第0个元素的指针。而&a的情况也是如此,它只给出了数组的起始地址
  • 作为指向数组a[]起始元素的-->指针,它不知道其他元素的位置。

    &用于存储数组a[]的一个-->地址位置,它存储第一个元素位置,但知道每个元素的位置

    类似地,其他元素的位置将是(a+2),(a+4)等等,直到阵列的末端

    因此,你得到了这样的结果

  • int(*p)[3]是指向数组的指针。如果它是int*p[3],它的意思就完全不同了。这意味着一个指针数组,与此上下文完全不同
  • 指向数组的指针将自动处理所有其他数组 数组中的元素。在本例中,您的为(p)

    然而,指向数组第一个元素的指针,即will 只知道数组的第一个元素。您必须手动 给出访问下一个元素的指针算术方向。请参见本节中的 case--我们可以通过在a上加2得到a的第二个元素,即。 a+2,第三个元素,将4添加到a,即a+4,依此类推当心 二的差,因为它是一个整数数组

  • a和&a有相同的值。如何
  • 它们的值相同,但类型不同。数组对象在元素之间(之前或之后)没有填充,因此数组的地址和数组的第一个元素的地址是相同的

    即:

    (void *) a == (void *) &a
    
  • 它到底做什么int(*p)[3];声明指向数组的指针,我知道这一点。但是,指向数组的指针与指向数组第一个元素和数组名称的指针有何不同
  • 这是两种不同的指针类型。例如,指针算法:

    a + 1   /* address of the second element of the array */
    &a + 1  /* address one past the last element of the array */
    
    编辑:由于大众的需求,我在下面添加了一些有关阵列转换的信息

    除了三个例外,在表达式中,数组类型为
    T
    的对象转换为指向数组第一个元素的指针类型为
    T
    的值。例外情况是,如果对象是
    sizeof
    &
    一元运算符的操作数,或者如果对象是初始化数组的字符串文字

    例如,本声明:

    printf("a:%d\t&a:%d\n", a, &a);
    
    实际上相当于:

    printf("a:%d\t&a:%d\n", &a[0], &a);
    
    另外请注意,
    d
    转换说明符只能用于打印有符号整数;要打印指针值,必须使用
    p
    说明符(参数必须是
    void*
    )。因此,要正确做事,请使用:

    printf("a:%p\t&a:%p\n", (void *) a, (void *) &a);
    
    分别为:

    printf("a:%p\t&a:%p\n", (void *) &a[0], (void *) &a);
    

    在回答问题1时,这只是C语言设计的一个方面,与大多数其他现代语言不同,C/C++允许直接操作内存中的地址,并内置了“理解”这些地址的工具。网上有很多文章比我在这个小空间里能更好地解释这一点。这里有一个,我相信还有很多其他的:

    来自6.3.2.1 p3

    除非它是sizeof运算符或一元数的操作数& 运算符,或是用于初始化数组的字符串文字 类型为“”的数组“”的表达式转换为 类型为“指向类型的指针”且指向初始值的表达式 数组对象的元素,并且不是左值。如果数组对象 已注册存储类,行为未定义

    其他答案已经解释了这个问题。我试图用一些图表来解释它。希望这会有所帮助


    当您声明数组时

    int a[3] = {5, 4, 6}  
    
    内存安排看起来像

    现在回答你的问题:

  • a
    &a
    具有相同的值。如何设置 正如您所知,
    a
    是数组类型,数组名
    a
    成为指向数组
    a
    的第一个元素(衰减后)的指针,即它指向地址
    0x100
    。请注意,
    0x100
    也是内存块的起始地址(数组
    a
    )。你应该知道