Coming Soon
This lesson is currently being developed
Introduction to containers and arrays
Introduction to storing collections of data.
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.1 — Introduction to containers and arrays
In this lesson, you'll learn about containers in C++, with a focus on why they're essential and how they compare to C-style arrays. This foundation will prepare you for working with std::vector, one of the most important containers in C++.
What are containers?
A container is a data structure that holds a collection of elements. Think of containers like different types of storage boxes:
- A shoe box holds multiple pairs of shoes
- A bookshelf holds multiple books in order
- A filing cabinet holds multiple documents organized by category
In C++, containers hold multiple values of the same type and provide ways to access, add, remove, and manipulate those values.
Why do we need containers?
So far, you've worked with individual variables:
int score1 = 85;
int score2 = 92;
int score3 = 78;
int score4 = 90;
int score5 = 88;
But what if you need to store 100 test scores? Or 1000? Creating individual variables becomes impractical. This is where containers shine - they let you store many values in a single, manageable structure.
C-style arrays: The foundation
Before diving into modern C++ containers, let's understand C-style arrays - the foundation upon which containers are built.
Declaring and initializing arrays
Here's how to create a C-style array:
#include <iostream>
int main()
{
// Create an array of 5 integers
int scores[5];
// Initialize values
scores[0] = 85;
scores[1] = 92;
scores[2] = 78;
scores[3] = 90;
scores[4] = 88;
// Print the scores
std::cout << "Test scores: ";
for (int i = 0; i < 5; ++i)
{
std::cout << scores[i] << " ";
}
std::cout << std::endl;
return 0;
}
Output:
Test scores: 85 92 78 90 88
You can also initialize arrays when you declare them:
#include <iostream>
int main()
{
// Initialize array with values
int scores[5] = {85, 92, 78, 90, 88};
// Or let the compiler count the elements
int grades[] = {95, 87, 92, 78, 85, 90}; // Size is 6
std::cout << "Scores: ";
for (int i = 0; i < 5; ++i)
{
std::cout << scores[i] << " ";
}
std::cout << std::endl;
std::cout << "Grades: ";
for (int i = 0; i < 6; ++i)
{
std::cout << grades[i] << " ";
}
std::cout << std::endl;
return 0;
}
Output:
Scores: 85 92 78 90 88
Grades: 95 87 92 78 85 90
Problems with C-style arrays
While C-style arrays work, they have several significant limitations:
1. Fixed size at compile time
int size = 10;
int scores[size]; // Error! Size must be known at compile time
const int SIZE = 10;
int scores[SIZE]; // OK - SIZE is compile-time constant
2. No size information
Arrays don't know their own size:
#include <iostream>
int main()
{
int numbers[] = {1, 2, 3, 4, 5};
// This doesn't give you the number of elements!
// It gives you the total bytes used by the array
std::cout << "sizeof(numbers): " << sizeof(numbers) << std::endl;
// To get the number of elements, you need:
int count = sizeof(numbers) / sizeof(numbers[0]);
std::cout << "Number of elements: " << count << std::endl;
return 0;
}
Output:
sizeof(numbers): 20
Number of elements: 5
3. No bounds checking
Arrays don't prevent you from accessing invalid indices:
#include <iostream>
int main()
{
int numbers[3] = {10, 20, 30};
std::cout << numbers[0] << std::endl; // OK
std::cout << numbers[2] << std::endl; // OK
std::cout << numbers[5] << std::endl; // Undefined behavior! No error message
return 0;
}
Output:
10
30
-858993460
The third output is unpredictable - it could be any value!
4. Difficult to resize
You cannot change the size of a C-style array after creation:
int scores[5] = {85, 92, 78, 90, 88};
// No way to add a 6th score without creating a new array
When arrays are useful
Despite their limitations, C-style arrays are still useful in certain situations:
1. When size is known and fixed
#include <iostream>
int main()
{
// Days in each month (non-leap year)
int daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
std::cout << "January has " << daysInMonth[0] << " days" << std::endl;
std::cout << "February has " << daysInMonth[1] << " days" << std::endl;
return 0;
}
Output:
January has 31 days
February has 28 days
2. For performance-critical code
Arrays have minimal overhead and provide direct memory access.
3. Working with C libraries
Many C libraries expect C-style arrays.
Modern C++ containers
Modern C++ provides powerful container classes that solve the problems of C-style arrays:
- std::vector: Dynamic array that can grow and shrink
- std::array: Fixed-size array with bounds checking
- std::string: Specialized container for characters
- std::deque: Double-ended queue
- std::list: Linked list
- std::set: Sorted collection of unique elements
- std::map: Key-value pairs
Why std::vector is special
std::vector is the most commonly used container because it:
- Grows and shrinks automatically
- Provides bounds checking (in debug mode)
- Knows its own size
- Offers many useful member functions
- Has performance similar to C-style arrays
- Is compatible with standard algorithms
Here's a preview of what std::vector looks like:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> scores = {85, 92, 78, 90, 88};
std::cout << "Number of scores: " << scores.size() << std::endl;
// Add a new score
scores.push_back(95);
std::cout << "After adding a score: " << scores.size() << std::endl;
// Print all scores
std::cout << "All scores: ";
for (int score : scores) // Range-based for loop
{
std::cout << score << " ";
}
std::cout << std::endl;
return 0;
}
Output:
Number of scores: 5
After adding a score: 6
All scores: 85 92 78 90 88 95
Memory layout and performance
Array memory layout
Arrays store elements in contiguous memory:
Array: [10][20][30][40][50]
Memory: |10|20|30|40|50|
^ ^ ^ ^ ^
addr addr+4 addr+8 addr+12 addr+16
This layout provides:
- Fast access: Elements are accessed by simple arithmetic
- Cache efficiency: Nearby elements are likely in CPU cache
- Predictable performance: Access time is constant
Container overhead
Modern containers like std::vector maintain this performance while adding useful features:
std::vector<int> numbers = {10, 20, 30, 40, 50};
// Internally stores:
// - Pointer to data: points to [10][20][30][40][50]
// - Size: 5 (current number of elements)
// - Capacity: 5 (space allocated)
Best practices for choosing containers
Use std::vector when:
- You need a dynamic array
- You frequently access elements by index
- You need to add/remove elements at the end
- You want good general-purpose performance
Use C-style arrays when:
- Size is fixed and known at compile time
- You need minimal memory overhead
- You're interfacing with C code
Use other containers when:
- std::array: Fixed size with bounds checking
- std::deque: Frequent insertion/deletion at both ends
- std::list: Frequent insertion/deletion in the middle
- std::string: Working with text
Summary
Containers are essential tools for managing collections of data in C++. While C-style arrays provide the foundation and are still useful in specific scenarios, modern C++ containers like std::vector solve many of their limitations:
- C-style arrays: Fixed size, no bounds checking, minimal overhead
- Modern containers: Dynamic sizing, bounds checking, rich functionality
- std::vector: The go-to container for most situations
In the next lesson, you'll dive deep into std::vector and learn how to create, initialize, and use vectors effectively.
Quiz
- What are the main limitations of C-style arrays compared to modern containers?
- When would you still choose a C-style array over std::vector?
- How do you find the number of elements in a C-style array?
- What happens when you access an array element beyond its bounds?
- What are the advantages of contiguous memory layout in arrays?
Practice exercises
Try these exercises to practice working with arrays and containers:
-
Grade calculator: Create a C-style array to store 5 test scores, calculate the average, and display all scores along with the average.
-
Array comparison: Write a program that creates two integer arrays and compares them element by element, reporting whether they are identical.
-
Container preview: Create a simple std::vector of your favorite numbers, add a few more numbers using push_back(), and display the final list with its size.
-
Memory exploration: Use the sizeof operator to explore how much memory different array sizes consume and calculate the bytes per element for different data types.
Explore More Courses
Discover other available courses while this lesson is being prepared.
Browse CoursesLesson Discussion
Share your thoughts and questions