This question already has answers here:
Does C++ pass objects by value or reference?
(5 answers)
What's the difference between passing by reference vs. passing by value?
(18 answers)
Closed 26 days ago.
The community is reviewing whether to reopen this question as of 25 days ago.
So I've been returning to the world of C/C++ after many years of working in Java/C# and Python. I've been a software engineer for the better part of 12 years so I'm familiar with value vs reference and design patterns, but this issue I've been seeing has made me scratch my head and question myself.
I've been following a primer guide to get myself back up to speed with C/C++, starting from the basics including pointers. I've been working on dynamic arrays and memory management. I know... I know... in production situations I'm better off using vectors, but this is for education and catching up. So on to the problem...
Here is sample code:
int main() {
int capacity = 1;
int size;
int * dynamicArray = CreateDynamicArray(capacity, size);
InsertElement(dynamicArray, 20, size, capacity);
ResizeDynamicArray(dynamicArray, size, capacity + 1);
delete[] dynamicArray
return 0;
}
int * CreateDynamicArray(int capacity, int& size){
size = 0;
cout << "Creating Dynamic Array of size: " << capacity << endl;
return new int[capacity];
}
void InsertElement(int* dynamicArray, int element, int& size, int& capacity){
dynamicArray[size] = element;
size++;
}
void ResizeDynamicArray(int* dynamicArray, int& size, int newCapacity){
int * temp = new int[newCapacity];
copy(dynamicArray, dynamicArray + size, temp);
delete[] dynamicArray;
dynamicArray = temp;
}
So here we are using the new/delete method of memory allocation (will move to alloc/free later if I need to). When I write this code all into the main function, meaning no other functions, everything works perfectly fine. But when I break the code into separate functions I get really weird behavior with the memory.
in ResizeDynamicArray() I create the temp pointer and use std::copy to move data into the resized array. I then delete the old pointer and then point to the new array. However, while watching the pointer and outing the value, after the function returns the pointer's reference value dynamicArray[0] goes from 20 to some random value, as if the pointer was deleted. If I remove the delete[] dynamicArray portion it doesn't have this issue.
So this leaves me thinking, why does deleting the old pointer affect the new address that I am now pointing to?
Why does this behavior only happen when done within a function?
How do I best avoid this?
Using double pointers int** dynamicArray seems to avoid this issue, but I'm having a hard time understanding why as you have to deference back to the first pointer anyways.
The line dynamicArray = temp; does not have the effect you are hoping for. dynamicArray is a local variable, changing its value has no visible effect to the caller. Since it is the last line in the function it has no visible effect at all.
For this line to make sense, you would have to pass dynamicArray by reference, i.e.:
void ResizeDynamicArray(int*& dynamicArray, int& size, int newCapacity)
Related
This question already has answers here:
How do you 'realloc' in C++?
(4 answers)
Closed 2 years ago.
I have made a code in which i am creating array of objects using new.I am extending the array by another new keyword and last index of previous array like following.Its working fine(The constructor is printing "a" number of times the net index). But i dont know is it safe or not? My main motive is to make a dynamic array but i cant use malloc because it dows not call constructors.So i am using new. But idont know how to reallocate memory after using new. If i use realloc then the program is not giving any error but realloc is not calling the constructor.
Summary:->Just want to call constructor while reallocating memory.
I have given the image of my code
class xy
{
unsigned x[10],y[10],counter;
public:
xy()
{counter=0;}
void setxy(unsigned a,unsigned b)
{x[counter]=a;y[counter]=b;counter++;}
void printxy()
{for(unsigned i=0;i<counter;i++)cout<<"="<<x[i]<<"^3+"<<y[i]<<"^3";}
};
class unitcell
{
unsigned long long value_cube,hasharr_len;
xy* hasharr;
unsigned long long* r_numberindexes;
unsigned rarraylen;
public:
unitcell()
{cout<<"a";}
unsigned long long gethasharraylen()
{return hasharr_len;}
};
int main()
{
unitcell *a=new unitcell[3];
unitcell *b=a+3;
b=new unitcell[3];
}
No.
First you're initializing b to the value of a+3 and then you're assigning the result of new to it, which will be a completely different value. You have no control over where your allocated memory will end up. You should assume each new invocation gives you a completely random address, whose value you cannot predict.
If you want to "extend" your array you have to allocate a bigger one, copy all the elements you already had and then delete the old one
unitcell *b = new unitcell[6];
std::copy(a, a+3, b);
delete a;
a = b;
STL class std::vector works in this way internally.
This question already has answers here:
Can I delete[] a pointer that points into an allocated array, but not to the start of it?
(7 answers)
Why can't I delete pointer alone from an array of objects?
(4 answers)
Closed 5 years ago.
Consider, below program which gives runtime error. Point of this question is to understand memory view and management.
#include<iostream>
using namespace std;
int main(void) {
char* arr = new char[10];
char* ptr = NULL;
for(int i = 0; i < 10; i++) {
arr[i] = 'a';
}
cout << arr;
ptr = &arr[5];
delete ptr;
cout << arr;
return 0;
}
new allocates a block of memory. You can free that memory using delete, but you must pass the same address that was returned by new. That's how it works. You can't pass arbitrary addresses to delete.
Another option is to use malloc() and free(). These are older function but then you can also use realloc() to resize the memory. Then, if you want to delete part of the array, you can resize it to be smaller. BUT... you must still copy any data as needed to correctly form the resized array. That is not automatic.
Consider the following code:
int *expand_array(int *old_arr,int array_length)
{
int *new_arr = new int[array_length +3];
for(int counter=0;counter<array_length;counter++)
new_arr[counter]=old_arr[counter];
delete[] old_arr;
return new_arr;
}
int main()
{
int *my_first_arr = new int[4];
int *my_expanded_arr=expand_array(my_first_arr,4);
delete[] my_expanded_arr;
}
will there be any memory leak here?
And to generalize the question,
if the pointer returned from a new statement is copied ,passed to a function or assigned to a different pointer, will the delete copied_pointer release the memory?
Your code is perfectly valid C++ and has no memory leaks. You can copy a pointer as often as you want to and deleteing any of those copies in any scope has the same effect.
It is still bad practice, however, and you shouldn't write code like this. Use of raw new and delete is too error prone and will make for poorly maintainable code. Instead, use RAII wrapper types like std::unique_ptr, std::shared_ptr or, in this case, std::vector.
The code in your question is basically equivalent to this.
int
main()
{
auto numbers = std::vector<int>(4);
numbers.resize(7);
}
Much simple, no?
Why do you believe that there would be a memory leak? Of course there wouldn't be.
But there is a different bug in this code. If the new array size is larger than the size of the existing old_arr, the code that copies the old array to the newly allocated int array is going to copy too much, run off past the end of the old array, resulting in undefined behavior; possibly a crash (old array size is 2 ints, array_length is 10, the for loop will attempt to copy 10 values from the old array which only has 2).
This question already has answers here:
May I treat a 2D array as a contiguous 1D array?
(6 answers)
Closed 8 years ago.
Related thread here: Does C99 guarantee that arrays are contiguous?
Apparently answer() isn't valid below, but could be re-written to use char * or cast to int[nElements] (possibly). I'll admit I don't understand the standard references and why a contiguous block of int couldn't be accessed via int* if properly aligned.
First is the following code block valid on most C++ platforms?
void answer(int *pData, size_t nElements)
{
for( size_t i=0; i<nElements; ++i )
pData[i] = 42;
}
void random_code()
{
int arr1[1][2][3][4]; // local allocation
answer(arr1, sizeof(arr1) / sizeof(int));
int arr2[20][15];
answer(arr2, sizeof(arr2) / sizeof(int));
}
Second does answer() remain valid for all allocation types (global, local, heap(hopefully correct!))?
int g_arr[20][15]; // global
void foo() {
int (*pData)[10] = new int[50][10]; // heap allocation, at least partially
answer(&pData[0][0], 50*10);
// not even sure if delete[] will free pData correctly, but...
}
Yes, most platforms will indeed pack the elements of an N-dimensional array in such a way that linear addressing on a pointer to the first element will find all of the elements.
It is actually hard (as in, I cannot figure it out) to come up with a standards compliant implementation that does not do this, as an array of arrays must pack said arrays, and the size of the array of arrays is the size of each sub array times the number of arrays of arrays. There does not seem to be room for it not to work. Even the ordering of each element seems to be well defined.
Despite this, no clause in the standard I am aware of lets you actually reinterpret the pointer to the first element of a multi dimensional array as a pointer to an array of the product. Many clauses talk about how you can only access the elements of the array, or one-past-the-end.
The code in answer() is fine. The code in random_code() is misusing answer() (or not calling the overload of answer() shown in the question). It should be:
void random_code()
{
int arr1[1][2][3][4];
answer(&arr1[0][0][0][0], sizeof(arr1) / sizeof(int));
int arr2[20][15];
answer(&arr2[0][0], sizeof(arr2) / sizeof(int));
}
The code in answer() expects an int *; you were passing an int (*)[2][3][4] and an int (*)[15], neither of which looks like int *.
This remains valid for other allocation mechanisms that allocate a single contiguous block of data, such as the ones shown.
As the previous person said, there's a type error in your code. You're trying to use an int ()[X] type actual argument for an int formal argument. So to make your code work, you should use type casting.
C++/C uses the same memory layout for data types not depending on what section of memory is used for allocating an object so that the same code can be used for values where they are. So the answer to your second question, is if your code is working on stack-allocated values, it is going to work with a heap-allocated value too.
I've been reading through some books, and when it comes to Class/Functions using Pointers/Dynamic Memory (or heap or w/e they call it) I start to get confused.
Does anyone have a simple....like easy example they can show, because the books im using are using overly complex examples (large classes or multiple functions) and it makes it hard to follow. Pointers have always been my weak point anyways but I understand BASIC pointers, just classes/functions using them is a little bit confusing.
Also.....when would you use them is another question.
Stack allocation:
char buffer[1000];
Here the 1000 must be a constant. Memory is automatically freed when buffer goes out of scope.
Heap Allocation:
int bufsz = 1000;
char* buffer = new char[bufsz];
//...
delete [] buffer;
Here bufsz can be a variable. Memory must be freed explicitly.
When to use heap:
You don't know how much space you will need at compile time.
You want the memory/object to persist beyond the current scope.
You need a large chunk of memory (stack space is more limited than heap space)
Your computer's RAM is a big pile of bytes ordered one after another, and each one of those bytes can be accesed independently by it's address: an integer number startig from zero, upwards. A pointer is just a variable to hold that address of a single place in memory.
Since the RAM is a big chunk of bytes, the CPU ussually divides that big pile of bytes on several chunks. The most important ones are:
Code
Heap
Stack
The Code chunk is where the Assembly code lies. The Heap is a big pool of bytes used to allocate:
Global variables
Dynamic data, via the new operation on C++, or malloc() on C.
The stack is the chunk of memory that gets used to store:
Local variables
Function parameters
Return values (return statement on C/C++).
The main difference between the Stack and Heap is the way it is used. While the Heap is a big pool of bytes, the Stack "grows" like a stack of dishes: you can't remove the dish on the bottom unless there are no more dishes on it's top.
That's how recursion is implemented: every time you call a function recursively, memory grows on the stack, allocating parameters, local variables and storing return values of the returning functions, one on top of the others just like the stack of dishes.
Data living on the Stack have different "Life Span" than the data living on the Heap. Once a function exits, the data on the local variables get lost.
But if you allocate data on the Heap, that data won't get lost util you explicitly free that data with the delete or free() operations.
A pointer is basically a variable that contains the memory address of another variable (or in other cases to a function, but lets focus on the first).
That means that if I declare int[] x = {5,32,82,45,-7,0,123,8}; that variable will be allocated to memory at a certain address, lets say it got allocated on address 0x00000100 through 0x0000011F however we could have a variable which indicates a certain memory address and we can use that to access it.
So, our array looks like this
Address Contents
0x00000100 1
0x00000104 32
0x00000108 82
0x0000010B 45
0x00000110 -7
0x00000114 0
0x00000118 123
0x0000011B 8
If, for example, we were to create a pointer to the start of the array we could do this: int* p = &x; imagine this pointer variable got created a memory address 0x00000120 that way the memory at that address would contain the memory location for the start of array x.
Address Contents
0x00000120 0x00000100
You could then access the contents at that address through your pointer by dereferencing the pointer so that int y = *p would result in y = 1. We can also move the pointer, if we were to do p += 3; the pointer would be moved 3 addresses forward (note, however, that it moves 3 times the size of the type of object it is pointing to, here I am making examples with a 32 bit system in which an int is 32 bits or 4 bytes long, therefore the address would move by 4 bytes for each increment or 12 bytes in total so the pointer would end up pointing to 0x0000010B), if we were to dereference p again by doing y = *p; then we'd end up having y = 45. This is just the beginning, you can do a lot of things with pointers.
One of the other major uses is to pass a pointer as a parameter to a function so that it can do operations on certain values in memory without having to copy all of them over or make changes that will persist outside of the function's scope.
Warning: Don't do this. This is why we have vectors.
If you wanted to create an array of data, and return if from a function, how would you do it?
Obviously, this does not work:
int [10] makeArray(int val)
{
int arr[10];
for(int i=0; i<10; ++i)
arr[i] = val;
return arr;
}
You cannot return an array from a function. We can use pointers to refer to the first element of an array, like this:
int * makeArray(int val)
{
int arr[10];
for(int i=0; i<10; ++i)
arr[i] = val;
return &(arr[0]); // Return the address of the first element.
// Not strictly necessary, but I don't want to confuse.
}
This, however, also fails. arr is a local variable, it goes on the stack. When the function returns, the data is no longer valid, and now you have a pointer pointing to invalid data.
What we need to do is declare an array that will survive even after the function exits. For that, we use keyword new which creates that array, and returns the address to us, which needs to be stored in a pointer.
int * makeArray(int val)
{
int * arr = new int[10];
for(int i=0; i<10; ++i)
arr[i] = val;
return arr;
}
Then you can call that function and use that array like this:
int * a = makeArray(7);
for(int i=0; i<10; ++i)
std::cout << a[i] << std::endl;
delete [] a; // never forget this. Obviously you wouldn't do it right
// away like this, but you need to do it sometime.
Using pointers with new also gives you the advantage that you can determine the size of the array at runtime, something you can't do with local static arrays(though you can in C):
int * makeArray(int size, int val)
{
int * arr = new int[size];
for(int i=0; i<size; ++i)
arr[i] = val;
return arr;
}
That used to be one of the primary purposes for pointers. But like I said at the top, we don't do that anymore. We use vector.
One of the last vestiges of pointers is not for dynamic arrays. The only time I ever use them, is in classes where I want one object to have access to another object, without giving it ownership of that object. So, Object A needs to know about Object B, but even when Object A is gone, that doesn't affect Object B. You can also use references for this, but not if you need to give Object A the option to change which object it has access to.
(not tested, just writing down. and keeping things intentionally primitive, as requested.)
int* oneInt = new int; // allocate
*oneInt = 10; // use: assign a value
cout << *oneInt << endl; // use: retrieve (and print) the value
delete oneInt; // free the memory
now an array of ints:
int* tenInts = new int[10]; // allocate (consecutive) memory for 10 ints
tenInts[0] = 4353; // use: assign a value to the first entry in the array.
tenInts[1] = 5756; // ditto for second entry
//... do more stuff with the ints
delete [] tenInts; // free the memory
now with classes/objects:
MyClass* object = new MyClass(); // allocate memory and call class constructor
object->memberFunction("test"); // call a member function of the object
delete object; // free the object, calling the destructor
Is that what you wanted? I hope it helps.
I think this is what you're asking about:
Basically C++ doesn't allow variable-sized arrays. Any array in C++ has to be given a very specific size. But you can use pointers to work around that. Consider the following code:
int *arry = new int[10];
That just created an array of ints with 10 elements, and is pretty much the same exact thing as this:
int arry[] = int[10];
The only difference is that each one will use a different set of syntax. However imagine trying to do this:
Class class:
{
public:
void initArry(int size);
private:
int arry[];
};
void class::initArry(int size)
{
arry = int[size]; // bad code
}
For whatever reason C++ was designed to not allow regular arrays to be assigned sizes that are determined at runtime. Instead they have to be assigned sizes upon being coded. However the other way to make an array in C++ - using pointers - does not have this problem:
Class class:
{
public:
~class();
void initArry(int size);
private:
int *arry;
};
class::~class()
{
delete []arry;
}
void class::initArry(int size)
{
arry = new int[size]; // good code
}
You have to do some memory cleanup in the second example, hence why I included the destructor, but by using pointers that way you can size the array at runtime (with a variable size). This is called a dynamic array, and it is said that memory here is allocated dynamically. The other kind is a static array.
As far as 2-dimensional arrays go, you can handle it kind of like this:
Class class:
{
public:
~class();
void initArrays(int size1, int size2);
private:
int **arry;
};
class::~class()
{
delete [] arry[0];
delete [] arry[1];
delete [] arry;
}
void class::initArrays(int size1, int size2)
{
arry = new int*[2];
arry[0] = new int[size1];
arry[1] = new int[size2];
}
Disclaimer though: I haven't done much with this language in a while, so I may be slightly incorrect on some of the syntax.