Newebe question abot new operator

Need help with C, C++, perl, python, etc?

Newebe question abot new operator

Postby pythagorasmk » 2019-05-30 21:19

I am learning C++.
If I want to declare pointer to array I will use:
int (*p)[10];
but if I want to declare array of pointers I will use:
int *(p[10]);
But if I use new operator there is no variable name, like p, instead of that I must write:
x = new int *[10];
The question is: how compiler is determining the size of the memory allocated by this statement, is it array of pointers or is it pointer to array. Also how can I force compiler to interpret the meaning of int *[10] to my needs?
pythagorasmk
 
Posts: 39
Joined: 2015-01-18 03:40

Re: Newebe question abot new operator

Postby neuraleskimo » 2019-05-31 00:39

pythagorasmk wrote:I am learning C++.
If I want to declare pointer to array I will use:
int (*p)[10];
but if I want to declare array of pointers I will use:
int *(p[10]);
But if I use new operator there is no variable name, like p, instead of that I must write:
x = new int *[10];
The question is: how compiler is determining the size of the memory allocated by this statement, is it array of pointers or is it pointer to array. Also how can I force compiler to interpret the meaning of int *[10] to my needs?

Good question. When you tell operator new that you want to allocate an int or array of int's, operator new allocates memory for one or more int's and gives you the address.That is, the return is an address to memory containing int's. When you tell operator new that you want an array of int*'s (e.g., new int* [10]), operator new allocates memory for one or more int*'s and gives you the address. That is, the return is an address to memory containing int*'s. Notice how operator new always gives you an address. When you deference that address, you can access the contents. In the first instance, the contents will be an int and in the second the contents will be an address (that you may also deference). Now, the tricky part is that when returning a address to memory containing addresses, you would say (and write) the type is int** (an address to an address). If this is confusing, most people feel that way when approaching pointers for the first time. If you want, I can write a short version of a lecture I used to give on demystifying pointers and references. Returning to your question... When you type a number (e.g., 10) in brackets after new, the compiler will allocate sizeof(type) * number. In your case, sizeof(int) * 10 = 4 * 10 = 40 bytes or sizeof(int*) * 10 = 8 * 10 = 80 bytes.

Try the code below and don't hesitate to ask questions. Hope this helps...

Code: Select all
#include <array>
#include <iostream>
#include <memory>
#include <typeinfo>
#include <vector>

#define PRINT_INFO(p) \
    std::cout << "for \"" << #p << "\" the size is " << sizeof(p) \
        << " and the type is " << typeid(p).name() << "\n"

