Arrays 数组和衰减指针之间的差异

Arrays 数组和衰减指针之间的差异,arrays,c,pointers,assembly,Arrays,C,Pointers,Assembly,在较低的层次上,以下是我从一维数组中发现的差异列表,以及引用一维数组等价物的指针。下面是我发现的差异,以及下面的代码: #include <stdio.h> void function(void) { // 1. array has elements stored in contiguous-memory // whereas ptr is single 8-byte memory address value int nums[] = {1,2,3}

在较低的层次上,以下是我从一维数组中发现的差异列表,以及引用一维数组等价物的指针。下面是我发现的差异,以及下面的代码:

#include <stdio.h>

void function(void) {

    // 1. array has elements stored in contiguous-memory
    //    whereas ptr is single 8-byte memory address value
    int nums[] = {1,2,3};
    int* ptr_nums = &nums[0];

    // 2. compile-time sizeof is different
    //    ptr will always be 8 bytes, arr = unit_size * size
    printf("Sizeof: %zu", sizeof(nums));
    printf("Sizeof: %zu", sizeof(ptr_nums));

    // 3. assignment-to-ptr is valid, but not array
    //    by extension, arithmetic on ptr is allowed, not array
    // nums += 1;   // invalid
    ptr_nums = ptr_nums + 2;

    // 4. string-literal initialization is 'literal' rodata value
    //    for pointer, but contiguous chars in memory for array
    char name[] = "ABC"; // something like: mov $6513249, -24(%rbp)
    char* name_ptr = &name[0]; // will not create string literal
    char* name_ptr2 = "QCI"; // pointer to rodata string literal

    // 5. address-of operator
    // &array returns address of first element
    // &ptr return the address of pointer
    // (which *would not* be the same as the first element of the array if it pointed to that)
    printf("%zd", &nums);
    printf("%zd", &ptr_nums);

}
#包括
空函数(void){
//1.数组的元素存储在连续内存中
//而ptr是单8字节内存地址值
int nums[]={1,2,3};
int*ptr_nums=&nums[0];
//2.编译时大小不同
//ptr将始终为8字节,arr=单位大小*大小
printf(“Sizeof:%zu”,Sizeof(nums));
printf(“Sizeof:%zu”,Sizeof(ptr_nums));
//3.对ptr的赋值有效,但不是数组
//通过扩展,允许在ptr上进行算术运算,而不是数组
//nums+=1;//无效
ptr_nums=ptr_nums+2;
//4.字符串文字初始化为“文字”rodata值
//用于指针,但用于数组的内存中的连续字符
字符名[]=“ABC”;//类似于:mov$6513249,-24(%rbp)
char*name_ptr=&name[0];//将不会创建字符串文字
char*name_ptr2=“QCI”//指向rodata字符串文字的指针
//5.接线员地址
//数组返回第一个元素的地址(&A)
//&ptr返回指针的地址
//(如果数组的第一个元素指向该元素,则该元素*将*与该元素不*相同)
printf(“%zd”、&nums);
printf(“%zd”和ptr_nums);
}

还有什么我可能遗漏的差异吗?

我对这个问题的目的感到困惑。这就像问“int和struct之间的区别是什么”——似乎完全是武断的,答案也没什么用处。数组不是指针。就这些。衰变并没有以某种方式将它们不可分割地联系起来,这只是一种方便:它只允许您在许多适合指针的上下文中使用数组的名称来代替指向数组第一个元素的指针

显然,这样一个“衰减”指针不是左值,所以您不能修改它:它是幻影。你的问题似乎更多的是关于“左值和右值有什么不同,我该如何分辨”——你已经清楚地回答了这个问题。尝试
array+=1
并看到它失败相当于尝试
5+=1
。你不能指望别的,那是没有意义的。在C语言中,数组不是左值,它是一种杂种,因为一旦你把它放在范围内,你就不能用它太多:只使用数组本身的
sizeof
&
。对于其他所有内容,它衰减为右值指针。注意:不是指向右值的指针,因为您不能有一个。指针本身是一个右值。例如,
&(foo[1])
首先衰减数组,因为它没有其他用途,然后执行指针运算,就像
foo
是指针一样。rvalue是不可变的,并且没有存储空间,例如,不能获取它们的地址等

再次声明:数组不是右值。数组是一个带有存储的值,但实际上很少有语法可以对其进行操作。当您试图像使用指针一样使用数组时,C会帮助您消除并衰减该数组,但该指针不作为可以更改的左值存在。它只是一个动态合成的右值,就像整数文本动态合成右值一样:您可以使用它们,但仅限于可以使用右值的范围

右值和左值之间的这一根本区别是语言的基础,如果不牢牢把握这个概念,就很难理解C

为了进一步混淆,数组定义语法并不总是定义数组。例如:

#include <assert.h>

void foo(int notAnArray[10]) {
  int anArray[10];
  assert(sizeof(notAnArray) != sizeof(anArray));
}

void bar(int *notAnArray) {
  int anArray[10];
  assert(sizeof(notAnArray) != sizeof(anArray));
}
#包括
void foo(int notAnArray[10]){
国际原子能机构[10];
断言(sizeof(notAnArray)!=sizeof(anArray));
}
空栏(int*notAnArray){
国际原子能机构[10];
断言(sizeof(notAnArray)!=sizeof(anArray));
}

C的语义规定
foo
bar
是相同的(除了它们的名称之外):这两个词只是具有相同含义的不同语法。更糟糕的是,在某些情况下,第一个语法可能会有一些自我记录的用途,尽管它在其他方面完全是疯狂的。

我对这个问题的目的感到困惑。这就像问“int和struct之间的区别是什么”——似乎完全是武断的,答案也没什么用处。数组不是指针。就这些。衰变并没有以某种方式将它们不可分割地联系起来,这只是一种方便:它只允许您在许多适合指针的上下文中使用数组的名称来代替指向数组第一个元素的指针

显然,这样一个“衰减”指针不是左值,所以您不能修改它:它是幻影。你的问题似乎更多的是关于“左值和右值有什么不同,我该如何分辨”——你已经清楚地回答了这个问题。尝试
array+=1
并看到它失败相当于尝试
5+=1
。你不能指望别的,那是没有意义的。在C语言中,数组不是左值,它是一种杂种,因为一旦你把它放在范围内,你就不能用它太多:只使用数组本身的
sizeof
&
。对于其他所有内容,它衰减为右值指针。注意:不是指向右值的指针,因为您不能有一个。指针本身是一个右值。例如,
&(foo[1])
首先衰减数组,因为它没有其他用途,然后执行指针运算,就像
foo
是指针一样。rvalue是不可变的,并且没有存储空间,例如,不能获取它们的地址等

再次声明:数组不是右值。数组是一个带有存储的值,但实际上很少有语法可以对其进行操作。当您试图像使用指针一样使用数组,但该指针不存在时,C会帮助处理并衰减该数组