Coming Soon
This lesson is currently being developed
Arrays and loops
Iterate through container elements effectively.
What to Expect
Comprehensive explanations with practical examples
Interactive coding exercises to practice concepts
Knowledge quiz to test your understanding
Step-by-step guidance for beginners
Development Status
Content is being carefully crafted to provide the best learning experience
Preview
Early Preview Content
This content is still being developed and may change before publication.
16.6 — Arrays and loops
In this lesson, you'll master the art of combining arrays (both C-style arrays and std::vector) with loops. You'll learn various loop patterns, when to use each type, and how to avoid common pitfalls when iterating through container elements.
Why arrays and loops go together
Arrays and loops are natural partners in programming:
- Arrays store multiple related values
- Loops provide a way to process each value systematically
- Together, they enable powerful data processing patterns
Most real-world programming involves processing collections of data, making this one of the most important skills to master.
Loop types for array iteration
1. Index-based loops (traditional for loop)
The classic approach uses indices to access array elements:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> scores = {85, 92, 78, 90, 88, 95, 82};
std::cout << "Student scores:" << std::endl;
// Index-based loop
for (std::size_t i = 0; i < scores.size(); ++i)
{
std::cout << "Student " << (i + 1) << ": " << scores[i] << std::endl;
}
return 0;
}
Output:
Student scores:
Student 1: 85
Student 2: 92
Student 3: 78
Student 4: 90
Student 5: 88
Student 6: 95
Student 7: 82
Advantages of index-based loops:
- You have access to the index (position) of each element
- You can modify elements through the index
- You can easily skip elements or process in reverse order
2. Range-based for loops (C++11)
The modern, cleaner approach:
#include <vector>
#include <iostream>
int main()
{
std::vector<std::string> fruits = {"apple", "banana", "orange", "grape"};
std::cout << "Available fruits:" << std::endl;
// Range-based for loop (read-only)
for (const std::string& fruit : fruits)
{
std::cout << "- " << fruit << std::endl;
}
return 0;
}
Output:
Available fruits:
- apple
- banana
- orange
- grape
Advantages of range-based loops:
- Cleaner, more readable syntax
- No risk of index out-of-bounds errors
- Works with any container type
- Less prone to off-by-one errors
3. Iterator-based loops
More flexible but slightly more complex:
#include <vector>
#include <iostream>
int main()
{
std::vector<double> prices = {12.99, 8.50, 15.75, 22.00};
std::cout << "Product prices:" << std::endl;
// Iterator-based loop
for (auto it = prices.begin(); it != prices.end(); ++it)
{
std::cout << "$" << *it << std::endl;
}
return 0;
}
Output:
Product prices:
$12.99
$8.5
$15.75
$22
Modifying elements during iteration
Modifying with index-based loops
#include <vector>
#include <iostream>
int main()
{
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::cout << "Original: ";
for (int num : numbers) std::cout << num << " ";
std::cout << std::endl;
// Double each number using index
for (std::size_t i = 0; i < numbers.size(); ++i)
{
numbers[i] *= 2;
}
std::cout << "Doubled: ";
for (int num : numbers) std::cout << num << " ";
std::cout << std::endl;
return 0;
}
Output:
Original: 1 2 3 4 5
Doubled: 2 4 6 8 10
Modifying with range-based loops
Use references to modify elements:
#include <vector>
#include <iostream>
int main()
{
std::vector<std::string> words = {"hello", "world", "cpp", "programming"};
std::cout << "Original: ";
for (const std::string& word : words) std::cout << word << " ";
std::cout << std::endl;
// Convert to uppercase using range-based loop with references
for (std::string& word : words) // Note: non-const reference
{
for (char& c : word) // Nested loop to process each character
{
c = std::toupper(c);
}
}
std::cout << "Uppercase: ";
for (const std::string& word : words) std::cout << word << " ";
std::cout << std::endl;
return 0;
}
Output:
Original: hello world cpp programming
Uppercase: HELLO WORLD CPP PROGRAMMING
Common loop patterns
1. Finding elements
#include <vector>
#include <iostream>
int main()
{
std::vector<int> numbers = {10, 25, 30, 45, 50, 35, 20};
int target = 30;
// Find using index-based loop
bool found = false;
std::size_t foundIndex = 0;
for (std::size_t i = 0; i < numbers.size(); ++i)
{
if (numbers[i] == target)
{
found = true;
foundIndex = i;
break; // Stop searching once found
}
}
if (found)
{
std::cout << "Found " << target << " at index " << foundIndex << std::endl;
}
else
{
std::cout << target << " not found" << std::endl;
}
return 0;
}
Output:
Found 30 at index 2
2. Counting elements
#include <vector>
#include <iostream>
int main()
{
std::vector<int> grades = {85, 92, 78, 90, 88, 95, 82, 96, 89, 91};
// Count grades above 90
int countAbove90 = 0;
for (int grade : grades)
{
if (grade > 90)
{
++countAbove90;
}
}
std::cout << "Total grades: " << grades.size() << std::endl;
std::cout << "Grades above 90: " << countAbove90 << std::endl;
std::cout << "Percentage above 90: "
<< (100.0 * countAbove90 / grades.size()) << "%" << std::endl;
return 0;
}
Output:
Total grades: 10
Grades above 90: 4
Percentage above 90: 40%
3. Calculating aggregates
#include <vector>
#include <iostream>
int main()
{
std::vector<double> temperatures = {23.5, 25.2, 22.8, 24.1, 26.0, 21.5, 23.9};
// Calculate sum, min, max, and average
double sum = 0.0;
double min = temperatures[0];
double max = temperatures[0];
for (double temp : temperatures)
{
sum += temp;
if (temp < min) min = temp;
if (temp > max) max = temp;
}
double average = sum / temperatures.size();
std::cout << "Temperature Statistics:" << std::endl;
std::cout << "Count: " << temperatures.size() << std::endl;
std::cout << "Sum: " << sum << "°C" << std::endl;
std::cout << "Average: " << average << "°C" << std::endl;
std::cout << "Min: " << min << "°C" << std::endl;
std::cout << "Max: " << max << "°C" << std::endl;
return 0;
}
Output:
Temperature Statistics:
Count: 7
Sum: 167°C
Average: 23.8571°C
Min: 21.5°C
Max: 26°C
4. Transforming data
#include <vector>
#include <iostream>
int main()
{
std::vector<int> celsius = {0, 10, 20, 30, 40, 100};
std::vector<double> fahrenheit;
// Convert Celsius to Fahrenheit
for (int c : celsius)
{
double f = (c * 9.0 / 5.0) + 32.0;
fahrenheit.push_back(f);
}
std::cout << "Temperature conversions:" << std::endl;
for (std::size_t i = 0; i < celsius.size(); ++i)
{
std::cout << celsius[i] << "°C = " << fahrenheit[i] << "°F" << std::endl;
}
return 0;
}
Output:
Temperature conversions:
0°C = 32°F
10°C = 50°F
20°C = 68°F
30°C = 86°F
40°C = 104°F
100°C = 212°F
Working with multi-dimensional arrays
Vectors of vectors (2D arrays)
#include <vector>
#include <iostream>
int main()
{
// Create a 3x4 matrix (3 rows, 4 columns)
std::vector<std::vector<int>> matrix = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
std::cout << "Matrix contents:" << std::endl;
// Nested loops for 2D array
for (std::size_t row = 0; row < matrix.size(); ++row)
{
for (std::size_t col = 0; col < matrix[row].size(); ++col)
{
std::cout << matrix[row][col] << "\t";
}
std::cout << std::endl;
}
// Alternative using range-based loops
std::cout << "\nUsing range-based loops:" << std::endl;
for (const auto& row : matrix)
{
for (int value : row)
{
std::cout << value << "\t";
}
std::cout << std::endl;
}
return 0;
}
Output:
Matrix contents:
1 2 3 4
5 6 7 8
9 10 11 12
Using range-based loops:
1 2 3 4
5 6 7 8
9 10 11 12
Reverse iteration
Reverse index-based loops
#include <vector>
#include <iostream>
int main()
{
std::vector<std::string> words = {"first", "second", "third", "fourth", "last"};
std::cout << "Forward order: ";
for (const std::string& word : words)
{
std::cout << word << " ";
}
std::cout << std::endl;
std::cout << "Reverse order: ";
// Safe reverse iteration using signed integer
for (int i = static_cast<int>(words.size()) - 1; i >= 0; --i)
{
std::cout << words[i] << " ";
}
std::cout << std::endl;
return 0;
}
Output:
Forward order: first second third fourth last
Reverse order: last fourth third second first
Using reverse iterators
#include <vector>
#include <iostream>
int main()
{
std::vector<int> numbers = {10, 20, 30, 40, 50};
std::cout << "Forward: ";
for (auto it = numbers.begin(); it != numbers.end(); ++it)
{
std::cout << *it << " ";
}
std::cout << std::endl;
std::cout << "Reverse: ";
for (auto it = numbers.rbegin(); it != numbers.rend(); ++it)
{
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
Output:
Forward: 10 20 30 40 50
Reverse: 50 40 30 20 10
Filtering and conditional processing
#include <vector>
#include <iostream>
int main()
{
std::vector<int> ages = {15, 22, 17, 35, 28, 19, 42, 16, 25, 33};
// Filter into separate categories
std::vector<int> minors;
std::vector<int> adults;
std::vector<int> seniors;
for (int age : ages)
{
if (age < 18)
{
minors.push_back(age);
}
else if (age < 65)
{
adults.push_back(age);
}
else
{
seniors.push_back(age);
}
}
std::cout << "Minors (" << minors.size() << "): ";
for (int age : minors) std::cout << age << " ";
std::cout << std::endl;
std::cout << "Adults (" << adults.size() << "): ";
for (int age : adults) std::cout << age << " ";
std::cout << std::endl;
std::cout << "Seniors (" << seniors.size() << "): ";
for (int age : seniors) std::cout << age << " ";
std::cout << std::endl;
return 0;
}
Output:
Minors (3): 15 17 16
Adults (7): 22 35 28 19 42 25 33
Seniors (0):
Performance considerations
Prefer range-based loops for simple iteration
#include <vector>
#include <iostream>
#include <chrono>
int main()
{
std::vector<int> largeVector(1000000, 42);
// Time index-based loop
auto start = std::chrono::high_resolution_clock::now();
long long sum1 = 0;
for (std::size_t i = 0; i < largeVector.size(); ++i)
{
sum1 += largeVector[i];
}
auto end = std::chrono::high_resolution_clock::now();
auto indexTime = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
// Time range-based loop
start = std::chrono::high_resolution_clock::now();
long long sum2 = 0;
for (int value : largeVector)
{
sum2 += value;
}
end = std::chrono::high_resolution_clock::now();
auto rangeTime = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "Index-based loop time: " << indexTime.count() << " microseconds" << std::endl;
std::cout << "Range-based loop time: " << rangeTime.count() << " microseconds" << std::endl;
std::cout << "Both sums equal: " << (sum1 == sum2 ? "Yes" : "No") << std::endl;
return 0;
}
Output (example):
Index-based loop time: 1234 microseconds
Range-based loop time: 1198 microseconds
Both sums equal: Yes
Common mistakes and how to avoid them
1. Off-by-one errors
#include <vector>
#include <iostream>
int main()
{
std::vector<int> numbers = {10, 20, 30, 40, 50};
// ❌ Wrong: Off-by-one error
std::cout << "Wrong way (causes undefined behavior):" << std::endl;
// for (std::size_t i = 0; i <= numbers.size(); ++i) // Don't do this!
// {
// std::cout << numbers[i] << " "; // Will access out-of-bounds
// }
// ✅ Correct: Use < instead of <=
std::cout << "Correct way:" << std::endl;
for (std::size_t i = 0; i < numbers.size(); ++i)
{
std::cout << numbers[i] << " ";
}
std::cout << std::endl;
return 0;
}
Output:
Wrong way (causes undefined behavior):
Correct way:
10 20 30 40 50
2. Modifying container size during iteration
#include <vector>
#include <iostream>
int main()
{
std::vector<int> numbers = {1, 2, 3, 4, 5};
// ❌ Dangerous: Modifying size during iteration
std::cout << "Dangerous approach (don't do this):" << std::endl;
// for (std::size_t i = 0; i < numbers.size(); ++i)
// {
// if (numbers[i] % 2 == 0)
// {
// numbers.erase(numbers.begin() + i); // Changes size and indices!
// }
// }
// ✅ Safe: Iterate backwards when removing elements
std::cout << "Safe approach - iterate backwards:" << std::endl;
for (int i = static_cast<int>(numbers.size()) - 1; i >= 0; --i)
{
if (numbers[i] % 2 == 0)
{
numbers.erase(numbers.begin() + i);
}
}
std::cout << "Remaining numbers: ";
for (int num : numbers) std::cout << num << " ";
std::cout << std::endl;
return 0;
}
Output:
Dangerous approach (don't do this):
Safe approach - iterate backwards:
Remaining numbers: 1 3 5
3. Using wrong loop type for the task
#include <vector>
#include <iostream>
int main()
{
std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
// ❌ Overcomplicated: Using index when you don't need it
std::cout << "Overcomplicated:" << std::endl;
for (std::size_t i = 0; i < names.size(); ++i)
{
std::cout << names[i] << std::endl; // Index not actually needed
}
// ✅ Simple and clear: Range-based loop when you just need values
std::cout << "Simple and clear:" << std::endl;
for (const std::string& name : names)
{
std::cout << name << std::endl;
}
return 0;
}
Output:
Overcomplicated:
Alice
Bob
Charlie
Simple and clear:
Alice
Bob
Charlie
Summary
Loops and arrays are fundamental tools for processing collections of data:
- Index-based loops: Use when you need the index or want to modify specific positions
- Range-based loops: Use for simple iteration when you don't need indices
- Iterator-based loops: Use for more complex navigation or when working with algorithms
Common patterns:
- Finding elements with early termination (break)
- Counting elements that meet criteria
- Calculating aggregates (sum, min, max, average)
- Transforming data from one form to another
- Filtering elements into categories
Best practices:
- Choose the right loop type for your task
- Prefer range-based loops for simple iteration
- Be careful with off-by-one errors
- Don't modify container size during forward iteration
- Use const references when you don't need to modify elements
In the next lesson, you'll learn about solving common challenges with array loops and handling edge cases.
Quiz
- When should you use an index-based loop instead of a range-based loop?
- How do you safely iterate backwards through a vector when removing elements?
- What's the most efficient way to iterate through a vector when you only need to read values?
- What happens if you use
<=
instead of<
in an index-based loop condition? - How do you modify vector elements using a range-based for loop?
Practice exercises
Try these exercises to practice arrays and loops:
-
Statistics calculator: Write a program that calculates comprehensive statistics (count, sum, average, min, max, median) for a vector of test scores.
-
Matrix operations: Create a 2D vector (matrix) and implement functions to find the sum of each row, each column, and the main diagonal.
-
Data filter: Given a vector of integers, create separate vectors for positive numbers, negative numbers, and zeros. Count how many elements fall into each category.
-
String processor: Given a vector of strings, find the longest string, count total characters, and create a new vector with all strings converted to uppercase.
Explore More Courses
Discover other available courses while this lesson is being prepared.
Browse CoursesLesson Discussion
Share your thoughts and questions