C语言 数组和衰变指针的区别



在较低的层次上,下面是我在观察一维数组和引用相当于一维数组的指针时发现的差异列表。下面是编译器资源管理器,显示了我发现的差异,以及下面的代码:

#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);
}

还有其他我可能遗漏的差异吗?

我对这个问题的目的感到困惑。这就像问"int和struct之间有什么区别"——似乎完全是随意的,答案也没什么用。数组不是指针。这是所有。衰减并没有以某种方式将它们不可分割地联系起来,它只是一种方便:它只是让你使用数组的名称来代替指向数组第一个元素的指针,在许多情况下,指针是合适的。

显然,这样一个"衰减"的指针不是左值,所以你不能修改它:它是幻像。你的问题似乎更多的是关于"左值和右值是如何不同的,我怎么知道"-你已经清楚地回答了这个问题。尝试array += 1并看到它失败等同于尝试5 += 1。你不能期待其他任何东西,那就说不通了。在C语言中,数组不是左值,它是一种私生子,因为一旦你把它放在作用域中,你就不能用它了:只有数组本身的sizeof&。对于其他所有内容,它衰变成一个右值指针。注意:不是指向右值的指针,因为你不能有一个。指针本身是一个右值。如。&(foo[1])首先对数组进行衰减,因为它没有其他用途,然后像foo是指针一样进行指针运算。右值是不可变的,并且没有存储空间。你不能拿走他们的地址和其他东西。

再次说明:数组不是右值。数组是一个具有存储空间的值,但实际上可以对其进行操作的语法很少。当您试图像使用指针一样使用数组时,C会帮助解决这个问题,并使其衰减,但该指针不存在作为可以更改的左值。它只是一个动态合成的右值,就像整数字面值动态合成右值一样:您可以使用它们,但只能在可使用右值的范围内使用。

左值和右值之间的根本区别是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));
}

C的语义规定foobar是相同的(除了它们的名字):两者只是具有相同含义的不同语法。更糟糕的是,在某些情况下,第一种语法可能有一些自文档化的用途,尽管它在其他方面完全是愚蠢的。

最新更新