int main()
{
    std::cout << "Hello, World!\n";

    // What is the size of int on your platform?
    int x = 0;
    PRINT_INFO(x);
    // probably 4 bytes

    // What is the size of an int*?
    int* p1 = (int*)(0x12345678);
    PRINT_INFO(p1);
    // 8 for a 64-bit platform

    // What is the size of an array of ints?
    int p2[10];
    PRINT_INFO(p2);
    // should be 10 * 4 = 40 bytes

    // WHat is the size of an array of 10 int*'s?
    int* p3[10];
    PRINT_INFO(p3);
    // should be 10 * 8 = 80 bytes

    // What about an array of ints and int*'s created via operator new?
    // The compiler knows the type because we say so.
    auto p4 = new int[10];
    PRINT_INFO(p4);
    delete [] p4;
    auto p5 = new int*[10];
    PRINT_INFO(p5);
    delete [] p5;
    // Can you guess why sizeof() is different for p2/p3 and p4/p5?

    // It is good to learn about pointers, new, and delete, but I would rather
    // see you do the following in real code...
    auto p6 = std::make_unique<int>(1234);
    PRINT_INFO(p6);
    // or this ...
    auto p7 = std::make_shared<int>(1234);
    PRINT_INFO(p7);
    // Can you guess why p7 is bigger?

    // or better yet....
    std::vector<int> dynamic_array {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // for arrays you want to grow/shrink
    std::array<int, 10> static_array {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // for arrays that don't change size

    return 0;
}
User avatar
neuraleskimo
 
Posts: 113
Joined: 2019-03-12 23:26
Location: Bloomington, Indiana, USA

Re: Newebe question abot new operator

Postby pythagorasmk » 2019-05-31 10:58

neuraleskimo wrote: Returning to your question... When you type a number (e.g., 10) in brackets after new, the compiler will allocate sizeof(type) * number. In your case, sizeof(int) * 10 = 4 * 10 = 40 bytes or sizeof(int*) * 10 = 8 * 10 = 80 bytes.

Try the code below and don't hesitate to ask questions. Hope this helps...

What is the syntax for new operator. I am reading "jumping into C++" but there is no explanation of the syntax of the new operator, only few examples.
Lets say i have declared p with:
int (*p)[10];
how can I allocate memory with new operator for the variables of type p. Obviously:
int (*(*x))[10] = new int *[10]; //WRONG
is wrong.
To be more clear, I want something like this:
typedef int (*type1)[10];
type1 *x = new type1;
but without using typedef.
Thanks for your code. I can follow it until the auto word. I don't know the meaning of this word in C++. I will return to your code when I will learn more about C++, and I will have more questions.
pythagorasmk
 
Posts: 39
Joined: 2015-01-18 03:40

Re: Newebe question abot new operator

Postby neuraleskimo » 2019-05-31 14:40

pythagorasmk wrote:What is the syntax for new operator. I am reading "jumping into C++" but there is no explanation of the syntax of the new operator, only few examples.

Ah, examples without explanation or history. That's too bad. I haven't taught C++ in about 15 years, but I always liked telling my students stories about each feature so they would understand the historical context and evolution of a feature to reinforce when and how to use it.

Here is a good reference to help you as you learn C++: https://en.cppreference.com/w/

Here is what cppreference says about operator new:
https://en.cppreference.com/w/cpp/language/new
https://en.cppreference.com/w/cpp/memory/new/operator_new

There are many variations, but the basic syntax is any of the following:
Code: Select all
new type;
new type {value};
new type[count];
new type[count] {values, ...};

You would use each as follows:
Code: Select all
int* p = new int; // returns an address to an uninitialized int
int* p = new int {42}; // returns an address to an int containing the value 42
int* p = new int[3]; // returns an address to three uninitialized int's
int* p = new int[3] {1, 2, 3}; // returns an address to three int's containing the values 1, 2, 3

Rather than tell you the story of malloc/free andnew/delete, let's skip ahead to where I think your book lead you astray.

pythagorasmk wrote:Lets say i have declared p with:
int (*p)[10];
how can I allocate memory with new operator for the variables of type p. Obviously:
int (*(*x))[10] = new int *[10]; //WRONG
is wrong.
To be more clear, I want something like this:
typedef int (*type1)[10];
type1 *x = new type1;
but without using typedef.


Because you are just starting, I don't want to get lost in details; however, there are several types of memory. The two most important for now are the stack and the heap, for example:
Code: Select all
int main()
{
    int x = 42; // allocated on the stack
    int* p = new int {42}; // allocated on the heap
    return 0;
}

When declaring x, the compiler will handle memory for you. However, when declaring p, you have to ask new to get some memory and initialize it for you.

Why does this matter? If all you want is an array of fixed size, then C++ has a handy shortcut for you:
Code: Select all
    int x[3] = {1, 2, 3};
    for (auto i : x) {
        std::cout << i << "\n";
    }

Alternatively, you can allocate your array on the heap:
Code: Select all
    int* p = new int[3] {1, 2, 3};
    for (size_t i = 0; i < 3; ++i) {
        std::cout << *(p + i) << "\n";
    }
    // or
    for (size_t i = 0; i < 3; ++i) {
        std::cout << p[i] << "\n";
    }
    delete [] p;

Put simply, you are trying to combine two different schemes for handling data.

pythagorasmk wrote:Thanks for your code. I can follow it until the auto word. I don't know the meaning of this word in C++. I will return to your code when I will learn more about C++, and I will have more questions.

The auto keyword was introduced to C++ in 2011 (C++11). Put simply, it allows you to tell the compiler that you don't want to write the type (but the compiler should still care about type checking). I used auto so that, when you ran my code, you could verify that the types where int, int*, and int** without me explicitly telling the compiler so.

No problem. Feel free to ask.
User avatar
neuraleskimo
 
Posts: 113
Joined: 2019-03-12 23:26
Location: Bloomington, Indiana, USA

Re: Newebe question abot new operator

Postby peter_irich » 2019-05-31 17:29

When you use malloc or new, will be the really allocated memory is multiplied times page or cluster?
I prefer to allocate area that is multiplied time page, far example, for int or char and then from the pointer
to whole area count out the pointers to the others arrays.

Peter.
peter_irich
 
Posts: 1257
Joined: 2009-09-10 20:15
Location: Saint-Petersburg, Russian Federation

Re: Newebe question abot new operator

Postby neuraleskimo » 2019-05-31 18:11

peter_irich wrote:When you use malloc or new, will be the really allocated memory is multiplied times page or cluster?
I prefer to allocate area that is multiplied time page, far example, for int or char and then from the pointer
to whole area count out the pointers to the others arrays.

If I correctly understand your question, the operating system manages memory by pages. In that respect, allocating one byte might cause the virtual memory system to allocate an entire page to the process. In the worst case, every call to malloc/new results in a page allocation from virtual memory. In reality, the allocations from virtual memory are much, much less.

Anyway, like you, I will often malloc or new a buffer that is one page in size and then pass that buffer to libraries and system calls. However, I generally don't manage my own memory and try to avoid arrays of pointers. The reason I don't manage my own memory is that despite programming in C++ for most of my life, I can promise I will screw it up several times before getting it correct. There are so many good and well vetted data structures available today, writing my own is a very rare event. The reason I avoid arrays of pointers is that every dereference in the worst case leads to a cache miss. In general, I get much better performance from storing concrete types directly in the array. Of course, storing pointers is the only solution for polymorphic types (yes, there are some a few ways to avoid this, but they are brittle).
User avatar
neuraleskimo
 
Posts: 113
Joined: 2019-03-12 23:26
Location: Bloomington, Indiana, USA

Re: Newebe question abot new operator

Postby peter_irich » 2019-05-31 18:38

neuraleskimo, thank you for the explanation. I meant that if I need in several independence arrays I allocate the area for all
and then mark it by the pointers in any places.
If there are uniform objects, then it is may be comfortable to use pointers to its, pointer occupeys 8 bytes and arrays of the pointers
usually not required memory allocation.
peter_irich
 
Posts: 1257
Joined: 2009-09-10 20:15
Location: Saint-Petersburg, Russian Federation


Return to Programming

Who is online

Users browsing this forum: No registered users and 3 guests

fashionable