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

478 comments to 6.9a — Dynamically allocating arrays

  • Nishant

    For static allocated arrays- If we input array size from user, store it in a variable, and put that variable in place of size of the array when declaring it, the memory for this array is still allocated during runtime since it's size is determined by user input. So how is it different from dynamically allocated arrays??

  • Anas

    I am getting an error !
    string array is not decaying into pointer in swap.

  • Denis

    Hello everyone! I am waiting your remarks. Thanks a lot!)

    • Hello!

      - Line 11: Initialize with brace initializers. If you're using `=` during initialization, you're doing it wrong.
      - Line 21: You can re-use "i" as an identifier. The `i` from line 14 only exists inside the loop.

      Try using more functions to increase readability and reusability. This code could be separated into input, sort, print.

  • Sam

    Sorry. Here's my FULLY updated solution accounting for full names and uppercase characters :)

    • My previous comments apply here too.

      - `getNames::name` is unnecessary. You get pass `names[x]` to `std::getline`

      You're calling `lowerCase` very often, it'd be better to copy all names in lower case to a  new array and use that new array for comparisons.

  • Sam

    Updated solution

    • - `checkInput`: Unused parameter. If you don't pass a variable to another function, that other function doesn't know about the variable. `std::cin.fail` and `std::cin.clear` don't care about the value.
      - Line 24: '\n'
      - Line 65: `} while (!checkinput(amount));`.

  • Sam

    Here is my solution!

    Also, how do I get a profile picture? Do I just put the image link inside the "Website" box? I'm a bit confused

    • Sam

      Forgot to de-allocate the memory gg

    • - Line 21: Use 1 iterator and calculate `y` inside the loop. Iterating over multiple -variables is harder to follow.
      - `streammax` should be `static constexpr` inside `ignoreCin`.
      - `ignoreCin`: Unused parameter.
      - Remove `valid`, use `checkInput(amount)` as the loop's condition.

      > how do I get a profile picture?
      Register on gravatar with the same email address you're using when you post comments here.

      • Sam

        "`ignoreCin`: Unused parameter." Oh, I thought you had to actually pass in the value so it knows to cin.ignore for that value. Same with checking the input, since I have to send it a parameter of their input and see if it std::cin.fail()'s. I'll try to fix everything else. Thank you for your feedback like usual!

  • Jonathan

    How to change the name from lowercase to uppercase and vice versa? Otherwise, it seems that we can't compare them properly. Also, how to make sure that the name is reasonable (name like 123, #ken#)?

    • > How to change the name from lowercase to uppercase and vice versa?
      `std::tolower` and `std::toupper` in a loop or transformation function.

      > how to make sure that the name is reasonable
      Depends on your definition of "reasonable". If you just want to check if every character is in a whitelist (eg. only letters), loop through the string and see if your whitelist contains that character.

      • Jonathan

        like this?

        • The long switch can be replaced with an if-statement

          If the characters weren't in such a nice group, you could declare an array or string that holds all valid characters an loop through that (Resulting in 2 loops). That way you don't have to write the long switch.

          The name length should be checked before the loop, not inside it.
          Line 80 should print a line feed ('\n').

          • Jonathan

            like this?

            • - Initialize your variables with brace initializers.
              - `exception` should be `const static`.
              - Line 10 can only run to `exceptionLength`.

              Write a function that checks the validity of a single character. That will clear up your code.

              • Jonathan

                So I should separate the 'lowerName[i]' from the 'checkValidity()' function?

                • Exactly. You can now reuse "i" as the name for `j`.

                  Line 3, 4 should be

                  Line 11 can be removed and line 12 moved outside the loop.

                  Line 26+ won't work. `valid` will only be `false` if the last character in the name was invalid, because you're overriding every previous result.

  • Anastasia

    Hi!
    When I run this code with valgrind's memcheck I can see that there were 4 allocs and 4 frees. Does it mean that (the same(?)) heap memory is allocated every time I pass a (copy of) pointer holding address of dynamically allocated memory and freed when that copy goes out of scope and destroyed? Or the fact that it is freed upon the destruction of the pointer's copy means that the memory being allocated is not the same, but only has the content of the original memory copied into it?

    • No copies of the pointed-to memory are made when you pass a pointer.
      I'm not familiar with valgrind's memcheck. I assume it also detects the allocations performed by `std::string::string`. Do you get the same results no matter how many names you create?
      EDIT: It doesn't count allocs my `std::string::string`, 1 moment please

      EDIT2:
      1 alloc seems to be default
      1 alloc is made by `std::cout <<`
      1 alloc is made by `std::cin >>`
      1 alloc is made by `new std::string`

      • Anastasia

        Valgrind is a debugger for Linux. I'm not very familiar with it either, basically just started using it.
        Yes, it is the same no matter how many names I enter.

        Edit: Oh, I see now. Thanks a lot! The fact of having 4 functions there confused me.

          • Anastasia

            Thank you, that would explain it. Are all of them freed when I 'delete' names in main?

            • Anastasia

              That was a stupid question, sorry. It has nothing to do with the memory allocated by the user. 1 alloc is made for the program, I guess it's size would differ from system to system, std::cout and std::cin always take 1 for each, no matter how many times they are being used in the program. And they always manage to free this memory, even if I try to stop the execution before the end of main.

  • RAMBOY

    Hi! I struggle with having too much RAM on my computer so I tried to apply this newfound knowledge to help myself out. I wrote this program (pls don't steal my code for monetary gain I worked very hard on it):

    Unfortunately, it only clogged 2 out of my 8 GB's of RAM! I even launched Minecraft to see how it worked and it didn't really affect the fps at all! Why is that? In all seriousness, I'm curious why didn't my "masterpiece of programming" use up all of the heap memory of my computer (and how to fix that).

  • Samira Ferdi

    Hi, Alex and Nascardriver!

    I write

    instead of

    is it okay?

    • Yes, but you should check if the allocation was successful when you're using `new(std::nothrow)`.

      • Samira Ferdi

        Is it always like that? Checking the allocation was successful or not?
        But, it means that I have to do exception handling?

        • If you're using `std::nothrow` for allocations, you have to check if the allocation was successful. Otherwise you'll be using a `nullptr` somewhere else, leading to a crash. If you don't want to do manual checking, use the throwing version of `new`. That way you know what went wrong when your program suddenly exits.

          > it means that I have to do exception handling?
          `new(std::nothrow)` doesn't throw exceptions. If you use the throwing version, you can handle the exceptions, but you don't have to. Running out of memory is rare (Unless you're compiling in 32 bits, which you shouldn't). You can ignore the exception and it might get printed when your program exits or you can catch it with a debugger.

  • Kristine

    Hi, in the tutorial it says a dynamic array functions the same as a fixed decay array and it doesn't know its length or size. I tested this by printing the size of both. It turns out that the dynamic array gives the size of the elements but the fixed array gives the number of bits. Why would they differ in this? The tested code is below. Thanks.

    • `sizeof(array)` gives you the size of an `int*`, because there is no information about the array.
      `sizeof(myarray)` gives you the size of the array (4 * sizeof(int)), because `myarray` is still an array, it hasn't decayed.

  • 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]