copying static array to dynamic array c++ - c++

So I was playing around with some basics in c++ when I noticed this:
int * ptr = new int[3], arr[3] = { 11,13,15 };
for (int i = 0; i < 3; i++)
ptr[i] = arr[i];
cout << ptr[0] << ' ' << ptr[1] << ' ' << ptr[2] << endl;
this code will perfectly insert and print out the values: 11 13 15.
Whereas when I write it this way:
int size=0, * ptr = new int[size], arr[3] = { 11,13,15 };
for (int i = 0; i < 3; i++)
{
ptr = new int[++size];
ptr[i] = arr[i];
}
cout << ptr[0] << ' ' << ptr[1] << ' ' << ptr[2] << endl;
When I increment the size one value at a time, it prints out:
-842150451 -842150451 15
Why is it that when I define the total size at the beginning, the values are properly inserted, however when I increment one step at a time it does not? Also, is there any way to write the second code but in a way where it works please?

As #Ch3esteR points out in the comment. The problem is that you are reallocating your
array on each iteration, and thereby zeroing (or in your case, catching some random
values on the heap).
I would say that the bigger solution might be to use standard containers for handling memory. Here is a solution for fixing your original code original() and a proposed alternative for how to handle dynamic arrays with std::vector.
#include <vector>
#include <iostream>
using namespace std;
void original() {
const int arr[3] = { 11,13,15 };
const int size=3;
auto ptr = new int[size]; // this is what you want to do
std::copy(arr, arr + size, ptr); // Standard function for copying
cout << ptr[0] << ' ' << ptr[1] << ' ' << ptr[2] << endl;
}
int main() {
original();
const int arr[3] = { 11,13,15 }; // You might want to make this a std::vector too
std::vector<int> result{arr, arr + 3};
// std::vector<int> result; // Or if the question was how to do it dynamically
// for (auto i: arr)
// {
// result.push_back(i); // Dynamic add
// }
cout << result[0] << ' ' << result[1] << ' ' << result[2] << endl;
}
On request: How to do it with pointers (don't do this unless you have some external constraint that forces you to do this, like a teacher)
#include <iostream>
using namespace std;
// Reallocate memory and delete the old pointer
int *resize(int *arr, size_t oldSize, size_t newSize) {
auto newArr = new int[newSize];
auto copySize = std::min(oldSize, newSize); // Handle both growing and shrinking resize
std::copy(arr, arr + copySize, newArr); // Copy your old data
// Or do it like this
// for (size_t i = 0; i < copySize, ++i) {
// newArray[i] = arr[i]
// }
delete [] arr;
return newArr;
}
int main() {
auto arr = new int[2] { 11,13 }; // Observe 'new' here
size_t size = 3;
// "resize" the array arr (in practice you are just creating a new one)
arr = resize(arr, size, size + 1);
// Assign your new value
arr[2] = 14;
cout << arr[0] << ' ' << arr[1] << ' ' << arr[2] << endl;
delete [] arr; // Remember, try to not manual memory management,
// only use it in class when you are learning the basics, otherwise use
// std::unique_ptr or std::shared_ptr
}

Related

Dynamically allocate an array from a textfile and retain its values

After looking at some other similar questions, this is what I've written so far:
#include <iostream>
#include <fstream>
#include <string>
void read_from_file() {
int* arr;
int length;
std::string file_name = "data.txt";
std::ifstream file_data;
file_data.open(file_name.c_str());
if (file_data.is_open())
{
file_data >> length;
arr = new int[length];
for (int i = 0; i < length; i++)
{
file_data >> arr[i];
std::cout << arr[i] << " ";
}
file_data.close();
}
else
std::cerr << "Cannot open the file " << file_name << std::endl;
}
All good here, until I try to manipulate the array's values. For example, I have to check if the array is sorted in ascending order. I don't know how to get back where I read the array and get the values.
bool check_if_sort_asc(int* arr, int length)
{
for (int i = 0; i < length - 1; i++)
if (arr[i] > vect1[i + 1])
return false;
return true;
}
int main()
{
int *arr;
int length;
read_from_file();
if (check_if_sort_asc(arr, length)==true)
std::cout << " The array is sorted in ascending order ";
else
std::cout << "The array is not sorted in ascending order ";
return 0;
}
The immediate fix is this
Change read_from_file to return the data it read
int * read_from_file() {
int *arr = NULL;
then return arr at the end of it
else
std::cerr << "Cannot open the file " << file_name << std::endl;
return arr;
}
and finally use the returned value in main
arr = read_from_file();
and free it when you have finished
delete [] arr;
But your code doesnt compile, because of that vect1 stuff, plus you should use std::vector.
As Bob_ points out you need the length too, so either
use std::vector
make the arr array one bigger and place the length as first entry
use std::vector
pass a length int by reference into read_form_file (see below)
use std::vector
ie
int * read_from_file(int * length) {
int *arr = NULL;
...
file_data >> *length;
But mainly, use std::vector

Using vector::data() chaining with member function print differnet values as pointer arithmetic

I have a class hello with a method which returns a vector member.
I am trying to print out values using vector::data() with pointer arithmetic, but I am facing an undefined behavior. See example below:
class hello
{
public:
std::vector<int> data()
{
return v;
}
private:
std::vector<int> v{1, 2, 3, 4};
};
int main(int argc, const char **argv)
{
hello h;
std::cout << "----------------------------" << std::endl;
for (int i = 0; i < 4; i++)
{
std::cout << &*(h.data().data() + i) << std::endl;
std::cout << *(h.data().data() + i) << std::endl;
}
int *sa = h.data().data();
std::cout << "----------------------------" << std::endl;
for (int i = 0; i < 4; i++)
{
std::cout << sa + i << std::endl;
std::cout << *(sa + i) << std::endl;
}
return 0;
}
The result looks like this:
----------------------------
0x9e2ee0
1
0x9e2ee4
2
0x9e2ee8
3
0x9e2eec
4
----------------------------
0x9e2ee0
0
0x9e2ee4
0
0x9e2ee8
10289168
0x9e2eec
0
Why do *(sa + i) and *(h.data().data() + i) print different values?
sa + i and &*(h.data().data() + i) prints the same memory address, why I can not get the correct data just use this memory address (sa + i)
hello::data() is returning a vector by value, which means it will return a temporary copy of hello::v, which will allocate its own int array and copy the values from v.
When calling h.data(), that temporary vector will be destroyed when it goes out of scope at the end of the full statement that called h.data().
So, in your 1st loop:
for (int i = 0; i < 4; i++)
{
std::cout << &*(h.data().data() + i) << std::endl;
std::cout << *(h.data().data() + i) << std::endl;
}
This is perfectly valid code, as the temporary vector returned by each call to h.data() will not be destroyed until after its inner data has been printed.
However, in your 2nd loop:
int *sa = h.data().data();
for (int i = 0; i < 4; i++)
{
std::cout << sa + i << std::endl;
std::cout << *(sa + i) << std::endl;
}
In the statement that is calling h.data():
int *sa = h.data().data();
The temporary vector gets destroyed when it goes out of scope at the end of the statement, leaving sa to be a dangling pointer to freed memory, thus any use of sa inside the loop is undefined behavior.
sa + i and h.data().data() + i may point at the same memory address, but only if this last call to h.data() happens to create a new vector that reuses the same memory block that the temporary vectors in the 1st loop used, but that is not a guarantee. In any case, sa is pointing at freed memory, so it doesn't matter if the memory block was reused or not, the vector that owned that memory block is destroyed, freeing the memory, before the 2nd loop is entered. That is why you can't access the data, even if the memory addresses were the same.
To fix this issue, you need to change hello::data() to return a reference to hello::v instead, then no copy will be created, eg:
class hello
{
public:
std::vector<int>& data() // <-- note the &
{
return v;
}
private:
std::vector<int> v{1, 2, 3, 4};
};
Thus each call to h.data().data() will return a valid pointer to v's internal data, thus sa will not be a dangling pointer anymore.
Alternatively, have hello::data() return a pointer to v's data, rather than returning (a reference to) v itself, eg:
class hello
{
public:
int* data()
{
return v.data();
}
private:
std::vector<int> v{1, 2, 3, 4};
};
...
for (int i = 0; i < 4; i++)
{
std::cout << &*(h.data() + i) << std::endl;
std::cout << *(h.data() + i) << std::endl;
}
...
int *sa = h.data();
for (int i = 0; i < 4; i++)
{
std::cout << sa + i << std::endl;
std::cout << *(sa + i) << std::endl;
}
You returned a temporary copy of your vector. After the statement it is part of it is destroyed. If you wanted to keep it around you need to assign it to another vector.
So, you made a pointer to a temporary value which got erased. It no longer exists, and you're trying to point to pieces of its corpse.

print an array after deep copying in c++ classes

I want to achieve the following behaviour:
The class DataSequence has a pointer that points to an array in the main function.
print the array when an object in initialised of the class DataSequence
create a deep-copy of the same object (via a copy constructor) and print it when the object is formed.
The code I have written is as follows:
#include<bits/stdc++.h>
using namespace std;
class DataSequence{
float *ptr;
int _size;
public:
DataSequence(float input[] , int size){
_size = size;
ptr = new float; ptr = input;
//print the array
cout << "Main constructor" << endl;
for(int i=0 ; i<_size; ++i){
cout << *(ptr+i) << " ";
// ++ptr;
}
}
//copy constructor
DataSequence(DataSequence &d){
_size = d._size;
ptr = new float; *ptr = *(d.ptr);
//print the array
cout << "copy constrructor" << endl;
for(int i=0 ; i<_size ; ++i){
cout << *(ptr+i) <<" ";
// ++ptr;
}
}
};
int32_t main(){
int size=4;
float input[size];
int bins;
input[0] = 3.4;
input[1] = 1.3;
input[2] = 2.51;
input[3] = 3.24;
DataSequence d(input , size);
cout << endl;
DataSequence d1 = d;
return 0;
}
The output is as follows
Main constructor
3.4 1.3 2.51 3.24
copy constrructor
3.4 2.42451e-038 -2.61739e-019 3.20687e-041
I am unable to figure out why I am getting garbage from the copy constructor, can someone help.
This statement:
ptr = new float;
only allocates a single float. That means in this loop:
for(int i=0 ; i<_size; ++i){
cout << *(ptr+i)
as soon as i is greater than 0, you dereference invalid memory, which is undefined behavior. This results in a program that can do anything, including producing the "garbage" output you see.
If you want to allocate an array, you need to do:
ptr = new float[_size];
and to delete it, you need to do:
delete [] ptr;
Note that even if you allocate memory correctly as shown above, you are not actually copying the data from the argument. Just setting pointers would do a shallow copy which is not what you want.
You can do a deep copy like this:
std::copy(d.ptr, d.ptr + _size, ptr);

Is this the correct way to allocate and delete dynamic memory in C++?

I have an assignment for class, in which I need to create 3 functions to test with constant arguments. I am also supposed to create and delete dynamic memory. I have attached the exact directions from the assignment, just in case, as well as my code.
I apologize if the code is messy. I am a beginning programmer and new to the site, so I'm not exactly sure how to format everything perfectly.
Directions from assignment:
Write a C++ program that will test three functions described below that use pointers and dynamic memory allocation.
Expand: takes an int array and the array's size as parameters. It should create a new array that is twice the size of the argument array. The function should copy the contents of the argument array to the new array, and initialize the unused elements of the new array with -1. The function should return a pointer to the new array.
concatenate: takes two int arrays and the arrays' sizes as parameters (that's 4 parameters). It should create a new array big enough to store both arrays. Then it should copy the contents of the first array to the new array, and then copy the contents of the second array to the new array in the remaining elements, and return a pointer to the new array.
subArray: It takes an int array, a start index and a length as arguments. It creates a new array that is a copy of the elements from the original array starting at the start index, and has length equal to the length argument. For example, subArray(aa,5,4) would return a new array containing only the elements aa[5], aa[6], aa[7], and aa[8].
My code:
#include <iostream>
using namespace std;
int* Expand(int [], int);
int* concatenate(int[], int, int[], int);
int* subArray(int[], int, int);
int main()
{
//Declare variables
const int SIZEAA = 10;
const int SIZEBB = 5;
int aa[SIZEAA] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int bb[SIZEBB] = { 11, 22, 33, 44, 55 };
//Output both original arrays
cout << "aa[10]: ";
for (int i = 0; i < SIZEAA; i++)
cout << aa[i] << " ";
cout << endl;
cout << "bb[5]: ";
for (int i = 0; i < SIZEBB; i++)
cout << bb[i] << " ";
cout << endl;
//Call the Expand function
int* aaExpand = Expand(aa, SIZEAA);
//Output expanded array
cout << "Testing Expand: ";
for (int i = 0; i < 20; i++)
cout << aaExpand[i] << " ";
//Release dynamic memory
delete[] aaExpand;
aaExpand = nullptr;
cout << endl;
//Call the concatenate function
int* concatenateArray = concatenate(aa, SIZEAA, bb, SIZEBB);
//Output concatenated array
cout << "Testing concatenate: ";
for (int i = 0; i < (SIZEAA + SIZEBB); i++)
cout << concatenateArray[i] << " ";
//Release dynamic memory
delete[] concatenateArray;
concatenateArray = nullptr;
cout << endl;
//Call subArray function
int* arraySub = subArray(aa, 5, 4);
//Output the sub array
cout << "Testing subArray: ";
for (int i = 0; i < 4; i++)
cout << arraySub[i] << " ";
//Release dynamic memory
delete[] arraySub;
arraySub = nullptr;
cout << endl;
}
int* Expand(int aa[], int size) /*This function takes in an array and
the size as parameters, creates a new array of double the size, and copies
the old array into it.It then adds -1 into all new spaces created.
It returns a pointer to the new array*/
{
//Declare new array
int* aaNew;
int newSize = size * 2;
aaNew = new int[newSize];
//Copy old array into new array
for (int i = 0; i < newSize; i++)
{
if (i >= 0 && i < size) //Check to see if it needs to copy an old value in or put -1 into the array
aaNew[i] = aa[i];
else
aaNew[i] = -1;
}
return aaNew;
}
int * concatenate(int aa[], int sizeAA, int bb[], int sizeBB) /*This
function takes in two different arrays, creates a new array, then copies
both arrays into the new array.It returns a pointer to the new array*/
{
//Create new array size
int newSize = (sizeAA + sizeBB);
//Create new array
int* concatArray;
concatArray = new int[newSize];
//Add elements of first and second array into new array
for (int i = 0; i < newSize; i++)
{
if (i >= 0 && i < sizeAA) //Check to see if a value from the first or second array is supposed to be added
concatArray[i] = aa[i];
else
concatArray[i] = bb[i - sizeAA];
}
return concatArray;
}
int * subArray(int a[], int start, int length) /* This function takes in
an array, a start value, and a length value. It creates a new array and
copies the values of the original array starting at the passed start value
and continues until the new array is the length of the passed length value.
It returns a pointer to the new array*/
{
//Create new array size
int subSize = length;
//Create a new array
int* sub;
sub = new int[subSize];
//Add elements of original array starting at the passed start value into new
array until the new array is the length specified by the argument
for (int i = 0; i < subSize; i++)
{
sub[i] = a[start];
start += 1;
}
return sub;
}
Your set up is very good. Glad to see you're getting the hang of it. Your functions could use some optimization, however. Before we begin, Id 'd like to note that C++ has a std::vector class which dynamically allocates memory as needed and supplies many powerful mod functions. I'd recommend checking that out as it would take your program to the next level.
To begin, Your Expand()function is pretty well set up. Just some minor modifications: to clean up your code,
int* aaNew;
int newSize = size * 2;
aaNew = new int[newSize];
can simply become:
int newSize = size * 2;
int *aaNew = new int[newSize];
and within your for loop, there is no need to check the complete range of i, only its upper bound:
if (i >= 0 && i < size)
can become:
if (i < size)
This will have the same result as your if-statement but is more elegant since i will never be less than 0.
Moving on, your concatenate() function could become a lot simpler. While what you are doing is technically correct and works, your concatenate() function could simplify to:
int * concatenate(int aa[], int sizeAA, int bb[], int sizeBB) {
int * result = new int[sizeAA + sizeBB];
copy(aa, aa + sizeAA, result);
copy(bb, bb + sizeBB, result + sizeAA);
return result;
}
Furthermore, in your subArray() function, you can reduce:
//Create new array size
int subSize = length;
//Create a new array
int* sub;
sub = new int[subSize];
to:
//Create new array size
int subSize = length;
int *sub = new int[subSize];
Lastly, your main function could use an overhaul. Consider adding a writeArray() function since you are repeating that task often:
string writeArray(int ar[], int arLength) {
string ret = "";
for (int i = 0; i < arLength; i++)
ret += " " + to_string(i);
return ret + "\n";
}
That way your main() can become:
int main() {
//Declare variables
const int SIZEAA = 10, SIZEBB = 5;
int aa[SIZEAA] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int bb[SIZEBB] = { 11, 22, 33, 44, 55 };
//Output both original arrays
cout << "aa[10]: " << writeArray(aa, SIZEAA);
cout << "bb[5]: " << writeArray(bb, SIZEBB);
//Call the Expand function
int *aaExpand = Expand(aa, SIZEAA);
cout << "Testing Expand: " << writeArray(aaExpand, SIZEAA * 2);
//Call the concatenate function
int *concatenateArray = concatenate(aa, SIZEAA, bb, SIZEBB);
cout << "Testing concatenate: " << writeArray(concatenateArray,
(SIZEAA + SIZEBB));
//Call subArray function
int *arraySub = subArray(aa, 5, 4);
cout << "Testing subArray: " << writeArray(arraySub, 4);
//Output the sub array
//Release dynamic memory
delete[] aaExpand;
delete[] concatenateArray;
delete[] arraySub;
aaExpand = nullptr;
concatenateArray = nullptr;
arraySub = nullptr;
}
The rest of your program looks decent. Keep up the good work!
int* Expand(int elements[], int size)
{
int* new_elements = new int[2 * size];
for (int i = 0; i < size; i++)
{
new_elements[i] = elements[i];
new_elements[i + size] = -1;
}
return new_elements;
}
int* concatenate(int first[], int firstSize, int second[], int secondSize)
{
int* elements = new int[firstSize + secondSize];
for (int i = 0; i < firstSize; i++)
{
elements[i] = first[i];
}
for (int j = 0; i < secondSize; j++)
{
elements[firstSize + j] = second[j];
}
return elements;
}
int* subArray(int elements[], int offset, int size)
{
int* new_elements = new int[size];
for (int i = 0; i < size; i++)
{
new_elements[i] = elements[offset + i];
}
return new_elements;
}

Appending to an array in Dynamic Memory

Using dynamic memory, I am trying to make a class that stores numbers in a dynamic array (so 123 would be arr[0] = 1, arr[1] = 2, arr[2] = 3) and be able to append digits (e.g. if the number stored is 123, you could add more digits.. 45 and the new number would be 12345).
Here's my code so far: How would I go about making an append function?
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
int *exampleArray; //new array into exsistence
exampleArray = new int[5]; // dynamically allocates an array of 5 ints
for (int i = 1; i < 5; i++)
{
exampleArray[i] = i;
cout << exampleArray[i] << endl;
}
delete exampleArray; // deleted from exsistence
system("pause"); // to show the output
return 0;
}
If you allocate an array with new[], the only way to "append" to it is to new[] a new array of larger size, copy the existing values from the old array into it, and then delete[] (not delete) the old array and update your array pointer to point at the new array.
Also, note that arrays are 0-indexed. Your loop is not populating exampleArray[0] with any data.
For example:
int *arr = new int[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
...
int *newarr = new int[5];
std::copy(arr, arr+3, newarr);
newarr[3] = 4;
newarr[4] = 5;
delete[] arr;
arr = newarr;
...
delete[] arr;
You can optimize this a little by pre-allocating more memory than you actually need, and only "grow" when you actually exceed that memory. For example:
int *arr = NULL;
int num = 0, cap = 0;
void append(int digit)
{
if (num == cap)
{
int *newarr = new int[cap + 10];
std::copy(arr, arr+num, newarr);
delete[] arr;
arr = newarr;
cap += 10;
}
arr[num] = digit;
++num;
}
...
append(1);
append(2);
append(3);
...
append(4);
append(5);
...
delete[] arr;
That being said, what you are asking for would be best handled using std:vector instead. It is a dynamic-length container that handles these ugly details for you.
For example:
std::vector<int> arr;
void append(int digit)
{
arr.push_back(digit);
}
...
append(1);
append(2);
append(3);
...
append(4);
append(5);
...
An alternative solution that would not require you to use the std::vector container or any additional pointers would be to use the malloc()/realloc()/free() family of functions in the cstdlib C++ header as follows:
int *exampleArray;
exampleArray = (int *) malloc(5 * sizeof(int));
for (int i = 1; i < 5; i++)
{
exampleArray[i] = i;
cout << exampleArray[i] << endl;
}
// Now to add further elements
exampleArray = (int *) realloc(7 * sizeof(int)); // Added space for 2 new elements
for (int i = 5; i < 7; i++) {
exampleArray[i] = i;
cout << exampleArray[i] << endl;
}
free(exampleArray);