Start learning free

LESSON 99 OF 409 · ARRAYS I

Exceeding Vector Bounds in C++

Lesson Read the full explanation

When accessing vector data with indices, the most common problem we can run into is exceeding the vector's bounds.

Remember, the items of a vector are indexed from 0 to size - 1. Any index which is not in this range is invalid.

When you try to access an item with an invalid index, C++ throws an error:

vector<int> ourArray = {50, 40, 30};

// Valid indices: 0, 1, 2
cout << myArray[0] << endl; // Output: 50
cout << myArray[2] << endl; // Output: 30

// Invalid indices: 3, 30, -1
cout << myArray[3] << endl; // raises IndexOutOfBounds error
cout << myArray[30] << endl; // raises IndexOutOfBounds error
cout << myArray[-1] << endl; // raises IndexOutOfBounds error

As programmers, we always want to make sure that we don't exceed one vector's bounds in our programs.


Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 1
    Ctrl + Enter to check

    C++ · ARRAYS I

    Exceeding Array Bounds in C++, explained

    Introduction

    In this lesson, we will explore the concept of vector bounds in C++. Vectors are a dynamic array type provided by the C++ Standard Library, and they are widely used due to their flexibility and ease of use. However, one common issue when working with vectors is accessing elements outside their valid range, which can lead to runtime errors. Understanding how to handle vector bounds is crucial for writing robust and error-free code.

    Understanding the Basics

    Vectors in C++ are zero-indexed, meaning the first element is at index 0, and the last element is at index size - 1. Accessing an element outside this range will result in an IndexOutOfBounds error. For example, if a vector has 3 elements, valid indices are 0, 1, and 2. Any attempt to access indices like -1, 3, or beyond will cause an error.

    Here is a simple example to illustrate this:

    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> ourArray = {50, 40, 30};
    
        // Valid indices
        std::cout << ourArray[0] << std::endl; // Output: 50
        std::cout << ourArray[2] << std::endl; // Output: 30
    
        // Invalid indices
        std::cout << ourArray[3] << std::endl; // Undefined behavior
        std::cout << ourArray[30] << std::endl; // Undefined behavior
        std::cout << ourArray[-1] << std::endl; // Undefined behavior
    
        return 0;
    }
    

    Main Concepts

    To avoid accessing invalid indices, we need to ensure that our index values are within the valid range. This can be done by checking the size of the vector before accessing its elements. The size() method of the vector class returns the number of elements in the vector, which can be used to validate indices.

    Here is an example of how to safely access vector elements:

    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> ourArray = {50, 40, 30};
    
        for (int i = 0; i < ourArray.size(); ++i) {
            std::cout << ourArray[i] << std::endl;
        }
    
        int index = 3;
        if (index >= 0 && index < ourArray.size()) {
            std::cout << ourArray[index] << std::endl;
        } else {
            std::cout << "Index out of bounds" << std::endl;
        }
    
        return 0;
    }
    

    Examples and Use Cases

    Let's consider a few more examples to understand the concept better:

    #include <iostream>
    #include <vector>
    
    void printElement(const std::vector<int>& vec, int index) {
        if (index >= 0 && index < vec.size()) {
            std::cout << "Element at index " << index << ": " << vec[index] << std::endl;
        } else {
            std::cout << "Index " << index << " is out of bounds" << std::endl;
        }
    }
    
    int main() {
        std::vector<int> numbers = {10, 20, 30, 40, 50};
    
        printElement(numbers, 2); // Valid index
        printElement(numbers, 5); // Invalid index
        printElement(numbers, -1); // Invalid index
    
        return 0;
    }
    

    Common Pitfalls and Best Practices

    One common mistake is assuming that an index is always valid without checking. This can lead to undefined behavior and potential crashes. Always validate indices before accessing vector elements.

    Best practices include:

    • Using the at() method instead of the subscript operator [] for safer access, as at() throws an exception if the index is out of bounds.
    • Encapsulating vector access in functions that perform bounds checking.
    • Using iterators to traverse vectors, which inherently avoid out-of-bounds errors.

    Advanced Techniques

    For advanced usage, consider using iterators and the std::find algorithm to safely access and manipulate vector elements. Iterators provide a way to traverse the vector without directly using indices, reducing the risk of out-of-bounds errors.

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    int main() {
        std::vector<int> numbers = {10, 20, 30, 40, 50};
    
        auto it = std::find(numbers.begin(), numbers.end(), 30);
        if (it != numbers.end()) {
            std::cout << "Element found: " << *it << std::endl;
        } else {
            std::cout << "Element not found" << std::endl;
        }
    
        return 0;
    }
    

    Code Implementation

    Here is a complete example demonstrating safe vector access and handling out-of-bounds errors:

    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> ourArray = {50, 40, 30};
    
        // Safe access using at()
        try {
            std::cout << ourArray.at(0) << std::endl; // Output: 50
            std::cout << ourArray.at(2) << std::endl; // Output: 30
            std::cout << ourArray.at(3) << std::endl; // Throws out_of_range exception
        } catch (const std::out_of_range& e) {
            std::cerr << "Exception: " << e.what() << std::endl;
        }
    
        return 0;
    }
    

    Debugging and Testing

    When debugging vector access issues, use assertions to validate indices. This helps catch errors during development:

    #include <iostream>
    #include <vector>
    #include <cassert>
    
    int main() {
        std::vector<int> ourArray = {50, 40, 30};
    
        int index = 3;
        assert(index >= 0 && index < ourArray.size() && "Index out of bounds");
        std::cout << ourArray[index] << std::endl;
    
        return 0;
    }
    

    Writing tests for functions that access vectors is also important. Use testing frameworks like Google Test to automate and validate your code:

    #include <gtest/gtest.h>
    #include <vector>
    
    int getElement(const std::vector<int>& vec, int index) {
        if (index >= 0 && index < vec.size()) {
            return vec[index];
        }
        throw std::out_of_range("Index out of bounds");
    }
    
    TEST(VectorTest, ValidIndex) {
        std::vector<int> vec = {10, 20, 30};
        EXPECT_EQ(getElement(vec, 1), 20);
    }
    
    TEST(VectorTest, InvalidIndex) {
        std::vector<int> vec = {10, 20, 30};
        EXPECT_THROW(getElement(vec, 3), std::out_of_range);
    }
    
    int main(int argc, char **argv) {
        ::testing::InitGoogleTest(&argc, argv);
        return RUN_ALL_TESTS();
    }
    

    Thinking and Problem-Solving Tips

    When dealing with vector bounds, always think about edge cases, such as empty vectors or accessing the first and last elements. Break down the problem into smaller parts and validate each part separately. Practice by writing small programs that manipulate vectors and handle out-of-bounds errors.

    Conclusion

    Understanding and handling vector bounds is essential for writing robust C++ programs. By validating indices, using safe access methods, and following best practices, you can avoid common pitfalls and ensure your code is reliable. Keep practicing and exploring more advanced techniques to become proficient in managing vectors in C++.

    Additional Resources

    Keep going with C++About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free