I'm learning C++ and I’ve noticed that the sizeof()-operator works differently on arrays on the stack and on the heap. For instance:
int onStack[5];
int* onHeap = new int[5];
std::cout << "sizeof(onStack)=" << sizeof(onStack) << std::endl;
std::cout << "sizeof(onHeap)=" << sizeof(onHeap) << std::endl;
generates the output
sizeof(onStack)=20
sizeof(onHeap)=4
However, as far as I can tell, both onStack and onHeap are just int pointers, right? I’m aware that you shouldn’t / can’t really use the sizeof()-operator to get the size of an array, but just out of curiosity, why does it behave differently, depending on whether the array is on the stack or on the heap?
No, onStack is a int[5] wich decays to a pointer. They are not the same, hence the sizeof difference.
Nothing to do with on stack vs on heap, it's really just type difference.
Related
I am allocating a multidimensional valarray of size 2000x2000 and it is working smoothly.
valarray<valarray<int>> D(valarray<int>(-2,2000), 2000);
D[1999][1999] = 2000;
However, if I try to allocate a normal array and access an element, I get segmentation fault.
int A[2000][2000];
A[1999][1999] = 2000;
Both are on the stack, why this difference ?
Like std::vector, the underlying storage of std::valarray is dynamic, and the size of the object that manages this storage does not depend on the number of elements.
This program:
#include <iostream>
#include<valarray>
int main() {
std::cout << "sizeof(std::valarray<std::valarray<int>>): "
<< sizeof(std::valarray<std::valarray<int>>) << std::endl;
std::cout << "sizeof(int[2000][2000]): " << sizeof(int[2000][2000]) << std::endl;
}
produces this output for me:
sizeof(std::valarray<std::valarray<int>>): 16
sizeof(int[2000][2000]): 16000000
If you were to use std::array instead, you would have problems, though.
Both are on the stack, why this difference ?
Because std::valarray is much, much smaller object. Its size is entirely implementation defined, but in a particular standard library implementation that I looked at, it was the size of two pointers.
By contrast, the size of the 2d array A is more than 15 megabytes assuming a 4 byte int. The space available for automatic objects (shared among all of them) is typically much less than that in typical language implementations.
The dynamic memory allocation is hidden inside of the constructor of the valarray class and still uses new or malloc in the end.
Actually valarray is not on stack. This is why construction of array overflow but valarray doesn’t .
I am trying to learn C++, I have a fair bit of experience in C# and the 2 languages are so dissimilar and I am having trouble understanding data types and pointer variants of data types and the initialization of them, please consider the code below:
wchar_t *array = new wchar_t[10]; //Declaring a pointer of wchart_t and initializing to a wchar_t array of size 10 ?
auto memAddressOfPointer = &array; //auto is resolving memAddressOfPointer to a pointer of a pointer?
cout << array << endl; //Printing the memory address of array not the object created above?
cout << *array << endl; //Getting the actual value of the object (empty wchar_t array of size 10 in bytes?
cout << &array << endl; //Printing the address of the obj?
cout << memAddressOfPointer << endl; //Printing the address of the obj ?
My question is why would I create a pointer and initialize it? Why not just create an array of wchar_t? like:
wchar_t array [10];
I refer to this stack post as well:
Unable to create an array of wchar_t
Thank you for your consideration.
If you know the size of the number of elements you need to put in the array, then just use the array i.e., wchar_t arr[10];.
If you don't know the size, you can create the array at runtime using dynamic memory allocation with the required size i.e., wchar_t *arr = new wchar_t[required_size]. Once the memory is allocated, you need to deallocate it using delete[] operator for arrays and delete for non-array pointers. However I highly recommend you don't do that and instead either
Use std::wstring in this particular case which will automatically handle this for you.
Use std::vector for everything else if you can. It's a dynamic array which will grow automatically. No manual memory management etc.
In case you have to use pointers, use a smart pointer like unique_ptr or shared_ptr. The advantage of using smart pointers is that they will automatically clean up once they go out of scope.
If you know the extent of the array when writing the program, there's absolutely nothing wrong with wchar_t array [10];. If 10 is a fixed (constexpr) number - stick with that.
What wchar_t *array = new wchar_t[10]; lets you do is to let 10 be a number that you find out in run-time. You can change 10 to x and let x be a number that the user supplies or that you calculate somehow. wchar_t array [x]; when x is not a constexpr is on the other hand not valid C++ (but is available as an exension, called VLA, in some implementations).
Note: One downside with using new is that you need to make sure you delete the same pointer. This is not always simple. Using these raw pointers is therefore not what you usually want to do. Instead, use a smart pointer, like std::unique_ptr<wchar_t[]>, and the resource will be delete[]d when the pointer goes out of scope.
The advantages of creating a pointer instead of an array are the dynamic allocation that you can take advantage of and also the properties of the pointer that might help.
Consider the following code that represent the dynamic allocation and reallocation:
int x;
cin >> x;
int *oldArr = malloc(x * sizeof(int));
for(int i = 0; i < x; i++)
arr[i] = i;
cin >> x;
arr = realloc(arr, x * sizeof(int));
Here is another example that shows one of the pointer features which also you can use along with arrays.
int arr[5] = {1, 2, 3, 4 ,5};
int *ptr = arr;
cout << *ptr;
ptr++;
cout << *ptr;
cout << *(ptr + 1);
Despite these advantages and others, I think that the example you are presenting of using pointers instead of arrays is just for academic purposes to understand how to work with pointers in order to build more complex data structures using pointers in future lessons as you are using constant size arrays.
I have just started learning C++ and I came on a problem I couldn't find on the Internet so I hope you can help me with.
This is my code:
int* a;
int* b;
a = (int*)calloc(1, sizeof(int));
b = (int*)calloc(5, sizeof(int));
cout << sizeof(a) << endl;
cout << sizeof(b) << endl;
What compiler returns me is: 8, 8.
If I use:
cout << sizeof(*a) << endl;
cout << sizeof(*b) << endl;
Compiler returns 4, 4.
The same thing is with malloc. I am using .
What am I doing wrong? Why isn't the size of b 20 as it is 5 times bigger if int is 4 bytes long?
Thanks!
sizeof(*a) and sizeof(*b) are always going to be equal to 4. It seems you expect them to return the size of arrays, but you need to understand that a and b are not arrays. They are pointers to int. If sizeof(int) is 4, then sizeof(*a) is also going to be 4, and this is already known at compile time.
With that being said, you do not need to use the C library functions malloc() and calloc() in C++. If you need manual memory allocation, use new and delete:
a = new int;
b = new int[5];
If you need to do zero-initialization like calloc does, just use () to default-construct the allocated integers:
a = new int();
b = new int[5]();
Instead of free(), use delete or delete[], depending on how new was called previously:
delete a; // Note: no '[]'
delete[] b; // Needs '[]'
However, you do not need manual memory allocation here. Just use std::vector<int>:
#include <vector>
// ...
std::vector<int> a(5); // 5 int elements, zero-initialized.
std::cout << a.size() << '\n'; // Will print '5'.
As a rule of thumb, your C++ code should not have any calls to new, delete, malloc(), calloc() or free(). Doing manual memory management requires more code and is error-prone. Use containers like vector and smart pointers like shared_ptr and unique_ptr instead to reduce the chance of memory and other resource leaks. These safer types are also more convenient. With vector for example, you do not have to remember the size of your allocated memory yourself. The vector keeps track of its size for you. You can also copy vectors easily by just assigning them directly. You also don't need to delete or free() vectors manually. They are automatically deleted when they go out of scope.
As a side-note, I recommend getting rid of the habit of using endl for printing newlines. endl flushes the stream, it doesn't just print a newline. If you use it, you will be constantly flushing the output stream, which is a slow operation. You only rarely need to flush a stream, in which case you can just do so manually with << flush if the need ever arises.
You are taking the sizeof a pointer in the first case and the size of the element int the second. *a is for your intents and purposes the same as a[0]. The size of the pointer is architecture dependent, and the size of the int is 4.
The sizeof value is evaluated at compile time. Dynamic memory allocation occurs at runtime. To find out the amount allocated at run time you can look at overloading the new operator (not recommended) or using the containers as the comments have suggested.
sizeof(a) is the size of the pointer (this is 8 in a 64bit architecture normally), while sizeof(*a) is the size of the pointed to element (an integer value). Nothing returned by sizeof operator has dynamic nature (as the number of elements returned by calloc(3))
By the way, calloc() is strongly deprecated in C++. Its use is reserved to cases in which you have to pass the pointers to C code and for legacy code. Use the operators new and new [] (the last one in this case). But none of these will change things, the sizeof operator will continue returning the values you got. If you want to check the size of the returned array, then check the parameters passed to both operators.
I wrote some code in which I attempted to create a pointer on the Free store(Heap memory). I think it's impossible but I tried regardless.
The code below is basically creating a vector of pointers on the heap and then making those pointers in the vector point to some ints on the heap. I want to know if those pointers in the vector called vec are on the heap? I also wanted to know what is the proper way to free up space allocated when using a vector like this. The last delete statement was crashing the program so I commented it out. I don't know if there is a memory leak.
vector<int*> *vec = new vector<int*>();
vec->push_back(new int(1));
vec->push_back(new int(2));
vec->push_back(new int(3));
cout << (*vec)[0] << " " << (*(*(vec))[0]) << endl;
cout << (*vec)[1] << " " << (*(*(vec))[1]) << endl;
cout << (*vec)[2] << " " << (*(*(vec))[2]) << endl;
delete (*vec)[0];
delete (*vec)[1];
delete (*vec)[2];
//delete [] vec;
Any variable can be created in heap, including a pointer.
That said, at the C++ level you don't control where exactly the memory is created.
The most important thing to understand about pointers is that there is nothing special about pointers.
Like all other vector elements, the elements of vec are located in the free store, since that’s where a vector keeps them.
If you want to manually create an int* in the free store, you would say new int*, which will of course return the address of that pointer, so for instance
int** pointer = new int*(nullptr);
However, there is very little point in doing this in practice — I don't think I’ve seen anyone use it in my twenty-odd years of C++.
The c++ way of creating a pointer on the heap is as follows:
int** pointerToPointer = new int*;
The type int** can be read as a pointer to a pointer. Then we use new to allocate a piece of data of type int* (int pointer) on the heap.
If you want to allocate memory for an integer, you can say new int;, as you've done here.
The new keyword will accept any (non-void) type. So if you want to allocate for a pointer (which would be of type int*), you can just say new int*;
A (heavily contrived) example may look like:
int thing = 7;
int **ptr = new int*(&thing);
std::cout << "**ptr = " << **ptr << std::endl;
Notice that since new will return an address pointing to whatever type we allocated (in this case int*), we'll need to assign it to an int** variable.
All this being said, you're very unlikely to ever need to allocate a raw new int*. More than likely, you'd run into something similar if you're were dealing with dynamically allocated multi-dimensional arrays.
But in any of these situations, I'd strongly suggest using more modern memory management methods with Smart Pointers.
In C++, I understand that the delete operator, when used with an array, 'destroys' it, freeing the memory it used. But what happens when this is done?
I figured my program would just mark off the relevant part of the heap being freed for re-usage, and continue on.
But I noticed that also, the first element of the array is set to null, while the other elements are left unchanged. What purpose does this serve?
int * nums = new int[3];
nums[0] = 1;
nums[1] = 2;
cout << "nums[0]: " << *nums << endl;
cout << "nums[1]: " << *(nums+1) << endl;
delete [] nums;
cout << "nums[0]: " << *nums << endl;
cout << "nums[1]: " << *(nums+1) << endl;
Two things happen when delete[] is called:
If the array is of a type that has a nontrivial destructor, the destructor is called for each of the elements in the array, in reverse order
The memory occupied by the array is released
Accessing the memory that the array occupied after calling delete results in undefined behavior (that is, anything could happen--the data might still be there, or your program might crash when you try to read it, or something else far worse might happen).
The reasons for it being NULL are up to the heap implementation.
Some possible reasons are that it is using the space for it's free-space tracking. It might be using it as a pointer to the next free block. It might be using it to record the size of the free block. It might be writing in some serial number for new/delete debug tracking.
It could just be writing NULL because it feels like it.
Whenever someone says int* nums = new int[3], the runtime system is required to store the number of objects, 3, in a place that can be retrieved knowing only the pointer, nums. The compiler can use any technique it wants to use, but there are two popular ones.
The code generated by nums = new int[3] might store the number 3 in a static associative array, where the pointer nums is used as the lookup key and the number 3 is the associated value. The code generated by delete[] nums would look up the pointer in the associative array, would extract the associated size_t, then would remove the entry from the associative array.
The code generated by nums = new int[3] might allocate an extra sizeof(size_t) bytes of memory (possibly plus some alignment bytes) and put the value 3 just before the first int object. Then delete[] nums would find 3 by looking at the fixed offset before the first int object (that is, before *num) and would deallocate the memory starting at the beginning of the allocation (that is, the block of memory beginning the fixed offset before *nums).
Neither technique is perfect. Here are a few of the tradeoffs.
The associative array technique is slower but safer: if someone forgets the [] when deallocating an array of things, (a) the entry in the associative array would be a leak, and (b) only the first object in the array would be destructed. This may or may not be a serious problem, but at least it might not crash the application.
The overallocation technique is faster but more dangerous: if someone says delete nums where they should have said delete[] nums, the address that is passed to operator delete(void* nums) would not be a valid heap allocation—it would be at least sizeof(size_t) bytes after a valid heap allocation. This would probably corrupt the heap. - C++ FAQs