Правильный путь цикла через массивы С++
Недавно я нашел много примеров, большинство из которых касается С++ 98, так или иначе я создал свой простой массив и цикл (codepad):
#include <iostream>
using namespace std;
int main ()
{
string texts[] = {"Apple", "Banana", "Orange"};
for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
{
cout << "value of a: " << texts[a] << endl;
}
return 0;
}
Вывод:
value of a: Apple
value of a: Banana
value of a: Orange
Segmentation fault
Он работает нормально, за исключением ошибки сегментации в конце.
Мой вопрос: действительно ли этот массив/цикл прошел хорошо? Я использую С++ 11, поэтому хотел бы убедиться, что он соответствует стандартам и не может быть сделан лучше?
Ответы
Ответ 1
В C/С++ sizeof
. всегда задает количество байтов всего объекта, а массивы рассматриваются как один объект. Примечание: sizeof
указатель - к первому элементу массива или одному объекту - указывает размер указателя, а не указатель на объект (ы). В любом случае sizeof
не дает количество элементов в массиве (его длина). Чтобы получить длину, вам нужно разделить на размер каждого элемента. например.,
for( unsigned int a = 0; a < sizeof(texts)/sizeof(texts[0]); a = a + 1 )
Что касается этого пути С++ 11, лучший способ сделать это, вероятно,
for(const string &text : texts)
cout << "value of text: " << text << endl;
Это позволяет компилятору выяснить, сколько итераций вам нужно.
EDIT: как указывали другие, является предпочтительным в С++ 11 по сравнению с необработанными массивами; однако ни один из других ответов не объяснил, почему sizeof
терпит неудачу, так что я все еще думаю, что это лучший ответ.
Ответ 2
string texts[] = {"Apple", "Banana", "Orange"};
for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
{
cout << "value of a: " << texts[a] << endl;
}
Неа. Совершенно неправильный способ итерации через массив. sizeof(texts)
не равно количеству элементов в массиве!
Современные, С++ 11 способов:
- используйте
std::array
, если вам нужен массив, размер которого известен во время компиляции; или
- используйте
std::vector
, если его размер зависит от времени выполнения
Затем используйте range-for при итерации.
#include <iostream>
#include <array>
int main() {
std::array<std::string, 3> texts = {"Apple", "Banana", "Orange"};
// ^ An array of 3 elements with the type std::string
for(const auto& text : texts) { // Range-for!
std::cout << text << std::endl;
}
}
Живой пример
Вы можете спросить, как std::array
лучше, чем массив ol 'C? Ответ заключается в том, что он обладает дополнительной безопасностью и особенностями других стандартных библиотечных контейнеров, в основном похожих на std::vector
. Кроме того, ответ заключается в том, что он не имеет причуд распадающихся указателей и, таким образом, теряет информацию о типе, которая после того, как вы потеряете исходный тип массива, вы не можете использовать range-for или std::begin/end
на нем.
Ответ 3
sizeof
указывает размер элемента, а не количество элементов в нем. Более С++ 11 способ делать то, что вы делаете, будет следующим:
#include <array>
#include <string>
#include <iostream>
int main()
{
std::array<std::string, 3> texts { "Apple", "Banana", "Orange" };
for (auto& text : texts) {
std::cout << text << '\n';
}
return 0;
}
ideone demo: http://ideone.com/6xmSrn
Ответ 4
sizeof(texts)
в моей системе оценивается до 96: количество байтов, необходимых для массива и его экземпляры строки.
Как уже упоминалось в другом месте, sizeof(texts)/sizeof(texts[0])
даст значение 3, которое вы ожидали.
Ответ 5
Добавить значение остановки в массив:
#include <iostream>
using namespace std;
int main ()
{
string texts[] = {"Apple", "Banana", "Orange", ""};
for( unsigned int a = 0; texts[a].length(); a = a + 1 )
{
cout << "value of a: " << texts[a] << endl;
}
return 0;
}