Pointer to array changes value of array elements [duplicate] - c++

This question already has answers here:
How do I use arrays in C++?
(5 answers)
Closed 6 years ago.
I have an array of integers that I pass into function. Then I want to make a dynamic array in that function as a copy of the first array, but whenever I change the value of an element in second array (copy), the value in the first array also changes. What am I doing wrong?
example:
int *array1 = new int[N]
int *array2 = new int[N]
array2 = array1;
array2[1]=2; //element of the first array at index 1 also becomes 2
Thank you.

The Explanation:
Since we are dealing with C++, there is pretty much no reason to use new int[N] instead of std::vecotr<int> of a size N.
To explain what is happening in your code: You create a pointer named array1 and allocate memory enough to contain N integers. You do the same with second pointer, called array2. Since the names array1 and array2 are just pointers to memory, what they point to can be changed. In the line array2 = array1 you change to what is pointing array2 to memory allocated and pointed to by array1 pointer.
So what happens now? Really bad stuff. You are encountering a memory leak. The memory that was pointed to by array2 is still there, still allocated, but you are unable to access it, since your only access to it (array2 pointer) now points to entirely different part of memory. You now also have 2 pointers that point to the same memory (originally the memory that was allocated in the line int *array1 = new int[N]).
How to improve your code?
Use std::vector<int>. Vector class comes with well written and safe assignment operator that will work for you here:
std::vector<int> array1(N);
std::vector<int> array2(N);
array2 = array1;
Now you have 2 identical vectors, memory is managed well (array1 and array2 are separate entities. They do not share the same memory and can be freely changed without affecting the other one) and your code looks pretty.
What if you cannot change everything to std::vector?
You mentioned having an array that you pass into a function. Let's call it an original_array of a size N. Consider this code, which uses similar signature, but uses safe memory management by converting array to vector:
void copy_and_do_stuff(int original_array[], int N)
{
std::vector<int> array2;
std::copy(original_array, original_array + N, array2.begin());
// here, the vector "array2" is a copy of your `original_array`. Changes
// to it will not affect your argument.
// ... do whatever you need to do in this function ...
}
Remember to add #include <vector> and #include <algorithm> to use vectors and std::copy function.

To give a full answer, although the comments say everything important so far:
The line array2 = array1; does the following: take the address that is stored in array1 and store it also in array2. They are both pointing at the same location now (and the old, reserved storage is still reserved but not pointed at, aka a memory loss)
In any case, pointers are somewhat dangerous things, easily leading to unexpected behaviour, especially if you are a beginner. Therefore, you want to use std::vector:
//at the head of the file
#include <vector>
using std::vector;
//in the program
vector<int> array_1(n);
//do something with array_1:
array_1[0] = 1;
array_1[1] = ...
vector<int> array_2 = array_1; //actually copies the content
or:
vector<int> array_2(array_1); //copy constructor
At some point you will want to investigate how vector works internally (it wraps an array, actually), but for now, simply use vector. Read it's documentation. You can do all sorts of things on it with the STD library, like for example having it sorted by std::sort.

As mentioned in the comments you probably shouldn't be doing this in c++; std::vector is THE optimized; safe and reliable way to handle data of this sort.
But it is clear from your question that you don't really understand pointers.
This is what you code does:
int *array1 = new int[N]; //allocate memory for the first array
int *array2 = new int[N]; //allocate memory for the second array
array2 = array1; //OVERWRITE the location of the second array
//with that of the first (thus destroying your
//only pointer to the second array and creating a
//memory leak)
To achieve what you want in array2=array1 you need to write a loop and copy every integer ELEMENT of the array across to the new array - this creates a 'deep' copy.

array1 and 2 are pointers in your case.
When you do:
array2 = array1;
array2 points to the same memory location as array1, and the old array2 is lost in memory (and so it creates a memory leak, as Elemental said)
You need to copy the array elements by hand or use std::vector

Related

How to create a pointer to pointers

