这是代码
#include <stdio.h>
int a[] = {1, 2, 3, 4, 5};
int main()
{
for (int i : a)
printf("%d\n", i);
return 0;
}
在我看来,对于(int i:a),只有当a是整数向量时才有效。但是在上面的代码中,a是一个整数数组,很像一个指向整数的指针。为什么这样做?
答案 0 :(得分:13)
数组不“非常像指针”。数组可以衰减为指针,但在非衰减的上下文中,它仍然是一个已知大小的数组。
答案 1 :(得分:3)
如其他答案所述,数组不是指针。它们在某些情况下会衰减成指针,这是正确的,但仅限于某些情况下。
int a[] = {1, 2, 3, 4, 5};
a
的类型为int [5]
,这是一个包含五个int
类型元素的数组。在这种情况下,一对空方括号告诉编译器推导出元素的数量,因此您的定义等同于int a[5] = {1, 2, 3, 4, 5};
。
如果您仍然不相信,这里有一段代码试图让编译器发出包含a
类型的错误消息:
template <typename T> struct Type;
int main()
{
int a[] = {1, 2, 3, 4, 5};
Type<decltype(a)> dummy;
}
g ++ 5.3发出
error: aggregate ‘Type<int [5]> dummy’ has incomplete type and cannot be defined
如您所见,decltype(a)为int [5]
。
cppreference.com包含range-based for loop的详细说明。 你的for循环相当于:
{
auto && __range = a;
for (auto __begin = a, __end = a + 5; __begin != __end; ++__begin)
{
int i = *__begin;
std::printf("%d\n", i);
}
}
总结一下:T [N]
是一种类型:N
类型为T
的元素的数组。 N
是编译时已知的整数常量,因此编译器知道数组的最后一个元素的位置,因此能够生成一个遍历所有元素的循环。
如果您想了解有关阵列衰减的更多信息,建议您阅读What is array decaying?。
答案 2 :(得分:1)
编译器知道有关该数组的所有知识
T arr[]
是一种不完整的类型,但它会变得更好并且“#34”功能完整&#34;右边的部分是一个列表,一个定义大小的列表,在编译时编译器已知,所以它是静态检查的,你有它,你知道大小,你甚至知道元素;你还需要什么?
顺便说一下,数组不是指针,为了更好地理解你可以从不同角度解决这个问题,例如你应该明白,当你将一个数组传递给一个函数时,你实际上是在解决一个无法解决的问题。在C和C ++中可以很好地解决,没有void foo( T arr [] )
,但是你被迫使用void foo ( T * arr )
,因为你无法在C / C ++中创建一个只有数组的真实接口。 / p>
答案 3 :(得分:0)
在我看来,对于(int i:a),仅当a是整数向量
时才有效
你错了。
在上面的代码中,a是一个整数数组,它非常像指向整数
的指针
你也错了。数组和指针是两个完全不同的东西。
为什么这样做?
因为那是什么范围。它遍历容器。数组是容器。
答案 4 :(得分:0)
因为它调用了std::begin()
和std::end()
,它专门用于C数组。这是来自glibc的<range_access.h>
:
template<class _Tp, size_t _Nm>
inline _Tp*
begin(_Tp (&__arr)[_Nm])
{ return __arr; }
template<class _Tp, size_t _Nm>
inline _Tp*
end(_Tp (&__arr)[_Nm])
{ return __arr + _Nm; }
答案 5 :(得分:0)
因为编译器遵循C ++标准。草案n4296明确表示基于范围的for语句对普通数组有效:
6.5.4基于范围的语句[stmt.ranged]
对于基于范围的表格形式
for ( for-range-declaration : expression ) statement
...
(1.1) - 如果_RangeT是一个数组类型....如果_RangeT是一个未知大小的数组或一个数组 不完整的类型,程序是不正确的;
int a[] = {1, 2, 3, 4, 5};
定义了一个包含5个整数的数组。