为什么可以直接分配数组?

时间:2017-11-24 07:21:40

标签: c arrays variable-assignment function-parameter

请考虑以下代码段:

void foo(int a[], int b[]){
    static_assert(sizeof(a) == sizeof(int*));
    static_assert(sizeof(b) == sizeof(int*));
    b = a;
    printf("%d", b[1]);
    assert(a == b); // This also works!
}

int a[3] = {[1] = 2}, b[1];
foo(a, b);

输出(无编译错误):

2

我无法理解b = a有效的原因。即使数组可能会衰减为指针,也不应该衰减为常量指针(T * const)?

3 个答案:

答案 0 :(得分:10)

他们不能。

无法分配数组。 foo函数中没有数组。函数参数列表中的语法int a[]表示声明a具有类型“指向int的指针”。行为与代码void foo(int *a, int *b)完全相同。 (C11 6.7.6.3/7)

将一个指针指向另一个指针是有效的。结果是两个指针都指向同一个位置。

  

即使数组可能衰减到指针,它们是否应该衰减为常量指针(T * const)?

由数组“衰减”产生的指针是一个右值。 const限定符仅对左值(C11 6.7.3 / 4)有意义。 (术语“衰变”是指参数的转换,而不是参数的调整)。

答案 1 :(得分:8)

引用C11,章节§6.7.6.3,函数声明符(包括原型)

  

参数声明为''类型''的数组应调整为''限定指针   输入'',其中类型限定符(如果有)是在[]内指定的类型限定符。   数组类型推导。 [...]

因此,ab实际上是指针,而不是数组。

没有任何数组类型的任务分配,因此代码没有问题。

答案 2 :(得分:4)

是的,将[]声明的数组参数调整为const限定指针是有意义的。但是,当建立此行为时,const不存在。

当开发C语言时,通过传递其地址,或者更具体地说,传递第一个元素的地址来传递数组是有意义的。你当然不想复制整个数组来传递它。传递地址是使被调用函数知道数组的简单方法。 (我们在C ++中看到的引用类型的语义尚未发明。)为了使程序员能够轻松编写代码而不是foo(ArrayA, ArrayB),可以编写foo(&Array[0], &ArrayB[0])而不是void foo(int ArrayA[], int ArrayB[]),将数组转换为发明了指向其第一个元素的指针。 (由Dennis M. Ritchie根据M.M.The Development of the C Language,这个参数符号已经存在于C的前身语言B中。)

没关系,你隐藏了转换。但这只是调用函数的地方。在被调用的例程中,正在考虑传递数组的程序员将编写int *ArrayA。但由于我们实际上是传递指针而不是数组,因此需要将它们更改为int *ArrayBint ArrayA[]。因此,创建了声明为数组的参数自动调整为指针的概念。

正如您所看到的,这使程序员能够为参数赋值,这会更改数组的表观基址。将声明为int * const ArrayA的参数调整为ArrayA是有意义的,因此无法更改参数const的值。然后它会更像一个数组,其地址也无法更改,所以这更符合假装传递数组的目标,即使我们传递地址。

但是,当时const不存在,所以这是不可能的,没有人想到当时发明class s3(TemplateView): template_name = 'project/s3.html' def get_context_data(self, **kwargs): context = super(s3, self).get_context_data(**kwargs) aws = boto3.resource('s3') buckets = aws.buckets.all() for bucket in buckets: totalSize = 0 bucketName = bucket.name createdAt = bucket.creation_date fileBuckets = boto3.resource('s3').Bucket(bucketName) for file in fileBuckets.objects.all(): totalSize += file.size context['buckets'] = buckets context['bucket'] = buckets context['createdAt'] = createdAt context['bucketName'] = bucketName context['totalSize'] = totalSize return context (或者至少做了足够的工作以使其被采用进入语言)。

现在世界上有大量的源代码可用于非const调整。现在更改C语言的规范会导致现有代码出现问题。