英文:
Arrow operator for array length? No output when printed, How?
问题
我有这段代码来迭代一个数组,而不是使用sizeof(array)/sizeof(*array)
,我使用了一个箭头操作符(我不太明白它是如何工作的)。
我不明白为什么当我打印array->length()
时,输出为空白,并且如何使for循环能够按照i < array->length()
的设置条件正常工作和终止。
#include <iostream>
using namespace std;
int main() {
string cars[] = {"Corvette", "Ford", "Mustang"};
cars[1] = "Camaro";
for (int i = 0; i < cars->length(); i++)
{
cout << cars[i] << '\n';
}
cout << cars->length();
return 0;
}
英文:
I have this code to iterate over an array, instead of using sizeof(array)/sizeof(*array)
I used an arrow operator (I don't understand really well how it works).
I don't understand why when I print out array->length()
it is just a blank output, and how can the for loop work and terminate properly with the set condition of i < array->length()
.
#include <iostream>
using namespace std;
int main() {
string cars[] = {"Corvette", "Ford", "Mustang"};
cars[1] = "Camaro", "Ford";
for (int i = 0; i < cars->length(); i++)
{
cout << cars[i] << '\n';
}
cout << cars->length();
return 0;
}
答案1
得分: 5
在 cars->length()
中,数组 std::string cars[3]
会衰减为指向第一个元素的指针。在该指针上使用 ->
运算符将其解引用,然后在第一个元素上调用 length()
将返回该元素的长度(对于 "Corvette" 来说是 8) - 而不是数组的大小。
由于您的循环等效于:
for (int i = 0; i < 8; i++)
并且在循环内部对 cars[i]
进行了解引用,这将访问数组越界。该数组仅有 3 个元素。这会导致_未定义行为_,您的程序可能会做任何事情 - 或什么都不做,或者崩溃。
该程序中的另一个问题是使用逗号运算符的方式:
cars[1] = "Camaro", "Ford";
这会将 "Camaro"
赋给 cars[1]
,但完整表达式的结果是 "Ford"
。示例:
auto x = (cars[1] = "Camaro", "Ford");
x
现在是 "Ford"
,而 cars[1]
是 "Camaro"
。
英文:
In cars->length()
, the array std::string cars[3]
decays into a pointer to the first element. Using ->
on that pointer dereferences it, and calling length()
on that first element will return the length of the element (8 for "Corvette") - not the size of the array.
Since your loop is equivalent to:
for (int i = 0; i < 8; i++)
and you dereference cars[i]
inside the loop, you access the array out of bounds. The array only has 3 elements. This causes undefined behavior, and your program could do just about anything - or nothing, or crash.
Another problem in this program is this use of the comma operator:
cars[1] = "Camaro", "Ford";
This assigns "Camaro"
to cars[1]
, but the result of the full expression is "Ford"
. Example:
auto x = (cars[1] = "Camaro", "Ford");
x
is now "Ford"
while cars[1]
is "Camaro"
.
答案2
得分: 5
@TedLyngmo已经涵盖了这里的问题,以及为什么代码看起来可能不像它应该工作得那么好。
我将尝试介绍一些使代码工作的方法。首选的方法可能是使用基于范围的for循环,像这样:
for (auto const &car : cars)
{
cout << car << '\n';
}
另一种替代使用 sizeof(array)/sizeof(array[0])
的方法是像这样:
template <class T, size_t N>
size_t length(T (&array)[N]) {
return N;
}
有了这个,你可以更像你的原始代码一样操作:
for (int i=0; i<length(cars); i++) {
std::cout << cars[i] << '\n';
}
与 sizeof(array)/sizeof(array[0])
相比,这个的巨大优势在于,如果你有一个指针而不是一个实际的数组,sizeof
代码将产生不正确的结果,但这个简单地根本不会编译。但一般情况下,你不需要自己定义这个函数——标准库提供了一个 std::size
,它将为你完成这项工作,而无需记住通过引用传递数组的语法。
如果不提到更常见的方法,那就不完整了,更常见的方法是使用 std::vector
:
std::vector<std::string> cars = {"Corvette", "Ford", "Mustang"};
有了这个,你可以使用基于范围的for循环(我上面显示的第一个),或者 cars.size()
——现在会正确工作,因为 cars
是一个向量,它具有返回向量中元素数量的 size()
成员。
英文:
@TedLyngmo has already covered the problems here, and why the code doesn't work as well as it might appear to.
I'll try to cover some of the ways to make the code work. The preferred one is probably a range-based for loop, like this:
for (auto const &car : cars)
{
cout << car << '\n';
}
Another alternative to using sizeof(array)/sizeof(array[0])
is something like this:
template <class T, size_t N>
size_t length(T (&array)[N]) {
return N;
}
With this, you can do something more like your original code:
for (int i=0; i<length(cars); i++) {
std::cout << cars[i] << '\n';
}
The big advantage of this compared to sizeof(array)/sizeof(array[0])
is that if you have a pointer instead of an actual array, the sizeof
code will produce incorrect results, but this simply won't compile at all. You generally don't want to actually define this yourself though--the standard library provides an std::size
that will do the job for you, without having to remember the syntax for passing an array by reference.
I'd be remiss if I failed to mention that the generally preferred way would be to use an std::vector
though:
std::vector<std::string> cars = {"Corvette", "Ford", "Mustang"};
With this, you can use the range-based for loop (the first one I showed above) or a cars.length()
--which will now work correctly, because cars
is a vector, which has a length()
member that returns the number of elements in the vector.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论