An array is a linear data structure which stores a collection of elements stored in contiguous memory. If you come from a JavaScript background, you might not notice the problems that I want to discuss today. I was in the same situation, when I was learning C++. I was asking myself, “Really ? Is this an array? 😨”.

This happens when you try to learn a old school language, after being proficient in a modern language like JavaScript. Soon I realized that knowing old languages is benefitial, since you can compare those with other modern languages and you’ll have the knowledge why something has changed overtime. In modern languages, dynamic arrays are used instead of raw arrays. This leaves a question for us. What are the problems with raw arrays? πŸ˜• I will write the rest of the article in a C++ perspective.

Arrays are fixed sized

Arrays can’t grow or shrink. If you want an raw array, you need to tell it how many elements you want to store. Isn’t that a problem? Suppose you are reading values from a file and you don’t know the exact amount of values in the file. What will you do? One simple way is to declare an array with a high number of elements (10^6). It may work but the problem is, you are just wasting memory spaces. The file may contain only 4 elements, and for storing 4 elements you are defining an array with 10^6 elements.

Checking out of bound

It has really surprised me that when I declare an array with 3 elements, int arr[3];, I can still access arr[4] or arr[100]. Later on I discovered that, the array name arr is a pointer. A pointer is a special type of variable that can store a memory address. So, arr points to the memory location of the first element, simillarly if you write arr + 1, it’ll point to the second element. Remember, arr and arr + 1 are pointers, they’re memory locations. They’re not the values stored in that particular index. So how do you extract the value from that memory location? You can use the contents of ( * ) operator. will give you the value of second element. So, arr[i] \equiv *(arr + i) also if you use the address of (&) operator, &arr[i] \equiv (arr + i). According to pointer arithmetic it’s valid, since arr[x] is just moving x steps from the base adress arr. It doesn’t really matter what x is. It’s your job while using arrays that x remains in the range [0, n – 1], where n is the length of the array.

Dynamic Arrays

A dynamic array is an improved version of array, which fixed all the problems that I’ve stated above. Though, it is implemented with raw arrays. It does it in a clever way. We can use C++ dynamic memory allocation for making our own dynamic array. The idea is that, we dynamically allocate memory for small number of elements. When the array has no space, allocate memory for double number of elements than before. Copy everything from the previous array to the new array. Now, you can free the memory of the previous array and the new array becomes your current array.

std :: vector

In C++, there is a STL container called vector which is basically an implementation of the dynamic array. If you don’t wanna run into problems that are hard to debug, then you should use dynamic arrays. Note that, dynamic arrays are a bit slow compared to raw arrays.

Usage of std :: vector

  1. Include the vector header file.
    #include <bits/stdc++.h>
    using namespace std;
    
  2. Creating a new vector
    // v1 -> vector that stores integers
    vector<int> v1;
    
    // v2 -> vector which stores float values
    vector<float> v2;
    
    // test_scores -> vector of 5 elements initialized with 0
    vector<int> test_scores (5);
    
    // test_scores -> vector with predefined values
    vector<int> test_scores {100, 98, 89, 85, 93};
    
    // test_scores -> vector of 5 elements initialized with 10
    vector<int> test_scores (5, 10);
    
  3. Pushing elements to vector
    vector<int> v1;
    // v1 = {}
    
    v1.push_back(1);
    // v1 = {1}
    
    v1.push_back(9);
    // v1 = {1, 9}
    
    v1.push_back(13);
    // v1 = {1, 9\. 13}
    
  4. Popping elements from vector
    vector<int> v1;
    v1.push_back(1); 
    v1.push_back(9); 
    v1.push_back(13);
    
    // pop_back() method removes and returns the last element
    int last_element = v1.pop_back(); // 13
    last_element = v1.pop_back(); // 9
    
  5. Getting size of a vector
    vector<int> v1;
    v1.push_back(1);
    v1.push_back(9); 
    v1.push_back(13);
    
    int size = v1.size(); // 3
    v1.push_back(20); 
    size = v1.size(); // 4
    
  6. Accessing individual elements
    vector<int> v;
    v.push_back(11); // {11}
    v.push_back(91); // {11, 91}
    v.push_back(123); // {11, 91, 123}
    
    // With [ ] operator
    cout << v[0] << endl; // 11
    cout << v[1] << endl; // 91
    cout << v[2] << endl; // 123
    cout << v[3] << endl; // no warning
    
    //  With at( ) method
    cout << v.at(0) << endl; // 11
    cout << v.at(1) << endl; // 91
    cout << v.at(2) << endl; // 123
    cout << v.at(3) << endl; // warning
    
  7. Traversing vectors with for loop
    vector<int> v;
    v.push_back(11); // {11}
    v.push_back(91); // {11, 91}
    v.push_back(123); // {11, 91, 123}
    
    // printing all the elements with for loop
    for (int i = 0; i < v.size(); i++)
        cout << v.at(i) << ", ";
    cout << endl;
    
  8. Traversing vectors with for … in loop
    vector<int> v;
    v.push_back(11); // {11}
    v.push_back(91); // {11, 91}
    v.push_back(123); // {11, 91, 123}
    
    // printing all the elements with for loop
    for (int element: v)
        cout << element << ", ";
    cout << endl;
    
  9. Traversing vectors with iterators
    vector<int> v;
    v.push_back(11); // {11}
    v.push_back(91); // {11, 91}
    v.push_back(123); // {11, 91, 123}
    
    for (auto it = v.begin(); it != v.end(); ++it)
        cout << *it << ", ";
    cout << endl;
    
Do you like Naimul Haque's articles? Follow on social!
Comments to: Arrays and vectors in C++

Your email address will not be published. Required fields are marked *