This seems like it should have a super easy solution, but I just can't figure it out. I am simply creating a resized array and trying to copy all the original values over, and then finally deleting the old array to free the memory.
void ResizeArray(int *orig, int size) {
int *resized = new int[size * 2];
for (int i = 0; i < size; i ++)
resized[i] = orig[i];
delete [] orig;
orig = resized;
}
What seems to be happening here is that resized[i] = orig[i] is copying values by reference rather than value, as printing orig after it gets resized returns a bunch of junk values unless I comment out delete [] orig. How can I make a deep copy from orig to resized, or is there some other problem that I am facing? I do not want to use std::vector.
Remember, parameters in C++ are passed by value. You are assigning resized to a copy of the pointer that was passed to you, the pointer outside the function remains the same.
You should either use a double indirection (or a "double pointer", i.e. a pointer to a pointer to int):
void ResizeArray(int **orig, int size) {
int *resized = new int[size * 2];
for (int i = 0; i < size; i ++)
resized[i] = (*orig)[i];
delete [] *orig;
*orig = resized;
}
or a reference to the pointer:
void ResizeArray(int *&orig, int size) {
int *resized = new int[size * 2];
for (int i = 0; i < size; i ++)
resized[i] = orig[i];
delete [] orig;
orig = resized;
}
By the way, for array sizes you should use the type std::size_t from <cstddef> - it is guaranteed to hold the size for any object and makes clear that we are dealing with the size of an object.
I highly suggest replacing the arrays with std::vector<int>. This data structure will resize as needed and the resizing has already been tested.
orig must be a pointer to a pointer to assign it to resized:
int **orig;
*orig = resized;
Related
The following snippet of code is my attempt to increase the size of an array by a factor of two. I am having several problems with it. Most importantly, should I be calling delete on my original array?
void enlarge(int *array, int* dbl int size) {
for (int i = 0; i < size; i++)
dbl[i] = array[i];
delete array;
array = dbl;
}
You have a few problems:
Modifying array only modifies the local copy of the pointer. You need to take a reference-to-pointer if you want the modification to be observed by the calling code.
You need to use delete[] when deleting things allocated with new[].
You attempt to copy too many items, and in so doing you overrun the original array.
void enlarge(int *& array, int size) {
// ^
// Use a reference to a pointer.
int *dbl = new int[size*2];
for (int i = 0; i < size; i++) {
// ^
// Iterate up to size, not size*2.
dbl[i] = array[i];
}
delete[] array;
// ^
// Use delete[], not delete.
array = dbl;
}
However, I would strongly suggest using std::vector<int> instead; it will automatically resize as necessary and this is completely transparent to you.
keyword double cannot be used as variable name, and previous array must be deleted before new allocation get assigned to same pointer, and loop should copy size no of items from prev array (not 2 * size)
void enlarge(int **array, int size) {
int *d = new int[size*2];
for (int i = 0; i < size; i++)
d[i] = *array[i];
delete [] *array;
*array = d;
}
if previous array was int *arr, and size is the currentsize of the array arr, call should be as: enlarge(&arr, size)
Okay, I'm writing a program that will perform different functions on an array. If necessary, the array will need to change capacity. The instructions are:
Create an new array.
Copy the contents from the old array to the new.
Delete the old array.
This part is understand, but what I don´t understand is how to keep a reference to the array that the functions will work with. This is my code for creating a new array and move over the elements.
int newSize = m_size*2;
double *tempArray= new double[newSize];
for(int i=0; i<m_size-1; i++)
{
tempArray[i] = arr[i];
}
delete []arr;
for(int i=0; i<m_size-1; i++)
{
arr[i] = tempArray[i];
}
delete []tempArray;
}
All the other methods use arr so I would like to reference back to that. A pointer won´t work since it only points to the first element. How can I use my arr variable to refer to an array?
In C and C++ dynamic arrays are usually represented by a pointer to the first element and the number of elements. So I'm assuming the following declarations:
double *arr;
int m_size;
If by any chance you have arr decleared as a real array double arr[..], then you cannot do delete []arr nor change its size!
Then your code should be along the lines of:
int newSize = 2*m_size;
double *tempArray= new double[newSize];
for(int i=0; i<m_size-1; i++)
{
tempArray[i] = arr[i];
}
delete []arr;
arr = tempArray;
m_size = newSize;
But now I wonder: why m_size-1 in the loop?
And also, you can just do:
memcpy(tempArray, arr, sizeof(*arr) * m_size)); //or m_size-1?
All this is nice if it is an exercise. For real code it almost always better to use std::vector<double> and the resize() member function.
You got undefined behaviour in your code.
delete []arr;
for(int i=0; i<m_size-1; i++)
{
arr[i] = tempArray[i];
}
You delete the memory arr was pointing to and then assign to the deleted memory inside the loop. Instead you should just write:
delete []arr;
arr = tempArray;
The whole code would be:
int newSize = m_size*2;
double *tempArray= new double[newSize];
for(int i=0; i<m_size-1; i++) // -1 might be wrong, look below for a comment on this line.
{
tempArray[i] = arr[i];
}
delete []arr;
arr = tempArray;
m_size = newSize // stolen from the others *cough* since I oversaw the need.
// note that I don't call delete on tempArray.
}
Also I don't know how you allocated your first array but if you made it calling new double[m_size] then you'd want to delete the -1 in the loop condition of the for loop since you're checking for i < m_size and not i <= m_size.
You need to allocate memory for ar after deallocating it.
int newSize = m_size*2;
double *tempArray= new double[newSize];
for(int i=0; i<m_size-1; i++)
{
tempArray[i] = arr[i];
}
delete []arr;
ar = new double[newSize];
for(int i=0; i<m_size-1; i++)
{
arr[i] = tempArray[i];
}
delete []tempArray;
delete []arr;
for(int i=0; i<m_size-1; i++)
{
arr[i] = tempArray[i];
}
Oops. Don't access after delete. And don't delete unless it was allocated with new.
You simply can't reallocate an array declared as
int arr[100]
or similar.
Based on the code you've given, what you're currently performing is:
Create a new array (tempArray)
Copy the contents of the old (arr) array to the new (temp) - (note - what happens if you make the new array smaller than the old?)
Delete the old array
Copy the new values back into the deleted remains of the old array (note - you deleted arr so you can't use it now!)
Delete the new array (so everything is gone)
Basically, you need to fix step 2, to handle sizes, and get rid of steps 4 and 5 entirely - you just need to re-assign arr instead:
arr = tempArray
You just have to declare the array arr and put the values in it. You can refer to the array through its pointer arr or each element with arr[element_id].
You have a couple of options here:
Take the C-style approach of just storing the pointer to the first element like you have, plus the length. From those two you can calculate anything you need.
Use std::vector. It holds an array, allows you to easily resize it with functions like emplace_back, and can tell you its length with the size function.
The second approach is certainly preferred. If you're in C++, you should usually be using std::vector instead of raw arrays, unless you're looking for a fixed-sized one. In that case use std::array.
You also get the added benefit of copying a vector being as simple as vector1 = vector2;.
Hello I have a generate array method:
void generateArray(double *data, int count) {
for (int i = 0; i < count; i++)
data[i] = rand() / ((rand() + rand()) / 2.0 + 1);
}
and I have below main
int main(void) {
double *arr;
generateArray(arr,40000);
cout << arr[0];
return 0;
}
it says arr is used before its value is set why? Why does not genearate array fills it? How can i fix this problem?
double *arr;
This only gives you a pointer. You haven't allocated any doubles for it to point at and you haven't initialised the pointer to actually point anywhere. Here, you'll find it easier to declare an array of the appropriate size instead:
double arr[40000];
Passing arr as you are currently doing will perform array-to-pointer conversion and it will work as expected.
However, an array of 40000 doubles is a pretty large object to have on the stack. You may prefer to dynamically allocate your array with double* arr = new double[40000];, but you would need to make sure you do delete[] arr; when you are done with it to avoid memory leaks. Instead, you might prefer to use a std::vector:
std::vector<double> arr(40000);
And simply change the first argument of generateArray to a std::vector<double>&.
You simply give it a pointer, but never allocate any memory for the array. You want a data = new double[count] in your generateArray, or to simply allocate it beforehand with double arr[40000] (or better yet, use a vector).
This would be preferable as:
std::vector<double> generateArray(int count) {
std::vector<double> data(count);
for (int i = 0; i < count; i++)
data[i] = rand() / ((rand() + rand()) / 2.0 + 1);
}
return data;
}
If you need to get array data back somehow, vector is guaranteed to utilize a contiguous array internally, accessible with &v[0] to &v[v.size()-1].
You never initialize the array with a size. You need to do
arr = new double[count];
inside the function. Like below. Don't forget to do delete[] arr; when you're done!
void generateArray(double *data, int count) {
arr = new double[count];
for (int i = 0; i < count; i++)
data[i] = rand() / ((rand() + rand()) / 2.0 + 1);
}
Another option would be doing double *arr = new double[40000] outside the function.
Constructor
This is how I'm allocating it:
char **board = new char*[width];
for(i = 0; i < width; i++){
board[i] = new char[height];
for(j = 0; j < height; j++)
board[i][j] = 0;
}
this->board = &board;
Inside the class, it's:
char ***board;
Destructor:
Now I want to delete it, so I wrote this (the board it the class field):
for(i = 0; i < width; i++)
delete (*board)[i];
delete (*board);
When running this:
Board* b = new Board(16, 30, 99);
delete b;
I get an Unhandled exception. Why?
You are storing a pointer to a variable on the stack, which becomes invalid as soon as the constructor returns. You should declare your class's data member as char **board and assign this->board = board.
EDIT: See also #Kerrek SB's comment. The local variable is redundant. Just use the data member directly (without the this->).
EDIT 2: Rectangular arrays are best created as a single array, using pointer arithmetic to index (which is what the compiler does with declared 2D arrays anyway):
char *board;
...
board = new char[width*height];
for(i = 0; i < width*height; ++i){
board[i] = 0;
}
...
char& operator()(int i, int j) { return board[width*i + j]; }
This has the advantage of requiring just one memory allocation (and therefore one delete[]). It also improves cache locality because the cells are contiguous.
Even better, if you know the dimensions at compile-time, use templates:
template <int W, int H>
class Board {
char board[W][H];
...
};
...
Board<8, 8>* b = new Board<8, 8>(...);
This requires no memory allocation at all (other than the new Board, of course).
Anything that you new you need to delete, in the exact same way:
board = new char*[width];
...
board[i] = new char[height];
...
...
delete[] board[i];
delete[] board;
No dereferencing is needed in this case.
You should use the powers of C++.
class Board
{
std::vector<std::vector<char>> board;
public:
Board(std::vector<std::vector<char>> const& board) : board(board) {}
Board(size_t x, size_t y, char val = 0)
{
std::vector<char> x2(x, val);
this->board(y, x2);
}
};
All you've got to do now is board[y].push_back(char_x_val) in order to append a new element to the end. You can treat board[y][x] just like any other 2D array (well, almost), but not worry about the deallocation.
Read up more on vectors here. (Anyone know a good tutorial?)
So i'm trying to avoid using vectors to do this, i know it would make it easier, but i'm trying to better my understanding of pointers and arrays. So is there a way to expand and shift an array without using the vectors? Here is what i have so far:
int *expand(int *&arr, int size)
{
int *newArray;
size = size * 2;
newArray = new int[size * 2];
for (int index = 0; index < size; index++)
newArray[index] = arr[index];
return newArray;
}
The simplest way to do what you want would be the standard library function realloc.
http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/
int* new_array = (int*) realloc (old_array, new_size * sizeof(int));
Note the *sizeof(int). That's important :)
realloc makes sure the contents of *old_array* can be found in *new_array*(it's either the same pointer, or the contents are copied). See the link for details.
In c++, try to avoid raw pointers. But since this is an exercise, this is a c++ way :
int *expand(int *&arr, int size)
{
int *newArray = new int[2*size];
std::copy( &arr[0],&arr[size], &newArray[0] );
// delete [] arr; // need to delete?
return newArray;
}
To do in place :
void expand(int *&arr, int size)
{
int *newArray = new int[2*size];
std::copy( &arr[0],&arr[size], &newArray[0] );
delete [] arr;
arr = newArray;
}
To do it manually, you need to copy the old data with the size of the original array, right now you're walking off the end of the original array.
Try this:
int *expand(int *&arr, int size)
{
int *newArray;
newArray = new int[size * 2];
for (int index = 0; index < size; index++)
newArray[index] = arr[index];
return newArray;
}
You're allocating twice as much memory as you need.
You're not deleting the old array.
You're not assigning the new pointer to arr - passing it as reference indicates that's what you intended - or that you intended to delete[] arr and assign 0 to it.
See this link for a method that uses memcpy instead of looping through individual items.
int *expand(int *&arr, int size)
{
size_t newSize = size * 2;
int* newArr = new int[newSize];
memcpy( newArr, arr, size * sizeof(int) );
size = newSize;
delete [] arr;
arr = newArr;
}
Since you aren't changing the value of arr inside the function, there's no need to pass the address by reference. If you did mean to change the value, you need to add a new line of code before the return newArray:
arr = newArray;
If the typical calling pattern is
arr = expand(arr, arr_size);
then you'll also need to watch out for options that ignore aliasing. And you'll have to make assumptions within expand that size is always doubled, and keep track of that yourself outside of it.
Also, your code has a terrible bug. size is doubled, and then used as the array limit for the source array. Then it leaks the memory that was previously allocated for arr. This is a good reason why people use std::vector. :-) Most of the bugs are out of that library, by now.
void expand_in_place(int *&arr, int& size)
{
const new_size = size * 2;
int *new_array = new int[new_size];
for (int index = 0; index < size; index++)
new_array[index] = arr[index];
delete[] arr;
arr = newArray;
size = new_size;
}
If you were using malloc and free instead of new [] and delete [], you could use realloc.