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.
Related
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.
User has to make an array from any amount of numbers and I need to rearrange the array, so that the elements from EVEN places would move to the start of an array and from UNEVEN places to the end. For example A=[1,2,3,4,5,6] would turn into B=[2,4,6,1,3,5]. Also I need to use POINTERS.... I am very bad at pointers, so help would be very much appreciated.
This is as far as I got myself. I am not using pointers here though, because I don't know how to.. :(
void switcharoo(int a, int b[]){
int temp[a], j=0;
for(int i=1;i<a;i+=2){
temp[j] = b[i];
j++;
}
for(int i=0;i<a;i+=2){
temp[j] = b[i];
j++;
}
b = temp;
}
Oups, you have still to improve your C++ knowledge...
int temp[a] is not valid C++ as you have been told in comment - Variable Length Arrays are a C feature
b is passed as a pointer (an arrays decays to a pointer to its first element when passed to a function). When you write b=temp; at the end of you function, you only change a local copy... which immediately goes out of scope: in short the current code is just a no-op.
array indices start at 0
If you want to train in using pointers, you could do something like that:
void switcharoo(int a, int b[]) {
int *even = new int[a]; // allocate an array of same size
int *odd = even + a / 2; // point at the mid array element
for (int i = 0; i<a - 1; i += 2) {
*odd++ = b[i]; // odd elements in high part
*even++ = b[i + 1]; // even in low part
}
if (0 != a % 2) { // one odd element remains
*odd++ = b[a - 1];
}
even = odd - a; // make even point again to start of allocated array
odd = even; // store a copy
for (int i = 0; i<a; i++) { // copy back in original array
b[i] = *even++;
}
delete[] odd; // and delete the allocated array
}
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)
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;
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.