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:

One caveat, in C++11 you can not initialize a dynamically allocated char array from a C-style string:

If you have a need to do this, dynamically allocate a std::string instead (or allocate your char array and then strcpy 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

Leave a Reply

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

  1. Thanks for this site, really enjoy - learned C and C++ almost 30 years ago, then let it fade away...mid life crisis (hah) has me learning again.

    Stuck on something that I swear should be obvious, but I can't seem to understand the following.

    (I just wanted to make a test function to read in one name and put it in the array, and practice passing string / array members around).

    This works

    And this does not (which is what I thought I needed to do first...)

    I get that cin needs an address...so if i make the incoming parm the 'address' it works, but I thought that's what the pointer to the array element was...

    Just not sure I've still understand the difference, and why the called parm version needed an & passed in, but when you did it in main...it was simply  array[index]

    • Remember that operator[] does an implicit dereference. So when you do this: names[i], you're dereferencing the names array to produce a std::string (not a pointer to a std::string).

      In the latter case, to pass an array element by pointer, you need to pass the address of the element, which requires using &: getName(&names[i]).

      In English, this translates as "get the element with index i out of the array names, then pass the address of that element to function getName()".

      • Thanks for the quick reply.

        I can make it work both ways now, is there a preference/best practice?

        Also, restating what you said to ensure understanding.

        In the first example, where getname is defined to accept an address.
           when I called it with names[i] what actually happened was
          
           names[i] dereferenced to a std::string.   It passed that to the function, saw that it expected an address, and just converted it  (?)

        In the second example, where it expects a pointer,
          I need to not send a std::string, but the address of it, (which the function accepts as a pointer back to the memory that has been allocated for that string in that array position..)

        (I got the code working both ways...but just want to make sure I got this in the noggin...memory serves, will be sending a lot of things via their address(structs, etc), and getting * and & straight is critical).

        • You should generally only pass by address when you're passing something that's already a pointer. The elements of the arrays aren't pointers, so you're better off passing them by reference than passing their addresses and having to explicitly dereference them in the function.

          I talk more about this in the beginning of chapter 7.

  2. Hi Alex, thanks a lot for your awesome tutorial. Do you have any idea why my program crashes when it tries to delete the array?

    here is my code:

    This is the error that comes up when I debug the program:

    Hope you can help me.
    Cheers!

    • I'm not sure why this is crashing, but I can definitely reproduce the crash. The offending line is the for statement as part of this code snippet:

      The last iteration of this loop accesses names[numNames], which is off the end of the array.

      When I fixed that, the crash went away.

      • Never thought that would be the problem, but it makes totally sense! Thanks a lot for your reply, and keep up the good work with your tutorial! Without doubt what got me best started in c++

  3. Hi Alex,

    I think I have misunderstood something fundamental about the connection between pointers and arrays. Consider the following code:

    int *array = new int[5];
    array[0] = 9;
    array[1] = 7;
    array[2] = 5;
    array[3] = 3;
    array[4] = 1;

    From what I understand, new int[5] returns a pointer that point to the memory address of an array of length five. The pointer 'array' now holds that address. Why does the pointer 'array' not need to be dereferenced before changing the value of one of its elements?

    Thanks so much for these awesome tutorials!

    • > Why does the pointer ‘array’ not need to be dereferenced before changing the value of one of its elements?

      It does! And you can do so in one of two ways:
      Explicitly: *(array + index) = 5;
      Implicitly: array[index] = 5;

      The thing you're probably missing is that the subscript operator ([]) does an implicit dereference.

  4. Alex, any way to print the array element the user inputs? This is what I have so far:

    • Try something like this:

  5. Are you sure today's compilers won't compile if the size of a fixed array it's not known at compiler time? I've tried it in my KaOS, using g++ -std=c++14 and it totally let me do it.

    • I didn't say compilers won't do it, I said it's not a part of C++ standard. Some compilers still support it for backwards compatibility with C99's Variable Length Arrays (VLA) feature. Until they're officially a part of the C++ standard, I recommend avoiding them.

  6. Hello Alex, thanks for your great tutorial, but I'm a little confused, if dynamic array means it can have a length based on user input at runtime, doesn't it can be done without dynamic memory allocation? maybe like this:

    • Nope, not yet (as of C++14). There have been various proposals to add sometime similar into both C++11 and C++14 but so far it hasn't made it. Maybe we'll see it added in C++17.

      Note that some compilers will let you define and use these anyway (largely for C99 compatibility). I recommend you avoid using those, as they are not part of the C++ standard.

      • Thank for reply, my compiler is GNU GCC compiler. I will try others latter. By the way, I used following code, and got identical result for both array1 and array2.

  7. Is it bad if I make sort loop inside infinity loop like this instead of lopping it specific amount?.

  8. Why is it that when I write something like this:

    Then set length equal to something like 10, the first 5 elements are initialised to what I have put in the curly brackets, but the last 5 elements are set to 0. When I don't add the initialiser list, all the elements are set to null or nothing. The last 5 elements should be set to null, shouldn't they?

    • If you don't use an initializer list, C++ assumes you don't want any elements of the array initialized, so it leaves them alone (and you end up with garbage values). If you do use an initializer list, C++ assumes you're intending to initialize all your elements, so any elements that you don't provide initialization values for, it sets to a zero-value (0 for int, 0.0 for floating point, etc...).

  9. Typo:

    you learned that a fixed arrays holds the memory address of the first array element

    I think you meant to say "array holds"

    Thanks!

  10. I'm a bit confused about memory requests for dynamic string arrays. I get with other types of arrays you can know how much memory to request just by knowing how many values the array will hold; but string doesn't have any set size, so how can memory be requested just by knowing the number of values the array will hold?

    I experimented a bit and noticed that no memory was being reserved for a dynamic string array unlike with an dynamic integer array where I noticed that the memory needed for the array was immediately reserved. However I also noticed that setting the size of my dynamic string array past a certain threshold would cause the application to crash; and that calling sizeof on any value in the array always returns 28 even if the string is longer than 28 characters.

    • std::string does have a set size, actually.

      If you run the following program:

      It will tell you how big std::string is. And as you've already noticed, at least on your Visual Studio, it's 28 bytes.

      So when you do something like this:

      You're allocating a dynamic array of 5 empty strings, which will reserve 5 * 28 = 140 bytes of memory.

      Here's something interesting: The sizeof() an empty std::string is the same as the sizeof() a std::string that is holding an actual string! And you can prove it:

      This prints 28 for both. This might surprise you at first, but it makes sense when you understand why.

      If you look at what std::string looks like internally, you might see something like this:

      When you take the sizeof() this structure, it adds up the size of all the data members, which equals 28 regardless of what the pointer is pointing to! In other words, sizeof() includes the size of the pointer itself, but not the size of any allocated memory the pointer is pointing to.

      Therefore, when we allocate an array of 5 std::string, we can always just allocate 140 bytes, and later on, when we set a value to any of those strings, the pointer inside the string will have some memory allocated for it. This allocated memory happens outside the array, so it doesn't impact the size of the array.

  11. Hello Alex,

    I have a question to ask. I have two pointer arrays, int *x, and int *y. Each pointer array has eight elements for x and y respectively. the value of these arrays are allocated int x = new int [numberofVals], where numberofVals = 10; and int y = new int [numberofVals]. Each element of x, and y, i.e. x[f], f = 0,1,2...(numberofVals-1), has eight sub values for x. I wanted to access one of the subvalues of x and y. When i type x[f][2] or y[f][2], i get error "subscripts must be array or pointer type", how do i access the subvalues of x and y ? I hope my question makes sense

    • >the value of these arrays are allocated int x = new int [numberofVals], where numberofVals = 10; and int y = new int [numberofVals].

      Ok, good so far.

      > Each element of x, and y, i.e. x[f], f = 0,1,2…(numberofVals-1), has eight sub values for x

      No, they don't. You've allocated your arrays as single-dimension arrays, so you can only index them once. The compiler is complaining because x[f] or y[f] resolves to an integer, and you can't use operator[] on an integer.

      If you want an array of arrays, then you need to dynamically allocate a multidimensional array. I talk about how to do this in the lesson "6.14 -- Pointers to pointers".

  12. In the quiz solution, I was curious why you chose to use auto type deduction in the for loop initializers, rather that just explicitly use "int".

    • I'm not sure, there doesn't seem to be any compelling reason for me to have done so. I've gone ahead and updated the solution to explicitly use int, since there are just simple counting loops.

  13. Under "Dynamic arrays are almost identical to fixed arrays", you wrote:

    "A dynamic array starts its life as a pointer that points to the first element of the array. Consequently, it does not know the length of the array it points to. But otherwise, it works identically to a decayed fixed array, except that the program itself is responsible for deallocating it."

    I think the paragraph would make more sense if you took the words "but otherwise" out of the equation. "But otherwise", to me, seems to suggest that a decayed fixed array DOES know the length of the array it points to. (sorry about the caps... I don't know how to use italics). Or am I just misunderstanding something here?

  14. why does this not work:

    my compiler says "array size in new-expression must be constant"

  15. Typo:
    The phrase "... fixed array can decay into a pointers ..." should probably read ".... fixed array can decay into a pointer ...".

  16. If i want to put...e.g Player coordinates from a 3D game(x, z, and y coordinates) into an array would you do it with an fixed sized array or std::array class and simply set the size to 3, or would you allocate the array dynamically? I guess it is not necessary to do it dynamically, right? Because array length won't change.

    • Array length won't change, so you might as well do it as a fixed size array or std::array of size 3. Enumerators would be useful here (so you know what the array elements represent).

      Alternatively, you could use a struct, which is probably a better way to go.

  17. Hi Alex! I need your help. I wrote the code below and everything goes well till I enter the last name, at that time Windows gives me an "Assertion error" o.O anyway the names are sorted and printed in the console. I check and recheck the code but I could not find the error.

    ----------------------------------------
    Debug Assertion Failed!

    Program: …15\Projects\ConsoleApplication1\Debug\ConsoleApplication1.exe
    File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
    Line: 888

    Expression: _CrtIsValidHeapPointer(block)

    For information on how your program can cause an assertion
    failure, see the Visual C++ documentation on asserts.

    (Press Retry to debug the application)
    ----------------------------------------

    Many thanks in advance!

    • In cases like this, I find commenting out code can help isolate where things aren't working. For example, I commented out getNames(), sortNames(), and prntNames(), and your program still crashes. At that point, I realized the problem had to be in main(). Then I noticed that you used non-array delete for an array. You should be using delete[].

  18. Thank you every time. I have 2 question!

    1)when I solve this quiz, I used 'struct Name' containing 'arrayNum'(int) and 'arrayList'(std::string*). I delivered struct variables(myName) between functions. Could this approach  cause future mistake?? or I can just get used to using it?

    2)In 'Dev-C', if I drag some lines at the source code and press 'ctrl + /' the whole line became comment(adding '//' at front). Is there any such keys in visual C++? I have hard time when changing lines into comment for testing.

  19. I have trid to sort this dynamically allocated array using this code:

    but i get an error.Can you tell me what is wrong?

    • Seems like a good thing to use the debugger to determine.

      Just eyeballing your code, it looks like you're allocating an array with elements 0 through size-1. But then you're looping until <= size-1, so the last loop iteration will have i2 = size-1. And then you're swapping elements i2 and i2+1, which would be size-1 and size. Element size is off the end of your array.

  20. Hi Alex,
    I cannot figure why the code below becomes an infinite loop if I enter a non-integer.

    Thank you for your time.
    Btw, are you the same Alex as the Alex Allain in cprogramming.com (just wondering)

    • When you enter a character the istream (cin) error bit gets set as the numName variable is an integer type.   As this error bit/flag is set my guess is that the "ignore" function is itself ignored. Your while loop evaluates to true as cin.fail() is true at this point regardless of the (garbage) value of numName. The "clear" function resets the cin error bit/flag. However, as the cin buffer hasn't been ignored the input stream is likely reading a null character (I think). This causes the cin to fail again, and we go round the loop infinitely.

      To solve do the following:

      We clear the error flag after the cin input and, crucially, before the ignore function. Note that I've also removed the fail function from the while condition as it is now redundant. Also note I've initialised the variable numNames to the fail case (i.e. zero). Without this numNames will be initialised to whatever was hanging about in memory at the time, which could be a very large positive integer; if cin fails the variable retains the value it had before input was attempted. You may want to add an if conditional to output some text if a user tries to enter a character instead of a number (and/or a number less than one).

      • Thank you both for the reply.
        I assumed that an input causing failure mode would not affect std::cin.ignore from clearing the buffer (I guess that is where my logic was wrong due to an incomplete understanding).

        Thank you Alex for this site because I am learning a lot from it but
        is there a website or book that you recommend that I can do more in depth reading?  I don't want to trouble you every time a problem comes along.

        Thanks.

        • I highly recommend Stack Overflow website for questions and answers, as well as Google's search engine. Most questions I answer here have probably been answered elsewhere -- if you can find the right search query. 🙂

  21. Why in the quiz solution there is no need to inculde <algorithm> (for std::swap)?

    And why it's unnecessary to include <string>? It seems work the same way with and without it.

    • I'm not sure, it could be another header you're including is using those itself. Or it could be your compiler is throwing them in. Don't rely on this.

  22. Hello, awesome tutorial as always! One question:
    I noticed that it's possible to use universal initialization in a sort of "nested" way:

    Is this considered "bad"? I've been trying to use universal initialization wherever possible, but I'm not sure where I should draw the line and use a normal =.

    Thanks!

    PS: compiled in Visual Studio 2015

    • I've never seen anybody do things that way, but if it works, I don't see anything wrong with it either.

  23. I tried using getline instead of cin to get names with space e.g. "Tim Jones". I got into an infinite loop. Is this because of the space between the names, and why?

    • I didn't get an infinite loop when I ran this. Not sure why you would. You should be using getline here since you want the space to be part of the input value.

  24. I am getting segmentation fault (core dumped) error after execution the code? Code shows the sorted output but at the end throws error. What is segmentation fault? How to avoid it?

    • A segmentation fault means your program crashed.

      This is happening because you've used <= instead of < in your loop that prints the names, thus accessing memory outside of the Names array (which probably belongs to another process, since Names is dynamically allocated).

  25. hey guys im stuck a bit... something is making my for loop skip the first input. but using cin before the loop is normal ( cin allows input before the loop)... but when the loop starts it skips asking for the 1st name and adding std::cin.ignore(32767, 'n'); before the loop fixes it. what character are there left in the cin buffer before the loop ? is it 'n' ? how is this ?

    std::cout <> numberOfNames;
    std::string *nameList = new std::string[numberOfNames];

    //std::string garbage;
    //std::cin >> garbage;
    //std::cout << "Garbage : " << garbage << std::endl;

    std::cin.ignore(32767, 'n');

    for (int iii = 1; iii <= numberOfNames; ++iii)
    {
    std::cout << "nEnter name #" << iii << "t: ";
    std::getline(std::cin, nameList[iii - 1]);
    }

    std::cout << "nn";

    for (int iii = 1; iii <= numberOfNames; ++iii)
    {
    std::cout << "for name #" << iii << " you have entered t: " << nameList[iii -1] << std::endl;
    }

    delete[] nameList;
    nameList = nullptr;

    • I presume you're trying to read numberOfNames in first, which is an integer. When you extract the integer, the '\n' stays in the input stream. Then when you go to read a string, it thinks you entered an empty string, so it extracts the '\n' to the first name and goes on its way. Using the ignore statement gets rid of that extra '\n'.

      This is one of the reasons why I think C++ I/O is really subpar. Mixing input of numbers and strings should "just work", and it doesn't.

  26. Hi Alex,

    I've read above in one of your comments where you say something along the lines that it's good to allocate and free memory in the same function but it's not always possible.

    Now, I did the quiz above and this is my main function:

    In the above code, getNames(.) dynamically allocates a string array and returns it, so <names> is now pointing to the array on the heap.

    In my opinion, it looks well-structured, except for the freeing memory bit at the end. It kind of looks out of place without an explicit <new> declaration. Would the above be "acceptable", or should I make my <new> declaration in the main() function?

    Thanks for the great tutorials!

    • This is fine, you just need to remember that getNames() is returning dynamic memory and the caller is responsible for cleanup. It's a little easier to see if the function explicitly does the new itself, but not enough to make it a rule. 🙂

  27. I don't understand how `delete[]` is able to deallocate an arbitrary amount of memory at a pointer without knowing how much was allocated at that address in memory. Unlike a higher level language like js or python, the length of the array is not embedded in the array itself. How does `delete[]` make this inference?

    • Good question. When you allocate an array, the allocator function keeps track of how much memory was allocated. When you then do a delete[], that information is recalled, so it knows how much to delete. If you do a delete (non-array) instead, this information isn't leveraged, which will result in a memory leak.

      Why this array size information isn't made accessible beyond the allocator, I'm not sure.

  28. Hi, Alex
    Excellent explanations in this tutorial. Thanks a lot.
    I am using Code::Blocks 13.12, and follow is my code for the quiz. It works fine.
    As you see, in each function it is declared dynamic memory allocation, but it is used delete[], and ptr = 0 only in main function.
    My complains:
    1. Is it to be used delete[], and nullptr in the body of each function when dynamic memory allocation is declared?
    2. I tried to use nullptr, but it is not compiled. Any suggestion, please?
    [

    #include <iostream>

    using namespace std;

    void writeNames (string *wNames, int sasia); //prototype
    void readNames(string *rNames, int sasia);
    void sortUp(string *upList, int sasia);
    void sortDown(string *downList, int sasia);
    {
    code for each function ...
    }

    int main()
    {
        int quantity;  // length of array
        cout << "How many names? " << '\n';
        cin >> quantity;
        string *ListOfNames = new string[quantity](); //allocate array and initialize to 0
        writeNames(ListOfNames, quantity); //write list
        readNames(ListOfNames, quantity);//read list
        sortUp(ListOfNames, quantity);  // by alphabetic order
        sortDown(ListOfNames,quantity); // descend order

        delete[] ListOfNames;
        ListOfNames = 0;  // not compiled when nullptr???

        return 0;
    }
    ]

    • It's good if you can allocate and deallocate memory in the same function, but this isn't always possible.

      If you can't use nullptr, it sounds like C++11 functionality is turned off. Revisit lesson 0.5 for instructions on how to check and turn it on.