Search

6.9a — Dynamically allocating arrays

In addition to dynamically allocating single values, we can also dynamically allocate arrays of variables. Unlike a fixed array, where the array size must be fixed at compile time, dynamically allocating an array allows us to choose an array length at runtime.

To allocate an array dynamically, we use the array form of new and delete (often called new[] and delete[]):

Because we are allocating an array, C++ knows that it should use the array version of new instead of the scalar version of new. Essentially, the new[] operator is called, even though the [] isn’t placed next to the new keyword.

Note that because this memory is allocated from a different place than the memory used for fixed arrays, the size of the array can be quite large. You can run the program above and allocate an array of length 1,000,000 (or probably even 100,000,000) without issue. Try it! Because of this, programs that need to allocate a lot of memory in C++ typically do so dynamically.

Dynamically deleting arrays

When deleting a dynamically allocated array, we have to use the array version of delete, which is delete[].

This tells the CPU that it needs to clean up multiple variables instead of a single variable. One of the most common mistakes that new programmers make when dealing with dynamic memory allocation is to use delete instead of delete[] when deleting a dynamically allocated array. Using the scalar version of delete on an array will result in undefined behavior, such as data corruption, memory leaks, crashes, or other problems.

One often asked question of array delete[] is, “How does array delete know how much memory to delete?” The answer is that array new[] keeps track of how much memory was allocated to a variable, so that array delete[] can delete the proper amount. Unfortunately, this size/length isn’t accessible to the programmer.

Dynamic arrays are almost identical to fixed arrays

In lesson 6.8 -- Pointers and arrays, you learned that a fixed array holds the memory address of the first array element. You also learned that a fixed array can decay into a pointer that points to the first element of the array. In this decayed form, the length of the fixed array is not available (and therefore neither is the size of the array via sizeof()), but otherwise there is little difference.

A dynamic array starts its life as a pointer that points to the first element of the array. Consequently, it has the same limitations in that it doesn’t know its length or size. A dynamic array functions identically to a decayed fixed array, with the exception that the programmer is responsible for deallocating the dynamic array via the delete[] keyword.

Initializing dynamically allocated arrays

If you want to initialize a dynamically allocated array to 0, the syntax is quite simple:

Prior to C++11, there was no easy way to initialize a dynamic array to a non-zero value (initializer lists only worked for fixed arrays). This means you had to loop through the array and assign element values explicitly.

Super annoying!

However, starting with C++11, it’s now possible to initialize dynamic arrays using initializer lists!

Note that this syntax has no operator= between the array length and the initializer list.

For consistency, in C++11, fixed arrays can also be initialized using uniform initialization:

As of the time of writing, the GCC still has a bug where initializing a dynamically allocated array of chars using a C-style string literal causes a compiler error:

If you have a need to do this on GCC, dynamically allocate a std::string instead (or allocate your char array and then copy the string in).

Also note that dynamic arrays must be declared with an explicit length:

Resizing arrays

Dynamically allocating an array allows you to set the array length at the time of allocation. However, C++ does not provide a built-in way to resize an array that has already been allocated. It is possible to work around this limitation by dynamically allocating a new array, copying the elements over, and deleting the old array. However, this is error prone, especially when the element type is a class (which have special rules governing how they are created).

Consequently, we recommend avoiding doing this yourself.

Fortunately, if you need this capability, C++ provides a resizable array as part of the standard library called std::vector. We’ll introduce std::vector shortly.

Quiz

1) Write a program that:
* Asks the user how many names they wish to enter.
* Asks the user to enter each name.
* Calls a function to sort the names (modify the selection sort code from lesson 6.4 -- Sorting an array using selection sort)
* Prints the sorted list of names.

Hint: Use a dynamic array of std::string to hold the names.
Hint: std::string supports comparing strings via the comparison operators < and >

Your output should match this:

How many names would you like to enter? 5
Enter name #1: Jason
Enter name #2: Mark
Enter name #3: Alex
Enter name #4: Chris
Enter name #5: John

Here is your sorted list:
Name #1: Alex
Name #2: Chris
Name #3: Jason
Name #4: John
Name #5: Mark