The problem that I have is to create a specific matrix.
I have to use an array called for example ptr with x pointers. Each pointer in this array should point to a new array (in this case, an int array; each array is a new line in the matrix then).
All x arrays should be created with new; in the end, it should be possible to access the matrix with ptr[a][b] easily.
After a lot of trying and failing, I hope that someone can help me out.
Thank you in advance!
Since this is obviously homework, let me give you a better answer for your sake to go alongside the accepted one.
std::vector<std::vector<int>> matrix(10, std::vector<int>(10));
// ^ ^ ^
// Column count ______| |________________|
// |
// |___ Each column is
// initialized with
// a vector of size 10.
That's a 10x10 matrix. Since we're using vectors, the sizes are dynamic. For statically sized arrays, you can use std::array if you want. Also, here's the reference for std::vector.
If the number of pointers in the array is known, you could simply use a raw array of pointers to int:
int* my_array[10]; // 10 int*
Then you should allocate memory individually for each pointer in the array using usually a for loop:
for(int i=0; i<10; i++){
// each int* in the array will point to an area equivalent to 10 * sizeof(int)
my_array[i] = new int[10];
}
On the other hand, if you don't know the size of the array, then you need a pointer to pointers:
int** ptr_to_ptr = new int*[10];
Note that I am allocating space for 10 int* and not int.
Remember to deallocate the memory allocated above also for the internal pointers, once you don't need that memory anymore.

When allocating a dynamic array, are the previous elements deleted?

Title says it all more or less. When I need an (for the sake of this example) integer array for an unknown amount of values I know I can change it's size using new *array = new int[size]. Now my question is: If I have an array of a certain size, but I need to make it bigger, can I just use the new operator to expand it and will it still have all previously stored elements or would it be smarter to create a whole new array with a dynamic size, copy all elements from the previous array into the new one and delete[] the old array. Basically just swapping between the two arrays, whenever I need a new size.
Specifically I am asking whether or not this piece of code would work in the way it's intended to work
for(int i = 1; i < 10; i++){
int *array = new int[i];
array[i-1] = i;
}
My assumption is that this array will first be the size of 1 and store the value 1 at index 0. Then it will reallocate its size to 2 and store the value to at index 1 and so on until i is 9.
I guess to rephrase my question a bit better: Does an array initialized with new have to be populated with elements or will it copy the elements it had from before using the operator?
You can't resize the array in this way. You need to make a new array and then copy the old array into it. You can also try std::vector, which does what you want automatically.
If you want to use pointers rather than std::vector to change the size of your array, you can do it in this way.
int n = 100; // This will be the number of elements.
int *array1; // Pointer
array1 = new int[n]; // This will allocate your array with size n, so you will have 100 elements. You can combine this with the previous in int *array1 = new int[n];
So fill up the this array however you please...
Then you decide you want a 200 element array instead? You will need to create a different array in the same way.
int *array2 = new int[200];
You can use the for loop to copy array 1 into array 2. The for loop should iterate as many times as there are elements in array 1 (100).
for(int i = 0; i < 100; ++i)
array2[i] = array[1];
At this stage array2 is exactly the same as array1, but with 100 uninitialized elements at your disposal from [100] to [199].
You won't need array1 anymore, so at some point, you should call
delete [] array1;
Your assumption, by the way would not work, because on the first cycle of your loop, you create (or try to create) an array of i=1 element. Arrays start counting at 0, so your only single element is [0]. When i is at 0, what is i-1?
If you try to access array[-1], you'll probably crash. But why should you want to create 10 different arrays? new keyword creates an unrelated object, not overwrites the one with the same name.
Does an array initialized with new have to be populated with elements or will it copy the elements it had from before using the operator?
new[] allocates new array, completely independent from previous.
I know 3 ways to "make the array bigger":
As #ravi mentioned, don't mess with poinsters, use modern std::vector.
Make new array in new pointer, std::move elements from old array to the new one, and then delete[] old array.
Get rid of new[] & delete[], use old realloc with malloc & free.
You have to allocate new array and copy old array's data into that. This is how vector is implemented. Had there been better way of doing it, C++ standard community would have considered that.

Pointer to an array get size C++

