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

441 comments to 6.9a — Dynamically allocating arrays

  • Toms

    Greetings, *khmm* the best c++ (and programming in general) teacher in the world *khmm*, Alex! (Thank you so much for these tutorials)

    I have a question - whenever I run my code, I always forget to #include headers.. But that's not the problem here. The problem (or advantage) is that even if I don't include these std libraries, such as <string>, my code works just fine with only <iostream> #included.

    Why is that?

  • DangerousVanilla

    This is what I came up with for the quiz in this section. It appears to be working, but any feedback would be appreciated. I know I didn't separate functions and such here, but I don't believe code is repeated either unless I've missed it.

    • - Initialize your variables with brace initializers.
      - You don't need `name`, you can extract directly into `namesArray[namesEntered]`.
      - Line 41-42 shouldn't be inside the loop.
      - Line 15+: You know how often you'll loop before starting the loop. Use a `for`-loop.

      You're not using selection sort, you're using bubble sort with early termination.

      • DangerousVanilla

        - When you say to initialize my variables with brace initializers, do you mean the first variable inside the for loops? Line 27, 31, and 47 - iteration, currentIndex, and index? If so, will do. This is just the way I keep seeing it done in the tutorials so I assumed it was correct I guess.

        - You're saying to extract as "std::cin >> namesArray[namesEnterd];" instead and just skip the names variable entirely? I suppose that makes sense and eliminates my useless variable.

        - When moving this outside the loop I had to also move my "bool swapped = false;" outside the loop and remove the break;, but other otherwise it seems to work the same. I'm not sure I completely understand why this was necessary. I thought (probably incorrectly) that placing it where I did would perform a break on the outside loop after the inside one was done with it's iteration which would terminate it prior to any additional calculations of the loops.

        - You're right, I'm not sure why I chose to use a do while here. Does a for loop provide better performance? I didn't recall reading about it anywhere yet.

        - I intentionally chose to use bubble sort here rather than selection sort. Just trying something different.

        • > When you say to initialize my variables with brace initializers [...]
          Line 25, 27, 29, 31, 47

          > skip the names variable entirely?
          Yup

          > moving this outside the loop
          Only line 41 and 42, the if-statement with the `break` stay inside the loop.

          > Does a for loop provide better performance?
          No, but it's easier to read as you don't have to search for a termination condition anywhere apart from the loop's header.

  • Sabhya Kapur

  • lmm

    /*
    Your name,
    email,
    and project name go here
    */

    /*
    There are 5 single character errors in the code below.
    Please find and fix the errors by adding or removing a single character.
    Put your initials and a comment about what you fixed.
    */

    #include <iostream>
    #include <string>
    #include <sstream>

    using namespace std;

    //Prototypes are correct, use as a guide
    void AskForInfoRefs(string &rName, int &rAge);
    void AskForInfoPoints(string *pName, int *pAge);
    string WriteInfo(string name, int age);

    int main()
    {
        string name, infoRefs, infoPoints;
        int *age;

        AskForInfoRefs(name, age);

        infoRefs = WriteInfo(name, age);

        AskForInfoPoints(&name, age);

        infoPoints = WriteInfo(name, age);

        cout << "\nThis is the info from the references:\n"
            << &infoRefs << endl;

        cout << "\nThis is the info from the pointers:\n"
            << infoPoints << endl;

        cin.get();
        return 0;
    }

    void AskForInfoRefs(string &rName, int &rAge)
    {
        cout << "Please enter someone's name: ";
        getline(cin, rName);

        cout << "Please enter someone's age: ";
        cin >> *rAge;
        cin.ignore();
    }

    void AskForInfoPoints(string *pName, int *pAge)
    {
        cout << "Please enter someone else's name: ";
        getline(cin, pName);

        cout << "Please enter someone else's age: ";
        cin >> *pAge;
        cin.ignore();
    }

    string WriteInfo(string name, int age)
    {
        stringstream ss;

        ss << "Hi, " << name << "! I wish I were " << age << "!\n";

        return ss.str();
    }

    where are my errors ?????

    • - Initialize your variables with brace initializers.
      - Limit your lines to 80 characters in length for better readability on small displays.
      - Don't pass 32767 to @std::cin.ignore. Pass @std::numeric_limits<std::streamsize>::max().
      - Use your editor's auto-formatting feature.
      - You're leaking memory. Delete `name`.

  • Torraturd

    This is what I got for the quiz answer:

    Thank you so much for this tutorial!

    • - Initialize your variables with brace initializers.
      - Limit your lines to 80 characters in length for better readability on small displays.
      - Don't pass 32767 to @std::cin.ignore. Pass @std::numeric_limits<std::streamsize>::max().
      - You don't need `name`, you can extract directly into `names[count`.
      - You're using the same name style for variables and functions, this can lead to confusion.
      - `main`: Missing return-statement.

      Looks good apart from that!

    • Hi, I was just wandering why did you use a null terminator here!

  • Dhananjay Singh

    Hi! First of all thanks for your tutorials!

    I just wanted to ask that earlier when I used to take length of the array as input from the user

    cin>>length

    and the declare an array i.e.

    int array[length]

    but now its showing the error, as you told, was it because I changed all my settings as told by you in previous tutorials on compilers, so even warnings are being treated as errors.

    Because online compilers, don't show any such error.

  • Rev

    I have two questions about delete[] operator. Say, I allocate 2 arrays like this:

    Array arr1 1 holds 2 ints, arr2 holds 10.
    And then i swap their pointers

    Then i delete arr1

    So my first question is: Does delete[] delete 10 ints or 2?

    and the second is: What if i do this:

    Now, are all ints in arr2 deallocated at all? Or only one is? Or delete[] accidentally deletes one innocent int and leaves the one before arr2?

    These are my questions. If anyone bothers to lighten my curiosity up, i'd be greatly grateful! Thank you.

    • The pointer you pass to `delete[]` must be one that was returned by `new[]`. For your swap example, that's the case. Everything works fine.
      Your second example doesn't try to delete a pointer returned by `new[]`, behavior is undefined.

  • cdecde57

    I need help with some code. Please note that I based this off of the quiz.

    No, it is not robust and it is not supposed to. I used std::nothrow but did not do any safeguards I know.

    My concern is when you run it, it will skip the first name. How do I fix this? Also please note that
    I did not put the sort in a different function I know I normally would put it in a function but I am just
    trying to narrow it down as much as possible so its' easier to read. Pretty much why does it skip the first
    name and how do I fix it.

    • cdecde57

      Note:

      I am using std::getline(std::cin, ); because that way you can do a name like,

      John Doe

      When I do cin insted of getline it works just fine. Thanks!

    • `std::cin.operator>>` doesn't remove the line feed from the input stream. @std::getline stops at the first line feed it finds.
      Add

      after you read the size.

      Your sorting algorithm won't work. Swap line 21 and 22.

      • cdecde57

        Thanks it all works now :D

        btw I was just wondering.
        How did you know that using

        would fix it? (I just want to know so when I am doing coding in the future I can fix my code better).
        Thanks!

        • `std::cin.operator>>` leaves the line feed ('\n') in the input stream.
          `std::getline` sees that line feed and stop extraction (But removes the line feed).
          To fix this, we need to remove the line feed before calling `std::getline` for the first time.
          `std::cin.ignore` removes characters, and that's what we want to do. We ignore all characters (`std::numeric_limits<std::streamsize>::max()`) until a line feed is found, we remove that too and stop removing characters.

  • i was trying to pass the array into the sort function safely but i doesnt feel right even though this works

    • * Initialize your variables with brace initializers.
      * Limit your lines to 80 characters in length for better readability on small displays.
      * Use ++prefix unless you need postfix++.
      * You're leaking @ptr_arrayOfNames.
      * The forward declarations can be avoided my moving @main below the other functions.
      * Line 52+, 67+: Duplicate code, can be reduced to

      That's the correct way of passing an array. C++ has several list containers (covered later), which combine the array and its length so you don't have to pass them separately.

  • OmegaX128

    Hey again! How does this look for the quiz question?

    • * Don't pass 32767 to @std::cin.ignore. Pass @std::numeric_limits<std::streamsize>::max().
      * Line 13: You're clearing the error flag, even if no error occurred. If an error occurred, you don't do anything about it (other than clearing the flag).
      * Line 26: Unnecessary variable. You can extract directly into an array element.
      * Sorting your includes alphabetically can help organizing your code.

      Looks good otherwise!

  • Ali Ahmad

    What if I want to find the size of a dynamically allocated array? How shall I do this?

  • MasterOfNothing

    Can anyone explain this:

    "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)."

    or allocate your char array and then copy the string in? My head is a bit spinning from pointers and arrays. How do I copy the string in again?

    QUIZ!
    I fear the do-while is unnecessary or can lead to problems here:

    • * Line 21, 40, 42, 46, 6, 65, 8, 9: Initialize your variables with brace initializers.
      * Line 9: Limit your lines to 80 characters in length for better readability on small displays.
      * Line 30, 35, 53: Don't pass 32767 to @std::cin.ignore. Pass @std::numeric_limits<std::streamsize>::max().
      * Line 49: You're checking for an error, but you continue even if an input error occurred. (I don't think anything can go wrong when extracting to a string anyway).
      * Line 43: Should be a for-loop.
      * Line 65+: Use curly brackets.

      You can use @std::strcpy from @<cstring>

      • MasterOfNothing

        Thank you for the input!

        Yes, brace initializing is thing I forget, often.

        So a pure string can also be used as an argument for strcpy() function. I thought only C-style strings were accepted as both arguments.

  • Dimbo1911

    Good morning, does this code seem ok? Is it required to include string and utility? This compiles fine without it (no warnings) on code blocks 17.12 with C++17

    • Hi!

      * Use angle brackets to access arrays.
      * Line 35: Unnecessary, @wasChanged dies at the end of a cycle and is re-defined.
      * Line 51: Using the no-throw version but not checking if the allocation was successful will cause more trouble than ignoring the exception.
      * Line 59: Unnecessary, your program is done after this line.

      If you use something, include it. Your code might compile fine for you, but it might not for someone else or with a different compiler.
      Your implementation of @<iostream> includes @<string> and @<utility>. That's not standard.

  • Tom

    Hi all - I've been banging my head for the past two hours trying to work out why my sorting algorithm doesn't work, even after comparing it to the one in the solution.

    This prints "Alex Jason John Chris Mark" after it finishes running (still working on the formatting!). Otherwise, it works fine when I replace my sorting algorithm with the one found in the solution. Any thoughts?

  • Hi
    Thanks a lot for this lovely tutorial.

    I just tried out the following code on https://www.onlinegdb.com/online_c_compiler:

    This is working fine. So I just have a doubt regarding the array size of a fixed array. Doesn't this code allow us to chose any array length at runtime??

    Thanks

    • It's not valid cpp. The -pedantic-errors compiler flag should prevent this. I couldn't get onlinegdb to abort compilation.

      It's working here
      https://rextester.com/l/cpp_online_compiler_clang
      with

  • yh

    When I use dynamically allocated arrays in C++, I got this "iso c++ forbids variable length array". Does it mean we shouldn't use this style in C++?

    • It means you didn't dynamically allocate it. You did something like this

      @arr is not dynamically allocated, it's length must be known at compile time.
      What you should do is

      • yh

        Thanks! I found my problem. I was trying to dynamically allocate a 2D array like this:

        Turns out it's more complicated than I thought to dynamically allocate a 2D array, so I use a 1D array workaround at last.
        Thanks!

Leave a Comment

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