Quiz solutions

1) Show Solution

6.10 -- Pointers and const
Index
6.9 -- Dynamic memory allocation with new and delete

522 comments to 6.9a — Dynamically allocating arrays

  • Luiz Carlo

    This is my shot at it, I tried it to make as robust as possible so there would be no ways to break it, since I have still to learn exception handling, I think it's pretty good.

    • nascardriver

      I think it's pretty good too. You could move the name input into its own function to de-clutter `main`.
      Standard functions live in the `std` namespace. So does `exit`. You need to include too.
      Some functions might be available without including their header or withing specifying their namespace. But more often than not this is compiler-dependent and your code might not work for others.

  • Cypeace

    Hey guys!

    this one was quite a nut to crack, took me at least 3 days and I'm still nowhere near to your code!
    I see from your solution, that you simply search for smallest element in array and the you swap it with the first. Then you repeat from next element, right?
    So how do you measure a "string", does < > operators compare each letter in string to the opposing element of "string" to determine, which has bigger letter? (brilliant if so)
    Here's my solution, which takes it too.. literally :-D

    • nascardriver

      Hey!

      - Initialize your variables with brace initializers.

      Your code looks good otherwise. You must've missed the hint "std::string supports comparing strings via the comparison operators < and >". Those operators compare letter by letter, until they find a difference.

      • Cypeace

        Oh indeed! I just love to complicate everything :-D But it was good exercise.. took me couple of days to figure it out lol

        But I guess in the end of the program, what really matters is the result.

        Thank you for all your support, see you in the next code!

  • Pave

    Okay. So the quiz was kinda confusing becouse i tought that passing an std::string array[] to a function would make it decay and could only access the first element.

    How is it that we can pass the array and access the whole array in a function? And some arrays will decay and can only access the first element.

  • hellmet

    So, in reality, name[0] is actually a pointer to the start of the string that std::string abstracts away from us? And name is technically identical to a char **?

    • You didn't say what type `name` is, I'm assuming it's `std::string`.
      > name[0] is actually a pointer to the start of the string
      No. It's a reference (Covered later) to the first char. You can take its address to get a pointer.

      > And name is technically identical to a char **?
      No. `std::string` stores a `char*`, but they're not identical. It's not guaranteed that the `char*` is the first member of `std::string`, so double indirection of an `std::string` isn't guaranteed to give you the string.

      • hellmet

        Ohh okay, I was thinking in analogies, but yes, you make it clear now. Also, I ran this code just before you replied, further cements your statements.

      • hellmet

        Also, did you mean

        • No. `c_str` is a member function of `std::string`.

          • hellmet

            (Oh and the 'names' here is the array in the example given above. )
            Hmmm... Okay, I asked 'cause I observed this

            • I was under the assumption that `names` is an `std::string`. If `names` is an array of `std::string`, ie. `std::string names[5]`, then

              > name[0] is actually a pointer to the start of the string
              `names[0]` is a reference to the first `std::string` in the array.

              > And name is technically identical to a char **?
              That's still wrong. `names` can decay to `std::string*`, so it's somewhat similar, but type-wise way different.

  • m3loo

    if I had a static array and I wanted to copy the values from the static array to a dynamic array, how would I do that?

    • You could of course also use a regular for-loop.

      `std::copy` can be parallelized and it's obvious that the line only copies data, it should be preferred.

      • m3loo

        first of all thank you very much!
        so I did use the for loop and it worked. now I wanted to copy a 2 dimensional static array in a one dimensional dynamic array (because the dynamic array can change it size so I thought that should be possible), and it kinda works but I also get those random numbers (meaning memory numbers).

        • > because the dynamic array can change it size
          If you create an array of size N, that array will always have size N. You can only "resize" it by deleting the old array and creating a new one.
          Without seeing your code, I can't tell you what you did wrong.

          • m3loo

            ahh ok. I just played around with

            • You're accessing invalid indexes. `i` and `j` run up to 3, but the highest valid index is 1. There are several issues with your code. Here's a fixed version. Please ask any questions that may come up.

              Or with `std::copy_n`

              Ideally you wouldn't use C-style arrays and multidimensional arrays in the first place.

              • m3loo

                thx again, I have some questions:

                1) so here, why did we have to use static_cast here? (I saw it get used, when for example we wanted to pass a double to an int.)
                2) then why did we use (array1) and in the next line we used (array1[0]), why the [0]?
                3) and my last question, why did we need the * here?

                • 1)
                  `std::size` returns an `std::size_t` which we need to convert to an `int`.

                  2)
                  We want to know the length of the inner arrays. Since all inner arrays have the same length, we can use any of them. `array1[0]` is the most likely to exist, so that's what I used.

                  3)
                  That's a multiplication.

  • Paul

    Hi,
    would you please help me?
    I'm getting desperate. I don't understand, why it's not working...THX

    #include <iostream>
    #include <string>
    void selectionSort(std::string *myArray, int numNames)
    {

        // Step through each element of the array
        // (except the last one, which will already be sorted by the time we get there)
        for (int startIndex = 0; startIndex < numNames - 1; ++startIndex)
        {
            // smallestIndex is the index of the smallest element we’ve encountered this iteration
            // Start by assuming the smallest element is the first element of this iteration
            int smallestIndex = startIndex;

            // Then look for a smaller element in the rest of the array
            for (int currentIndex = startIndex + 1; currentIndex < numNames; ++currentIndex)
            {
                // If we've found an element that is smaller than our previously found smallest
                if (myArray[currentIndex] < myArray[smallestIndex])
                    // then keep track of it
                    smallestIndex = currentIndex;
            }

            // smallestIndex is now the smallest element in the remaining array
                    // swap our start element with our smallest element (this sorts it into the correct place)
            std::swap(myArray[startIndex], myArray[smallestIndex]);
        }

        // Now that the whole array is sorted, print our sorted array as proof it works
        for (int index = 0; index < numNames; ++index)
            std::cout << myArray[index] << ' ';

    }
    std::string* enterName(int amount_names_)
    {
        std::string *nameslist=new std::string[amount_names_];
        for(int count=0;count< amount_names_;++count)
        {
            std::cout<<"Enter name #"<<count+1<<": ";
            std::cin>>nameslist[count];

        }
        return nameslist;
    }

    int main()
    {
        std::cout << "How many names would you like to enter? ";
        int amount_names{};
        std::cin>> amount_names;
        selectionSort(enterName(amount_names),amount_names);
        delete[] enterName(amount_names);
        return 0;
    }

    • Please use code tags.

      - line 51 calls `enterName` again, creating a new array. The array from line 50 is leaked.
      - Initialize your variables with brace initializers.
      - Use your editor's auto-formatting feature.
      - If your program prints anything, the last thing it prints should be a line feed.

      "it's not working" doesn't help.
      What are you trying to do? Quiz X
      What's the expected behavior? Quiz X
      What is your input?
      What is the output?
      What is the expected output?
      What are the error messages?

  • Bankomat

    Hello!
    I was just wondering if it's ok to delete a dynamic array returned from a function by doing

    At least, as ok as it gets using dynamically allocated arrays in this  manner.

    • No, that's wrong.
      When you delete arrays, you need to use `delete[]`. You can only delete pointers to memory that was allocated with `new`. Your calculation seems like this is not the case. If your function did

      then the caller can

      Even though this works, it's messy. You should use a standard container instead (Covered in a few lessons).

      • Bankomat

        Ah, thank you.

        The reason I tried what I tried was because I was under the impression that only the first element in the array would be deleted by the caller as the array would decay to a pointer.

        I've already learned a few ways to get by this problem from future chapters but thanks nonetheless!

        • > I was under the impression that only the first element in the array would be deleted by the caller as the array would decay to a pointer
          It does decay, but `new[]` and `delete[]` use some internal information to keep track of the array's size. You can't access it, but `delete[]` can.

  • Allocate the outer array first, then allocate the inner ones in a loop.

  • Ramkumar

    Hi, great work dude ! .
    How can i allocate multidimensional arrays like this? during run time?

Leave a Comment

Put all code inside code tags: [code]your code here[/code]