int * a;
a = new int[10];
cout << sizeof(a)/sizeof(int);
if i would use a normal array the answer would be 10,
alas, the lucky number printed was 1, because sizeof(int) is 4 and iszeof(*int) is 4 too. How do i owercome this? In my case keeping size in memory is a complicated option. How do i get size using code?
My best guess would be to iterate through an array and search for it's end, and the end is 0, right? Any suggestions?
--edit
well, what i fear about vectors is that it will reallocate while pushing back, well you got the point, i can jus allocate the memory. Hoever i cant change the stucture, the whole code is releevant. Thanks for the answers, i see there's no way around, so ill just look for a way to store the size in memory.
what i asked whas not what kind of structure to use.
Simple.
Use std::vector<int> Or std::array<int, N> (where N is a compile-time constant).
If you know the size of your array at compile time, and it doens't need to grow at runtime, then use std::array. Else use std::vector.
These are called sequence-container classes which define a member function called size() which returns the number of elements in the container. You can use that whenever you need to know the size. :-)
Read the documentation:
std::array with example
std::vector with example
When you use std::vector, you should consider using reserve() if you've some vague idea of the number of elements the container is going to hold. That will give you performance benefit.
If you worry about performance of std::vector vs raw-arrays, then read the accepted answer here:
Is std::vector so much slower than plain arrays?
It explains why the code in the question is slow, which has nothing to do with std::vector itself, rather its incorrect usage.
If you cannot use either of them, and are forced to use int*, then I would suggest these two alternatives. Choose whatever suits your need.
struct array
{
int *elements; //elements
size_t size; //number of elements
};
That is self-explanatory.
The second one is this: allocate memory for one more element and store the size in the first element as:
int N = howManyElements();
int *array = int new[N+1]; //allocate memory for size storage also!
array[0] = N; //store N in the first element!
//your code : iterate i=1 to i<=N
//must delete it once done
delete []array;
sizeof(a) is going to be the size of the pointer, not the size of the allocated array.
There is no way to get the size of the array after you've allocated it. The sizeof operator has to be able to be evaluated at compile time.
How would the compiler know how big the array was in this function?
void foo(int size)
{
int * a;
a = new int[size];
cout << sizeof(a)/sizeof(int);
delete[] a;
}
It couldn't. So it's not possible for the sizeof operator to return the size of an allocated array. And, in fact, there is no reliable way to get the size of an array you've allocated with new. Let me repeat this there is no reliable way to get the size of an array you've allocated with new. You have to store the size someplace.
Luckily, this problem has already been solved for you, and it's guaranteed to be there in any implementation of C++. If you want a nice array that stores the size along with the array, use ::std::vector. Particularly if you're using new to allocate your array.
#include <vector>
void foo(int size)
{
::std::vector<int> a(size);
cout << a.size();
}
There you go. Notice how you no longer have to remember to delete it. As a further note, using ::std::vector in this way has no performance penalty over using new in the way you were using it.
If you are unable to use std::vector and std::array as you have stated, than your only remaning option is to keep track of the size of the array yourself.
I still suspect that your reasons for avoiding std::vector are misguided. Even for performance monitoring software, intelligent uses of vector are reasonable. If you are concerned about resizing you can preallocate the vector to be reasonably large.

Is it necessary to delete elements as an array shrinks?

