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.

The length of dynamically allocated arrays has to be a type that’s convertible to std::size_t. We could use int, but that would cause a compiler warning when the compiler is configured with a high warning level. We have the choice between using std::size_t as the type of length, or declaring length as an int and then casting it when we create the array like so:

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, fixed arrays can also be initialized using uniform initialization:

Explicitly stating the size of the array is optional. Doing so can help catching errors early, because the compiler will warn you when the specified length is less than the actual length.

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

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 time


Question #1

Write a program that:
* Asks the user how many names they wish to enter.
* Dynamically allocates a std::string array.
* Asks the user to enter each name.
* Calls std::sort to sort the names (See 6.4 -- Sorting an array using selection sort and 6.8a -- Pointer arithmetic and array indexing)
* Prints the sorted list of names.

std::string supports comparing strings via the comparison operators < and >. You don’t need to implement string comparison by hand.

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

A reminder

You can use std::getline to read in names that contain spaces.

Show Solution


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

653 comments to 6.9a — Dynamically allocating arrays

  • faraz javed

    can anybody help in this
    Write a program that moves an asterisk ‘*’ in a grid of 10x10 cells. Your program should
    start with * on position (2,3) i.e. 3 rd column of 2 nd row. After printing the grid and ‘*’, your program will
    ask user if he wants to move the ‘*’ Up, Down, Left or Right. If user presses ‘U’, ‘D’, ‘L’ or ‘R’, your
    program will move the ‘*’ one position accordingly. If user presses ‘Q’, your program should terminate
    otherwise keep taking input from user and move *.

  • AlMu

    Is there a reason why the the User inputs the number of names as a type 'int' which is then static_cast to 'std::size_t', instead of  entering the number as type 'std::size_t' in the first place?

    Secondly, is there any benefit to calling std::cin.ignore in the getNames() function rather than immediately after the std::cin call in the getNameCount() funtion?

    • nascardriver

      There was no good reason not to be using `std::size_t`, lesson updated.

      `std::cin.ignore()` is called before using `std::getline()`, because otherwise we'd have to rely on everyone cleaning the stream after they're done using it. That's a poor assumption. If we need to be sure the stream empty, we need to clean it before using it.

  • allright

    auto* or auto for pointers is there a difference or which one do you suggest? thank you

  • hmmmm

    I really need to understand this line, specifically

    any help please? Yes i searched about it in google and cppreference, but still can't get it.

    • nascardriver

      returns the maximum value that type `T` can hold. `std::streamsize` is used by `std::cin` to store the size of the internal buffer.

      is the maximum size that `std::cin`'s buffer could possibly have.

      To `std::cin.ignore()`, this value has a special meaning. It causes everything up to the next '\n' to be ignored, ie. the character count check is disabled.

      • hmmmm no more

        WOW, that explains a lot. So it is just

        but we are anticipating that the user might enter really large numbers, so use this formula

        Pretty neat for me as a beginner :D
        As always, much obliged.

  • Daffy

    First crack at solution, it involves some pointer arithmetic.

    • nascardriver

      Your loop can be simplified to

      In line 34, you can use `auto` to get rid of the redundant type name.

  • ORK RAHMAN

    hi,
    how can i solve it by  Using the new operator, allocate an integer array of user specified size (the user gives the size of the array as
    input). Assign values to the array elements by taking user inputs and then print the values. Finally de-allocate the array
    using the delete operator.

    hope you'll help !!!!

  • Joshua

    Now, my question is really about best practices. I recall that a function should do one thing only... So, I've attempted to follow through with that. But following that approach always seems to blow up the code for me. Maybe seeing simple solutions just takes time and practice, but I always feel like I'm dividing up operations over too many functions. Am I? Also, have I screwed anything obvious up?

    • nascardriver

      Try to keep allocation and deallcation in the same function. It's too easy to lose track of who own memory when these things happen in different functions. If you don't intend to modify something, especially pointers and references, make it `const`.
      " " is a single character, it should be ' '.

      To your function splits, you have 2 functions with a 1 line body (`sortDynamicArrayOfStrings` and `createArray`). These function don't add value to your code, they're just a different name for something that was there before. The other functions are good :)

  • Innervate

    This was my attempt at the quiz:

    When I tried using the example from chapter 6.4:
    std::sort(std::begin(Array), std::end(Array));

    I got an error: "No matching function for call to 'begin'. No matching function for call to 'end'."

    How would I be able to use std::begin and std::end?

    • nascardriver

      You can't use `begin` and `end` on dynamically allocated arrays, because they don't have size information. Without size information, there's no way to tell where the end is. Calculating begin and end manually as you did is the correct approach.

  • Sonia

    Hello,

    Would you please check my solutions too?

    • nascardriver

      Hello

      - i++ should be ++i. i++ is slower.
      - Use array syntax to access array elements. Doing so allows the compiler (and other static analysis tools) to better understand what you're doing and maybe print warnings if you're doing something wrong. (`pString[i]`)
      - Your memory management is all over the place. There's no way for the caller of `printNames` to know that it deletes `pString`. Try to keep `new` and `delete[]` in the same function so that it's obvious where the memory comes from and where it dies.

      • Sonia

        Thank you so much.

        >> There's no way for the caller of `printNames` to know that it deletes `pString`. Try to keep `new` and `delete[]` in the same function so that it's obvious where the memory comes from and where it dies.

        What is the problem when the caller of `printNames` doesn't know that it deletes `pString`, while it is deleted in 'printNames' function?

        • nascardriver

  • rupp_bin

    can someone tell me why my code is not working at get_names function its asking two names at a time instead of one

    • Matt

      I had the same issue. You need to clear out the std::cin buffer before accepting text. Try this:

      void get_names(std::string* names,int num){

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

      for(int i=0;i<num;i++){
      std::cout<<"Enter name "<<i+1<<":";
      getline(std::cin,names[i]);
      }

      • rupp_bin

        Thank you bro,if you don't feel like iam annoying you.i have one more doubt actually its working with cin,can i know whats wrong with  getline

  • Cuong Nguyen

    Sorry. I have some questions:
    Is that dynamic array is similar to the array just different in:
    1. static array is stored in stack and dynamic array is stored in heap.
    2. static was created at compile time and dynamic at runtime.

  • qwerty

    Hi!

    1.In the solution at the `printNames` definition, the function has this parameter : `std::string* names`, my assumption is that `names` points to the location of the first character in the array, the character is not known at that time, so the pointer points at the address of where that character should go. Right?
    2.I've watched at the names[0] variable in the VS Watch Window before the std::cin, and at the `value section` is just `""`. Shouldn't it be what's currently stored in the address?

    Thanks!

    • nascardriver

      `names` points to the first element of the array. The first element is a `std::string`. When `printNames` is called, the value is known.
      In line 43 of the solution, the entire array is initialized with {}, which causes every element to be initialized to a default value. For strings, that's "".

  • RJ

    I have a question about the std::cin.ignore(220, '\n') line. When i run this program i'm allowed to enter the number of names and the strings for each element, but the line std::cin.ignore(220, '\n') creates a empty new line in the compiler, and any input i enter is thrown away. I understand ignore is being called but is it normal for it to try to take input from the user? I know this can be fixed just by moving the std::cin.ignore(220, '\n') line before the loop so it gets rid of the lingering '\n' in the std::cin buffer from entering the integer, but I just want to make sure I understand what is happening under the hood.

    • nascardriver

      When you use a function of `std::cin` and there is no input in `std::cin`'s buffer, it will prompt you to enter something.
      `std::getline` eats up everything in the buffer, including the line feed, so when you can `std::cin.ignore`, the buffer is empty and you are prompted to enter something. That something is then ignored.

  • Yolo

    A question about std::sort

    Does it take as parameters the addresses or the values of  'names' and 'names+length'?

    • nascardriver

      `std::sort` takes iterators as arguments. For built-in arrays, iterators are pointers.
      We cover iterators later in this chapter.

  • bury

    I have a question about this part,
    how come you don't have to dereference "array[0]" here in order to assign a value?

  • Nguyen

    Hi,

    Quiz #1
    .
    .
    . Calls std::sort to sort the names (See 6.4 -- Sorting an array using selection sort and 6.8a -- Pointer arithmetic and array indexing)
    .
    .
    Solution:

      // Sort the array
      std::sort(names, names + length);

    I remember clearly that we did have something similar to std::sort(names, names + length) mentioned somewhere in 6.4.  We used it here in our solution as shown in line 48.  I went back to 6.4 to look for it, it was not there. Maybe I am wrong!  Did we see that line in the previous chapters?

    • Nguyen

      So far I've seen std::sort(array, array + length) and std::sort(begin(array), end(array)).
      I first thought they would always work the same, but my program proved I was wrong.
      Could you please explain the differences between those std::sort?

      • nascardriver

        `array + length` only works because `array` is a pointer, so you can use pointer arithmetic. A `std::vector` has no + operator.
        `std::begin` and `std::end` call `std::vector::begin` and `std::vector::end` (Or the `begin` and `end` functions of the type you're passing in, whatever the type may be), or they calculate the begin and end of an array if you pass in an array.

    • nascardriver

      In lesson 6.8a towards the end, there's

  • CvB

    Hi Alex and nascardriver, I'm enjoying you tutorials very much. Your website got me incredibly excited about learning C++. As this chapter goes on though, I feel it's getting away from me. Because of the introduction of lots of complex concepts and because in the solutions to the quizzes, some features of C++ are used which I don't seem to grasp from the lessons that came before. For example in this quiz:

    - The use of std::sort - without the solution, I wouldn't have guessed this is the way I have to use it. The chapter referred to in the text, doesn't contain the syntax used in the solution here. (I loved trying to build the bubble sort though!)
    - The use of static cast string and size_t - in this chapter an array with a string is initialized as a char. In the quiz it is auto and then static cast as a string. I couldn't have known this was necessary (I think!) and I wouldn't have thought about using an unsigned int, because from the preceding tutorials, I have little experience with it.
    - The use of getline - it's been a while back this was covered, a hint that this would be handy, would be nice.

    Basically I feel that the quizzes, requiring these small, but important things, but not highlighting/hinting at them, detract from the main lesson you're trying to teach. Please correct me if these things have been sufficiently covered and I'm just being obtuse.

    • nascardriver

      Hi!

      > std::sort
      Lesson 6.4 shows `std::sort` with `std::begin` and `std::end`, but lesson 6.8a shows how begin and end can be calculated for dynamically allocated arrays.
      I added a note to lesson 6.8a saying that the calculation shown therein works for all algorithms.

      > static_cast/auto
      Either you're talking about something I don't see or you misunderstood the cast in the solution, or I misunderstood you.
      What you'd probably write

      We didn't cast the array, only the index. `auto` isn't used in the lesson, because the types ("int", "char") can be typed just as quickly as "auto".
      I updated the first example in this lesson, because it was using an `int` to allocate the array. I also added a note about the cast and use of `auto`.

      > getline
      I added a reminder to the quiz.

      Thanks for your detailed feedback, it's greatly appreciated! If there's anything else you think is missing, please let us know.

      • CvB

        Thanks nascardriver, I'm glad you appreciate the feedback. With your explanation of my static_cast/auto question above, it's much clearer. It's just the amount of things going on in that line that threw me off. I can imagine that happening to other budding coders as well.

        Thanks for your quick actions and I'll let you know if I find anything else!

  • krankk

    Any feedback would be appreciated.

    • nascardriver

      - There's no reason to pass `size` as a pointer. It's more dangerous and slower.
      - Don't use `std::endl` unless you need to. It's slow.
      - Use ++prefix unless you need postfix++. Postfix++ is slower.
      - Initialize variables with list initialization for higher type safety.

      • krankk

        Thank you for the help

        Don't use `std::endl` unless you need to. It's slow.
        -> I needed it for debugging since "<< '\n'" doesnt actually print in the console, had some funky cases where a Line in the Array would go missing

  • Robbie Williams

    Sorry, I know you guys must get loads of questions, but just a quick one. Why in the quiz do you static_cast the int with the number of names to size_t?

    Is it just to specify that it's referring to a size specifically or because we want to make sure it is positive and size_t is unsigned? Is there anything wrong with just this?

    Thanks in advance and I love these tutorials, they are a massive help :) Thanks a lot.

    • nascardriver

      Hello

      The array size has to be a type convertible to `std::size_t` (Which is some unsigned integer type). Without the cast and a high enough warning level, you'll get a warning, because an implicit conversion from signed to unsigned is taking place. The cast silences this warning.

  • Bill Lasher

    Hi:

    I am using the g++ compiler and it seems I am able to dynamically allocate an array without using pointers.  What's going on?  The following code works:

  • buku

    guys i like very much your learning and appreciate your efforts but i have to point something...
    i think using uniform initialisation with primitive type everywhere is a bit odd and sometimes confusing and just look this ugly suntax
    [int *array{ new int[length]{} };]
    regards

  • Ian

    Hi! Could you give me some feedback about the code below?
    The second function getNames() is a little bit different from yours.
    Thanks a lot!

    #include <iostream>
    #include <string>
    #include <algorithm>

    int getNumberOfNames()
    {
        std::cout << "How many names would you like to enter? ";
        int numberOfNames{  };
        std::cin >> numberOfNames;
        return numberOfNames;
    }

    std::string* getNames(int numberOfNames)
    {
        std::cin.ignore(32767, '\n');
        std::string* names{ new std::string[numberOfNames]{} };
        for (int count{}; count < numberOfNames; ++count)
        {
            std::cout << "Enter name #" << count + 1 << ": ";
            std::getline(std::cin, names[count]);
        }
        return names;
    }

    void sortAndPrintNames(std::string *names, int numberOfNames)
    {
        std::sort(names, names + numberOfNames);
        std::cout << "Here is your sorted list:\n";
        for (int count{}; count < numberOfNames; ++count)
        {
            std::cout << "Name #" << count + 1 << ": " << names[count] << '\n';
        }
    }

    int main()
    {
        int numberOfNames{ getNumberOfNames() };
        std::string* names{ getNames(numberOfNames) };
        sortAndPrintNames(names, numberOfNames);
        return 0;
    }

    • nascardriver

      Hi!

      Please use code tags when posting code.
      [-code]
      your code here
      [-/code]
      without the -.

      Returning dynamically allocated objects from a function is dangerous. The caller of the function doesn't know that the returned pointer points to dynamically allocated memory, so they're likely to not delete it, which leads to a leak. You fell for your own trap.
      If you allocate memory dynamically, try to structure your code such that `new` and `delete` are called from within the same function.

      The rest looks good :)

      • Ian

        Thanks for the feedback.
        Let me try posting...
        I don't think I figure out how to post...

        [-code]
        #include <iostream>
        #include <string>
        #include <algorithm>
        int main()
        {
            int numberOfNames{ getNumberOfNames() };
            std::string* names{ getNames(numberOfNames) };
            sortAndPrintNames(names, numberOfNames);
            return 0;
        }
        [-/code]

        So, what's wrong with my posting...?

        • Ian

          I got it...
          Thanks a lot! :D

  • Ankit

    if there is no default ctor for a class then how do we pass argument such that those arguments will be used to construct all the objects?

    • nascardriver

      You can't easily do that without initializing each element by hand. Use a `std::vector` instead (We talk about vectors later).

  • nascardriver

    Line B doesn't initialize the elements of the array. In line A, all elements are 0. Use list initialization, it works almost everywhere and is safer.

  • mesut

    Hi. Can we use line B instead of line A?

  • Gabe

    Quiz

  • Ambareesh

    I had a strange problem with taking user inputs while solving the quiz here:

    Case 1

    This caused the output to look like this:

    Enter name #1 : Abu

    Enter name #2 : Appu

    Enter name #3 : Abe

    Here's your sorted list:
    Name #1: Abe
    Name #2: Abu
    Name #3: Appu

    That is, I could only give the next name after pressing Enter twice. Once after entering the name, and then once more

    Case 2:

    This caused the output to look like this:

    How many names would you like to enter? 3
    Enter name #1 : Abu
    Enter name #2 : Appu
    Enter name #3 : Abe

    Here's your sorted list:
    Name #1: Abe
    Name #2: Abu
    Name #3: Appu

    So here everything worked normally. I only had to press Enter once to get the names.  Why did this happen? How exactly is std::getline taking in values from std::cin ?

    • nascardriver

      `std::getline` reads an entire line, including the trailing line feed.
      If you call `std::cin.ignore` and there is nothing in the input stream, it will prompt for input. Just like `std::cin` prompts if the input stream is empty.

  • Please can you tell what is wrong with this code its says:
    internal compile error in line 7

    • nascardriver

      Get a new compiler. There's no error in your code and your compiler shouldn't crash.
      If you can't get a new compiler, copy the string into the array after creating an empty array.

      • i am using Visual Studio which other compiler should i use::

        • nascardriver

          You're out of luck then, I can't recommend you a better compiler for Windows. As an alternative solution to my suggestion before, if you don't mind typing, you can use the array syntax.

  • Dudz

    :)

  • Sinethemba

    Hi nascardriver.

    Please see my solution below. Any feedback would be highly appreciated.

    • nascardriver

      Hi!

      - `getNumberOfUsers` allows negative `length` values. You probably meant to use `||`.
      - If you use the `nothrow` version of `new`, handle allocation failures.

Leave a Comment

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