Dynamic resizing array code not working in C++? - c++

I am trying to create an array, which doubles every time it is completely filled.
#include <iostream>
using namespace std;
int* array_doubler(int* array, int size){
int *new_array = new int[size*2];
for(int i = 0; i < size; i++){
new_array[i] = array[i];
}
delete[] array;
return new_array;
}
int main()
{
int N = 10; // Size of array to be created
int *array = new int[0];
for(int i = 0; i < N; i++)
{
if(array[i] == '\0')
array = array_doubler(array, i);
array[i] = i*2;
}
//Printing array elemensts
for(int i = 0; i < N; i++)
cout << array[i] << '\t';
cout << '\n';
return 0;
}
Problem is when I create dynamic memory with new, all the spots have the null character \0 value in them (not just the last spot). i.e. If i write:
int* p = new int[5];
then all the 5 blocks in memory p[0],p[1],p[2],p[3],p[4],p[5] have \0 in them, not just the p[5]. So the if(array[i] == '\0') in my main() calls array_doubler for every single iteration of for loop. I want it to fill the available spots in the array first and when it reaches the last element, then call array_doubler.

Problem is when I create dynamic memory with new, all the spots have the null character \0 value in them (not just the last spot).
Actually they have undefined values in them. 0 is a valid value for them to have, but tomorrow the compiler might suddenly decide that they should all have 1 instead of 0.
If you want to detect the end of an array, then you have to remember how big the array is. C++ doesn't do it for you. Actually, it does do it for you if you use std::vector, but I suppose that's not the point of this exercise.

I'm not sure why you'd want to do this, as std::vector offer this kind of feature, and are more idiomatic of c++ (see isocpp faq on why C-style array are evil).
One of the issue of C-style array is the fact that they don´t know their own size, and that they don't have default value, thus stay uninitialized.
If for some reason you need to not use std::vector, the next best solution would be to wrap the array with it's size in a structure or a class (which is kinda what std::vector is doing), or to initialize your array using std::memset (which is the C function you would use if you were in C).
Do keep in mind that this is not considered as good practices, and that the STL offer plenty of solution when you need containers.

Related

Can I use std::sort on heap allocated raw arrays?