I'm a student writing a method that removes zeros from the end of an array of ints, in C++. The array is in a struct, and the struct also has an int that keeps track of the length of the array.
The method examines each element starting from the last, until it encounters the first non-zero element, and marks that one as the "last element" by changing the value of length. Then the method walks back up to the original "last element", deleting those elements that are not out of bounds (the zeros).
The part that deletes the ith element in the array if i is greater than the updated length of the array, looks like this:
if (i > p->length - 1) {
delete (p->elems + i); // free ith elem
That line is wrong, though. Delete takes a pointer, yes? So my feeling is that I need to recover the pointer to the array, and then add i to it so that I will have the memory location of the integer I want to delete.
Is my intuition wrong? Is the error subtle? Or, have I got the entirely wrong idea? I've begun to wonder: do I really need to free these primitives? If they were not primitives I would need to, and in that case, how would I?
have I got the entirely wrong idea?
I'm afraid so.
If you make one new[] call to allocate an array, then you must make one delete[] call to free it:
int *p = new int[10];
...
delete[] p;
If your array is in a struct, and you make one call to allocate the struct, then you must make one call to free it:
struct Foo {
int data[10];
};
Foo *foo = new Foo;
...
delete foo;
There is no way to free part of an array.
An int[10] array actually is 10 integers, in a row (that is, 40 bytes of memory on a 32 bit system, perhaps plus overhead). The integer values which are stored in the array occupy that memory - they are not themselves memory allocations, and they do not need to be freed.
All that said, if you want a variable length array:
that's what std::vector is for
#include <vector>
#include <iostream>
struct Foo {
std::vector<int> vec;
};
int main() {
Foo foo;
// no need for a separate length: the current length of the vector is
std::cout << foo.vec.size() << "\n";
// change the size of the vector to 10 (fills with 0)
foo.vec.resize(10);
// change the size of the vector to 7, discarding the last 3 elements
foo.vec.resize(7);
}
If p->elems is a pointer, then so is p->elems + i (assuming the operation is defined, i.e. i is of integral type) - and p->elems + i == &p->elems[i]
Anyhow, you most likely don't want to (and cannot) delete ints from an array of int (be it dynamically or automatically allocated). That is
int* ptr = new int[10];
delete &ptr[5]; // WRONG!
That is simply something you cannot do. However, if the struct contains the length of the array, you could consider the array "resized" after you change the length information contained by the struct - after all, there is no way to tell the size of the array a pointer points to.
If, however your array is an array of pointers to integers (int*[]) and these pointers point to dynamically allocated memory, then yes, you could delete single items and you'd do it along the lines of your code (you are showing so little code it's difficult to be exact).

How to expand an array dynamically in C++? {like in vector }

Lets say, i have
int *p;
p = new int[5];
for(int i=0;i<5;i++)
*(p+i)=i;
Now I want to add a 6th element to the array. How do I do it?
You have to reallocate the array and copy the data:
int *p;
p = new int[5];
for(int i=0;i<5;i++)
*(p+i)=i;
// realloc
int* temp = new int[6];
std::copy(p, p + 5, temp); // Suggested by comments from Nick and Bojan
delete [] p;
p = temp;
You cannot. You must use a dynamic container, such as an STL vector, for this. Or else you can make another array that is larger, and then copy the data from your first array into it.
The reason is that an array represents a contiguous region in memory. For your example above, let us say that p points to address 0x1000, and the the five ints correspond to twenty bytes, so the array ends at the boundary of 0x1014. The compiler is free to place other variables in the memory starting at 0x1014; for example, int i might occupy 0x1014..0x1018. If you then extended the array so that it occupied four more bytes, what would happen?
If you allocate the initial buffer using malloc you can use realloc to resize the buffer. You shouldn't use realloc to resize a new-ed buffer.
int * array = (int*)malloc(sizeof(int) * arrayLength);
array = (int*)realloc(array, sizeof(int) * newLength);
However, this is a C-ish way to do things. You should consider using vector.
Why don't you look in the sources how vector does that? You can see the implementation of this mechanism right in the folder your C++ include files reside!
Here's what it does on gcc 4.3.2:
Allocate a new contiguous chunk of memory with use of the vector's allocator (you remember that vector is vector<Type, Allocator = new_allocator>?). The default allocator calls operator new() (not just new!) to allocate this chunk, letting himself thereby not to mess with new[]/delete[] stuff;
Copy the contents of the existing array to the newly allocated one;
Dispose previously aligned chunk with the allocator; the default one uses operator delete().
(Note, that if you're going to write your own vector, your size should increase "M times", not "by fixed amount". This will let you achieve amortized constant time. For example, if, upon each excession of the size limit, your vector grows twice, each element will be copied on average once.)
Same as others are saying, but if you're resizing the array often, one strategy is to resize the array each time by doubling the size. There's an expense to constantly creating new and destroying old, so the doubling theory tries to mitigate this problem by ensuring that there's sufficient room for future elements as well.