1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//Только для компиляторов, поддерживающих стандарт C++11 и выше #include <iostream> using namespace std; //clang C++11 Листинг #1 range-based for statement int main(){ int one_arr[] = {1,2,3,4,5}; int two_arr[][3]{ {1,2,3}, {9,8,7} }; cout << "one_arr:\n"; for (const auto &i:one_arr) cout << i << '\n'; cout << '\n'; cout << "two_arr:\n"; for (const auto &i:two_arr){ for (const auto &j:i){ cout << j << '\t'; } cout << '\n'; } cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//clang C++11 Обходим массив в обратном порядке range-based for statement //Только для компиляторов, поддерживающих стандарт C++11 и выше #include <iostream> using namespace std; //clang Листинг #2 range-based for statement int main(){ int arr[] = {1,2,3,4,5}; cout << "one_arr:\n"; for (const auto &i:arr) cout << *(end(arr) - i) << '\n'; cout << '\n'; cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//clang Листинг #3 Немного необычный подход к обходу массива в обратном порядке #include <iostream> using namespace std; int main(){ const int N = 5; int arr[N] = {1,2,3,4,5}; for (int i=0; i<N; i++){ cout << arr[(N - 1) - i] << ' '; } cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//clang попытка изменить значения //Только для компиляторов, поддерживающих стандарт C++11 и выше #include <iostream> using namespace std; //clang Листинг #4 Цикл range-for int main(){ const int N = 5; int arr[N] = {1,2,3,4,5}; for (auto i: arr){ i++; //попытка увеличить каждый элемент массива на 1 } for (auto i: arr) cout << i << ' '; //выводим массив на экран cout << '\n'; //ничего не изменилось cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
//clang попытка изменить значения //Только для компиляторов, поддерживающих стандарт C++11 и выше #include <iostream> using namespace std; //clang Листинг #5 Цикл range-for int main(){ const int N = 5; int arr[N] = {1,2,3,4,5}; cout << "arr before:\t"; for (auto i: arr) cout << i << ' '; //выводим массив на экран cout << '\n'; /*изменяем значения в ячейках*/ for (auto &i: arr){ i++; //попытка увеличить каждый элемент массива на 1 } /*обходим массив и выводим значения на экран*/ cout << "arr after:\t"; for (auto i: arr) cout << i << ' '; //выводим массив на экран cout << '\n'; //ничего не изменилось cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
//clang C++11 Защита самого себя от непреднамеренных изменений внутри обходимого массива //Листинг #6 #include <iostream> using namespace std; int main(){ const int N = 5; int arr[N] = {1,2,3,4,5}; cout << "arr before:\t"; for (const auto &i: arr) cout << i << ' '; //выводим массив на экран cout << '\n'; /*изменяем значения в ячейках*/ for (const auto &i: arr){ //i++; //будет ошибка } /*обходим массив и выводим значения на экран*/ cout << "arr after:\t"; for (const auto &i: arr) cout << i << ' '; //выводим массив на экран cout << '\n'; //ничего не изменилось, да потому что мы сейчас не можем cin.get(); } |
почему я создаю массив на 20 элемов, задаю 5, а выводит 5 + нули? про какую границу знает компилятор?
Массив в 20 элементов, вот все 20 и обходит.
а про какую границу идет речь? про конец массива? так об этом знает всё, что есть в С++
Я не знаю, чего Вы сейчас хотите.
Раньше было возможно 2 цикла: while, for и всякие разные способы, а теперь добавился for с диапазоном.
Если массив статический, то диапазон обхода от начала массива до последнего элемента массива.
Если массив динамический, то диапазон обхода от начала массива до последнего элемента согласно размеру size, но не по всему возможному резерву.
Но я не знаю, чего Вы хотите, поэтому затрудняюсь давать ответ в принципе.
Это всего лишь самый короткий синтаксис обхода всего массива.
Напишите код обхода массива не указывая границу (ни последний элемент, ни адрес последнего элемента массива, ни количество ячеек заданных массиву) явным образом.
while (mas[f]){f++;} — цикл будет накручиваться пока не закончатся заданные элементы в массиве, и не будет накручиваться до конца массива. Например: n=20; mas[n]={1,2,3,4,5} после написанного цикла f=5, а не 20. А при for ( auto i:mas){i++;} i=20 а не 5
А так: {0, 1, 2, 3, 4}
?
я не думал про этот подвох. получается нельзя, что бы в массив записывался ноль самостоятельно?
Это не подвох. Можно, но не в общем случае. Если 0 служит в качестве признака-окончания ввода, то без проблем, но если 0 не может служить в качестве окончания ввода, по причине возможного использования, то нельзя использовать такой вариант написания кода.
В круглых скобках while выражение, отдающее булевую истинну или ложь. Поскольку ноль всегда трактуется как ложь (false), то условие Вашего кода будет считаться выполненным при первом встреченном выражении, которое равносильно false. Встретили ноль, истрактовали его как false (ноль всегда false) и посчитали, что условие цикла выполнено.
Массив определён границами, которые нарушать нельзя. Если массиву сказали, что у массива максимум 20 элементов, то С++ выделяет в памяти ячейки на 20 элементов. Начало известно всегда, а вот где конец, обычно нужно или высчитывать или обозначать напрямую. Если выйти за допустимую норму, т. е., например, попробовать записать в 21-ю ячейку значение, то произойдёт нарушение границы массива, это повлечёт за собой UB. Память выделена для 20 ячеек, но не выделялась для 21-й. В невыделенное пространство в памяти производить запись незаконно.
Приведённый Вами пример UB. То, что он сработал правильно, это только стечение обстоятельства. Просто так получилось, что самый близкий сосед к последней ячейке массива (21-я ячейка) оказался со значением 0. При ином запуске программы всё может измениться. Вот эта последняя ячейка массива справа (сейчас 20-я) — это и есть граница массива, о которой спрашивалось Вами. Не последний записанный в массив элемент, а край массива, выходить за который незаконно.
Поправка. В том виде, какой есть, поведение не UB, потому что всем оставшимся элементам массива автоматически приписалось значение нуля. Но поведение свалится в UB как только весь массив наполнится. Если в значениях массива не окажется ноля, то цикл пойдёт за массив и будет продолжаться пока ноль не найдётся, а где ноль найдётся в непринадлежащей программе памяти, зависит от воли случая.
Спасибо, теперь немного разобрался