We know that when using a contiguous block of memory we can easily get an iterator (here &arra[0] or arra) and pass the iterators to std::sort.
for instance:
int arra[100];
for (int i = 0; i < 100; i++) {
arra[i] = rand() % 32000;
}
for (int i = 0; i < len; i++)std::cout << arra[i]<<" ";
std::sort(arra,arra+100);
Now if I have a heap allocated array, say, like arr here:
int len;
len = 100;
int* arr = new int[len];
for (int i = 0; i < len; i++) {
arr[i] = rand() % 32000;
}
I don't know whether I can get an iterator for this array, so can I use std::sort for this array at all?
if not, are there any workarounds to using std::sort on such an array?
Pointers do meet criteria of RandomAccessIterator which is required by std::sort. It doesn't matter if they point to stack memory or heap memory, as long as they point to the same (contiguous) array. So you can simply use:
std::sort(arr, arr + len);
This being said, std::vector is probably a better choice for allocating an array on the heap. It will save you the headache of managing memory on your own.
Yes, you can use std::sort in the same way in both cases, std::sort does not know or care how the memory was allocated.
In the C++ Library, Iterators are basically Fancy Pointers. As such, it is standard-compliant to just increment the pointer to the end of the array to get the "end" pointer:
#include<algorithm>
#include<iostream>
int main() {
int len;
len = 100;
int* arr = new int[len];
for (int i = 0; i < len; i++) {
arr[i] = rand() % 32000;
}
//Valid, Defined Behavior that works as expected
std::sort(arr, arr + len);
//alternative, to make the code easier to read:
//auto begin = arr;
//auto end = arr + len;
//std::sort(begin, end);
for(int i = 0; i < len; i++)
std::cout << arr[i] << std::endl;
}
However, some Compilers (like Visual Studio's compiler) recognize that this kind of code is inherently unsafe, because you're required to manually supply the length of the array. As a result, they will cause a (suppressible with a Compiler flag, if you need to) Compile-time error if you try to do this, and advise you use a compiler-provided utility instead:
#include<algorithm>
#include<iostream>
int main() {
int len;
len = 100;
int* arr = new int[len];
for (int i = 0; i < len; i++) {
arr[i] = rand() % 32000;
}
//MSVC Specific Code!
auto begin = stdext::make_checked_array_iterator(arr, len);
auto end = arr + len;
std::sort(begin, end);
for(int i = 0; i < len; i++)
std::cout << arr[i] << std::endl;
}
For more on this particular quick of the Visual Studio compiler, see here: https://learn.microsoft.com/en-us/cpp/standard-library/checked-iterators?view=vs-2019
Can I use std::sort on heap allocated raw arrays?
Yes.
I don't know whether I can get an iterator for this array
You can.
A pointer to element is a random access iterator for arrays. In the case of an automatic array, the array name implicitly decays into a pointer that you can use as an iterator to beginning of the array. In the case of a dynamic array, the result of new[] is already a pointer i.e. an iterator to the beginning of the array. You can get the pointer to the end using pointer arithmetic just like in your example.
The only significant difference between an array variable, and a pointer to a dynamic array regarding the use of std::sort is that you cannot use std::end or std::size with a pointer like you could with an array variable. Instead, you need to separately know the size of the array. In this case you've stored the length in the variable len.

Replace dynamic allocation with a static one

I have a project and I have to define an array of arrays of different dimensions (like a triangle) because I am not allowed to use std::vector or other container class. For this, I am using an array of pointers. Normally, I would do this:
int* triangle[n];
for(int i = 0; i < n; i++) {
triangle[i] = new int[i + 1];
for(int j = 0; j <= i; j++) cin >> triangle[i][j];
}
But I must not use dynamic memory! I thought that doing
int* triangle[n];
for(int i = 0; i < n; i++) {
int row[i + 1];
triangle[i] = row;
for(int j = 0; j <= i; j++) cin >> triangle[i][j];
}
would do the trick. But it didn't. Instead, when I iterate over the arrays and print the contents, I get garbage. So, how can I replace a dynamic allocation with a static one?
So, if you want "array of arrays" simplified, your choice is array linearization. It means that instead of 7 arrays of 10 items each you should declare single array of 70 elements. Then, just change nested indexes with a function that calculates resulting shift in linearized array, and viola!
Here you can find one of such examples: How to map the indexes of a matrix to a 1-dimensional array (C++)?
In case you don't know in advance how long is your array, it may be a tough choice to determine preliminary reservation size (for example, STL containers like vector etc. do the same trick: they allocate a chunk of memory then grow the container until free capacity left, then re-allocate bigger chunk moving the data from old to new buffer, and again, and again, and again...)
As #BeyelerStudios pointed out in the comments, at the end of the for loop, the memory allocated for the row array gets freed. When I am trying to print out the contents, I am dereferencing pointers to this freed up memory, so I am getting garbage. Thank you!

Pointer/Refer to an array?

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;.

pushback data from vector to vector of map

i have created a map called select_p and vector of this map is called pts. i have stored data in a array and i want to pushbcak these data into my vector of map. i tried this by inserting value of array into new vector and then pushback into my map.but it is not working please help me to correct these codes? thanks
#include<iostream>
#include<cstdlib>
#include <map>
#include <vector>
using namespace std;
int main()
{
int M=7;
int N=6;
int i=0;
int * temp;
map<int,vector<int> > select_p;
vector<int>pts;
for (int m=0; m<M; m++)
{
for (int n=0; n<N; n++)
{
vector<int>id;
if (n==0 && m==5)
{
temp = new int[3,i+N,i+N+1,i+1];
unsigned ArraySize = sizeof(temp) / sizeof(int);
id.insert(id.begin(),temp[0], temp[ArraySize]);
select_p[i].push_back(id);
}
i++;
}
}
delete[] temp;
system("PAUSE");
return 0;
}
for (int m=0; m<M; m++) {
for (int n=0; n<N; n++) {
if (n==0 && m==5) {
Why are you looping when you only actually do anything for a single pair of values of m and n? The loops are completely useless here; you would get the same effect by just setting n = 0 and m = 5.
temp = new int[3,i+N,i+N+1,i+1];
Whatever you think this does, that's not what it does. This is equivalent to temp = new int[i+1];. The rest of the expression inside of the [] has no effect.
That said, you should not use new to create arrays in your program. Use std::vector; it is far easier to use correctly.
unsigned ArraySize = sizeof(temp) / sizeof(int);
This does not work. When you dynamically allocate an array, you are responsible for keeping track of how many elements are in it. Given a pointer to a dynamically allocated array (like temp here) there is no way to determine the number of elements in the array.
What you have is equivalent to sizeof(int*) / sizeof(int), which is not going to do what you expect.
id.insert(id.begin(),temp[0], temp[ArraySize]);
std::vector::insert takes a range of iterators: you have provided it with two values. Presumably you want to use temp, which points to the initial element of the dynamically allocated array, and temp + i + 1, which points one past the end of the array. That said, since you haven't set the values of the elements in the array, you are copying uninitialized memory, which probably isn't what you mean to do.
select_p[i].push_back(id);
select_p[i] is a std::vector<int>. std::vector<int>::push_back() takes a single int that is appended to the sequence. Presumably you just mean to use assignment to assign id to select_p[i].
You should get a good introductory C++ book if you want to learn to program in C++. I am sorry to say that your program is nonsensical.

Expanding a dynamically allocated array

I have allocated an array as follows.
#include <iostream>
int main() {
const int first_dim = 3;
const int second_dim = 2;
// Allocate array and populate with dummy data
int** myArray = new int*[first_dim];
for (int i = 0; i < first_dim; i++) {
myArray[i] = new int[second_dim];
for (int j = 0; j < second_dim; j++) {
myArray[i][j] = i*second_dim + j;
std::cout << "[i = " << i << ", j = " << j << "] Value: " << myArray[i][j] << "\n";
}
}
// De-allocate array
for (int i = 0; i < first_dim; i++)
delete[] myArray[i];
delete[] myArray;
}
Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
I've heard that Vectors are so much more efficient for this purpose, but I hardly know what they are and I've never used them before.
Yes, but in a very painful way. What you have to do is allocate new memory which now has your new desired dimensions, in this case 4 and 2, then copy all the contents of your matrix to your new matrix, and then free the memory of the previous matrix... that's painful. Now let's see how the same is done with vectors:
#include <vector>
using std::vector;
int main()
{
vector< vector <int> > matrix;
matrix.resize(3);
for(int i = 0; i < 3; ++i)
matrix[i].resize(2);
matrix[0][1] = 4;
//...
//now you want to make the first dimension 4? Piece of cake
matrix.resize(4);
matrix[3].resize(2);
}
HTH
edit:
some comments on your original code:
In C++ ALL_CAP_NAMES usually refer to macros (something you #define). Avoid using them in other contexts
why do you declare FIRSTDIM and SECONDDIM static? That is absolutely unnecessary. If a local variable is static it means informally that it will be the same variable next time you call the function with kept value. Since you technically can't call main a second sime this is useless. Even if you could do that it would still be useless.
you should wrire delete [] array[i]; and delete [] array; so the compiler knows that the int* and int** you're trying to delete actually point to an array, not just an int or int* respectively.
Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
Yes, but it's a pain in the neck. It basically boils down to allocating a new array, just as your existing code does (hint: put it in the function and make the sizes arguments to that function) and copying compatible elements over.
Edit: One of the things that std::vector does for you is properly de-allocating you memory. In the code you have, failure to allocate one of the arrays along the 2nd dimension will result in a memory leak. A more robust solution would initialize pointers to 0 before performing any allocation. An exception block could then catch the exception and free whatever was partially allocated.
Because this code becomes complex quickly, people resort to allocating a single buffer and addressing using a stride or using a 1D array of 1D arrrays (i.e. std::vector of std::vectors).