Doubling of an arbitrary array of strings - c++

1: My goal is to create two arbitrary arrays using pointers: one with names, another one with corresponding numbers. From my previous question, I know that doubling an array is a good way to deal with arbitrary sizes. So, I am trying to double both arrays correspondingly. But while the doubling of an int array goes well, array of strings does not double. Could you explain, what is the problem with that?
2: Is there an alternative to the creation of arbitrary array of strings to store list of names?
Here is the part of the code:
string *pn = new string [size];
int *pd = new int [size];
while (x != 0) {
if (size == k+1) {
pn = doubn (pn, size);
pd = doubd (pd, size);
}
pn[k] = name;
pd[k] = val;
cout << "Another entry? (0 for exit)";
cin >> x;
getline (cin, name, ',');
cin >> val;
++k;
}
for (int i = 0; i<k; ++i) {
cout << pn[i] << " - " << pd[i] << " days"; }
del (pn, pd, k);
cin.get ();
cin.ignore();
}
string* doubn (string *pn, int size) {
string* pnn = new string [size*2];
for (int i = 0; i < size; ++i) {
pnn [i] = pn[i]; }
delete pn;
return pnn; }
int* doubd (int *pd, int size) {
int *pdn = new int [size*2];
for (int i = 0; i<size; ++i) {
pdn [i] = pd[i];}
delete pd;
return pdn;}

To have arbitrary sized arrays, use vectors.
Vectors are a part of the C++ Standard Template Library (STL) and required the #include<vector> header.
For more information, check this out: http://www.cplusplus.com/reference/vector/vector/
Also, you should be using delete [] instead of delete.

You use delete on memory allocated by new[], you should use delete[] instead.
Using std::vector would be simpler and less error prone anyway.

Related

return a dynamically allocated array of the same length but with the elements in the reverse order

Write a function, reverseArray, that when passed an int array of length greater than 0 will return a dynamically allocated array of the same length but with the elements in the reverse order. For example, if passed the array, {1,2,3,4,5,6,7,8,9,0} the function would return the array {0,9,8,7,6,5,4,3,2,1}.
Below is my code, but there is a bug in it.
This is my output.
1
2
3
4
5
6
4113
6
5
4
3
2
1
0x7fffe697ceb0
The 4113 and address are provided by the compiler.
#include <iostream>
using namespace std;
int * readNumbers() {
int * a = new int[6];
for (int i = 0; i < 6; i++) {
int x;
cin >> x;
a[i] = x;
}
// a++;
return a;
delete[] a;
}
int *reverseArray(int *numbers1,int length) {
for (int i = length; i >=0; i--) {
cout << numbers1[i] << endl;
}
return numbers1;
delete [] numbers1;
}
int main() {
int *arr1 = readNumbers();
cout << reverseArray(arr1,6) << endl;
return 0;
}
I think there may have been an issue with your wording. Assuming you want your function just to print the reverse of a passed array, you're off to a good start.
One issue is what was said in the comments: your for loop is indexing past your array. When you type int * a = new int[6]; you are creating a pointer 'a' which points to a location in memory. Since you chose size 6, the appropriate amount of memory is allocated. If you happen to index outside of that range, you will end up pointing to a random spot in memory, not allocated for your array. Hence why you are getting a weird number '4113'.
A fix for this could be:
int i = length changed to int i = length-1
Another issue is that your function returns an integer pointer, and you are trying to cout this pointer. As another commenter said, you have to think about what this does. If you try this code:
#include <iostream>
using namespace std;
int main() {
int arr[] = {1, 2, 3};
cout << arr << endl;
return 0;
}
your output would be something like 0xff09ba. This represents the location of the start of the array in memory. If you change arr to (arr + 1) you will get the location of the second index of the array.
So when you type cout << reverseArray(arr1,6) << endl; you are really just printing out the location of numbers1 in memory. This is why you are getting '0x7fffe697ceb0' in your output. To fix this, simply make your function
void reverseArray(int *numbers1,int length) {
for (int i = length; i >=0; i--) {
cout << numbers1[i] << endl;
}
}
and change your main to:
int main() {
int *arr1 = readNumbers();
reverseArray(arr1,6);
return 0;
}
Now, if you actually want to return this array, you would need to create a new array which holds the reverse numbers and then return that. An example of a function that does that is:
int* reverseArray(int *numbers1,int length) {
int j = 0;
int *numbers2 = new int[length];
for (int i = length-1; i >=0; i--) {
numbers2[j] = numbers1[i];
j++;
}
return numbers2;
}
There are probably better ways to do this, but this is just one solution. Regardless, you should always be careful when allocating memory yourself.

Dynamically allocated array C++ reads a sentence and prints the words

On the input we get a sentence which we read until EOF. We need to add single words to dynamic array and then write them one on each line.
Input: Hello this, is an example.
Output:
Hello
this,
is
an
example
I have the following code and I can't figure out why it doesn't even add anything to the array.
#include <iostream>
#include <string>
using namespace std;
void addToArray(string newWord, string myArray[], int& arrayLength)
{
string * tempArray = new string[arrayLength + 1];
tempArray[arrayLength] = newWord;
for (int i = 0; i < arrayLength; ++i)
{
myArray[i] = tempArray[i];
}
arrayLength++;
myArray = tempArray;
delete [] tempArray;
}
int main()
{
string * arrayOfWOrds = new string[1000];
int arrayLength = 0;
string temp;
while (getline(cin, temp))
{
cout << temp << endl;
addToArray(temp, arrayOfWOrds, arrayLength);
}
cout << "Array" << endl;
for (int i = 0; i < arrayLength; ++i)
{
cout << arrayOfWOrds[i] << endl;
}
}
It's because you don't return the new array from the addToArray function. The change you make only happens in addToArray, it doesn't happen in main.
You also delete[] the wrong array, you delete the array you've just created.
You also copy the array elements in the wrong direction, i.e. from your new array to your old array.
Try this, I've renamed some of the variables for clarity. There is no temporary array in your function only a new array and an old array. Choosing good variable names is very important for writing working code. Bad variable names just confuse yourself.
string* addToArray(string newWord, string* oldArray, int& arrayLength)
{
string * newArray = new string[arrayLength + 1];
newArray[arrayLength] = newWord;
for (int i = 0; i < arrayLength; ++i)
{
newArray[i] = oldArray[i];
}
arrayLength++;
delete [] oldArray;
return newArray;
}
Then use it like this
arrayOfWOrds = addToArray(temp, arrayOfWOrds, arrayLength);
I see several issues here. To begin with, you set arrayLength = 0, so it's not going to iterate over the whole array if you have stuff already in it. If you don't have anything in it, there's no point in making it start off with 1000 items. Also, while (getline(cin,temp)) is an infinite loop, so it will never end and actually print the array. If you want to print the array after each addition, you need to move it into the while loop. There's no real reason to cout the number the user types either; they can already see the line they just typed.
More importantly, there are real issues with the dynamic allocation. You've created a static array (string * arrayOfWOrds = new string[1000];), then you're giving that to the function which makes a new array one item larger, sets the last item in that array to the new value, then iterates over the entire new array and duplicates the values to the old array. Basically, you're just inserting items into the static array at that point, and what you're inserting is a bunch of nothing (because the new array only has one item in it, and it's at arrayLength+1 which is outside the bounds of the original array).
You need to delete the old array, not the new array, which actually should be thrown on the heap and returned.
Basically, it should look more like this:
#include <iostream>
#include <string>
using namespace std;
string* addToArray(string newWord, string myArray[], int& arrayLength)
{
string * returnArray = new string[arrayLength + 1];
returnArray[arrayLength] = newWord;
for (int i = 0; i < arrayLength; ++i)
{
returnArray[i] = myArray[i];
}
arrayLength++;
delete [] myArray;
return returnArray;
}
int main()
{
const int startSize = 0;
string * arrayOfWords = new string[1];
int arrayLength = startSize;
string temp;
cout << "Input: ";
getline(cin, temp);
string word = "";
for (char c : temp){
if (c == ' '){
arrayOfWords = addToArray(word, arrayOfWords, arrayLength);
word = "";
} else word.push_back(c);
}
arrayOfWords = addToArray(word, arrayOfWords, arrayLength); // Don't forget the last word
for (int i = 0; i < arrayLength; ++i)
{
cout << arrayOfWords[i] << endl;
}
}
The array is unchanged, because you pass the pointer to the addToArray function, but it has no way to pass the new pointer back. You can fix this by changing the signature of the function to
void addToArray(string newWord, string *myArray[], int& arrayLength)
You also need to change the code accordingly, and fix problem with deallocation.
You can save yourself all the trouble and use std::vector in place of manually allocated dynamic array:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<string> arrayOfWOrds;
string temp;
while (getline(cin, temp))
{
cout << temp << endl;
arrayOfWOrds.push_back(temp);
}
cout << "Array" << endl;
for (size_t i = 0; i < arrayOfWOrds.size(); ++i)
{
cout << arrayOfWOrds[i] << endl;
}
}
string in="dasd adas ads adsada adsa asd ads",out;
stringstream ss(in);
vector<string> vr;
while(ss>>out)
{
vr.push_back(out);
//cout<<out<<endl;
}
for(int i=0;i<vr.length();i++)
{
cout<<vr[i]<<endl;
}
try doing this

C++ Dynamic data – how to obtain it and how to get rid of it

The code below – it's a skeleton of a program operating on the dynamic collection of data. The idea is to use a structure containing two fields: the first stores the number of elements in collections, and the second is the actual collection (a dynamically allocated vector of ints). As you can see, the collection is filled with the required amount of pseudo-random data.
Unfortunately, the program requires completion, as the most important function.
Here's what i expect from the function:
if the collection is empty, it should allocate a one-element vector and store a new value in it.
if the collection is not empty, it should allocate a new vector with a length greater by one than the current vector, then copy all elements from the old vector to the new one, append a new value to the new vector and finally free up the old vector.
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
struct Collection {
int elno;
int *elements;
};
void AddToCollection(Collection &col, int element) {
//the first part of the funtion
if (col.elno==0){
col.elements= new int[1];
col.elements[0]= element;
}
//this is the second part but i do not know how to do it.
//Please help me to complete***************
else {
int *temp;
temp = new[];
}
}
void PrintCollection(Collection col) {
cout << "[ ";
for(int i = 0; i < col.elno; i++)
cout << col.elements[i] << " ";
cout << "]" << endl;
}
int main(void) {
Collection collection = { 0, NULL };
int elems;
cout << "How many elements? ";
cin >> elems;
srand(time(NULL));
for(int i = 0; i < elems; i++)
AddToCollection(collection, rand() % 100 + 1);
PrintCollection(collection);
delete[] collection.elements;
return 0;
}
vector container is originally dynamic container. so u can use vector.
Just declare vector variable in structure and use it in AddToCollection function.
struct Collection {
int elno;
std::vector<int> elements;
};
void AddToCollection(Collection &col, int element) {
col.elements.push_back(element);
col.elno++;
}
like this.
Here is what you are looking for:
void AddToCollection(Collection &col, int element)
{
if(col.elements == NULL)
{
col.elements = new int[1];
col.elements[0] = element;
col.elno = 1;
}
else
{
int *newArr = new int[col.elno+1];
for(int i = 0; i < col.elno; i++)
{
newArr[i] = col.elements[i];
}
newArr[col.elno] = element;
delete[] col.elements;
col.elements = new int[col.elno+1];
for(int i = 0; i < col.elno+1; i++)
{
col.elements[i] = newArr[i];
}
delete[] newArr;
newArr = NULL; // avoid dangling pointer
col.elno++;
}
}
For sure using vector container is a great ideea but the exercise require no modification to the main function. The objective of this exercise is to help the student to understand dynamically allocated memory.

Creation of Dynamic Array of Dynamic Objects in C++

I know how to create a array of dynamic objects.
For example, the class name is Stock.
Stock *stockArray[4];
for(int i = 0 ; i < 4;i++)
{
stockArray[i] = new Stock();
}
How do you change this to dynamic array of dynamic objects?
What I tried:
Stock stockArrayPointer = new Stock stock[4];
It doesn't work and the error is "The value of Stock** cannot be used to initalize an entity of type Stock.
Second question is after the creation of dynamic array of dynamic objects, what is the syntax to access the pointers in the array.
Now, I use stockArray[i] = new Stock(); How will this change?
Need some guidance on this...
If you are using c++ then you shouldn't reinvent the wheel, just use vectors:
#include <vector>
std::vector< std::vector< Stock > > StockVector;
// do this as many times as you wish
StockVector.push_back( std::vector< Stock >() );
// Now you are adding a stock to the i-th stockarray
StockVector[i].push_back( Stock() );
Edit:
I didn't understand your question, if you just want to have and array of arrays allocated on the heap just use:
Stock** StockArrayArray = new Stock*[n]; // where n is number of arrays to create
for( int i = 0; i < n; ++i )
{
StockArrayArray[i] = new Stock[25];
}
// for freeing
for( int i = 0; i < n; ++i )
{
delete[] StockArrayArray[i];
}
delete[] StockArrayArray;
The type of a variable to a dynamic array is a pointer to the first object of the array. You want an array of dynamically allocated Stock objects, so an array of pointers to Stock, so your variable is a pointer to a pointer to Stock:
int n = 4; // dynamic size of the array;
Stock** stockArray = new Stock*[n];
for (int i = 0; i != n; ++i)
{
stockArray[i] = new Stock();
}
and freeing it:
for (int i = 0; i != n; ++i)
{
delete stockArray[i];
}
delete[] stockArray;
Stock* stockArrayPointer = new Stock [4];
works only if the Stock class has a zero argument constructor
if it does not have any zero argument constructor you cannot create an array of dynamic objects dynamically
you can as said create a array of dynamic object with a static array like
Stock stockArrayPointer[4]={Stock(args),Stock (args)};
but the syntax
Stock* stockArrayPointer=new Stock[4]{Stock(args),Stock (args)}; does not hold
or as said
use vectors...
vectors are memory allocated on heap
so the vector is a dynamic allocation
vector<Stock> V;
V.push_back(Stock(args));
or
V.push_back(new Stock(args));
The reason why
Stock* stockArrayPointer=new Stock[4]{Stock(args),Stock (args)};
does not hold
is because
this means
you are using the new operator incorrectly
I did something which worked perfectly:
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class student {
string name;
int age;
int roll;
public:
student() {
name="";
age=0;
roll=0;
}
student (string n, int a, int r) {
name=n;
age=a;
roll=r;
}
void show_details ();
};
void student::show_details() {
cout << "Name: " << name << "\n";
cout << "Age: " << age << "\n";
cout << "Roll No: " << roll << "\n";
}
int main() {
string a; int b, c, n;
cin >> n;
student **obj;
obj=(student**)malloc(n*sizeof(student*));
for (int i=0; i<n; i++) {
cin >> a;
cin >> b;
cin >> c;
obj[i]=new student(a,b,c);
}
for (int i=0; i<n; i++) {
obj[i]->show_details();
}
for (int i=0; i<n; i++) free (obj[i]);
free (obj);
}
Yes... I used pointer to pointer for the array part, and it worked perfectly for variable sized arrays.

Having trouble with arrays and pointers

I currently reading a book to refreshing my memory on c++. The chapter I'm on has to do with dynamic memory allocation. I doing a practice problem and I'm having some trouble figuring out what is wrong with my program. The question is
"Write a program that lets users keep track of the last time they talked to each of their friends. Users should be able to add new friends (as many as they want!) and store the number of days ago that they last talked to each friend. Let users update this value (but don't let them put in bogus numbers like negative values). Make it possible to display the list sorted by the names of the friends of by how recently it was since they talked to each friend."
For now I'm just trying to get the program to store the user's input correctly.
It crashes after I enter 5 friends so I'm guessing its writing over the array but the Resize function should take care of that.
He is my code
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
struct Friend
{
string friends;
int days;
};
Friend Resize(Friend* p_array, int* size_of_array);
int main()
{
struct Friend f;
int quit = 1;
int array_size = 5;
int number_of_friends = 0;
Friend *p_array = new Friend [array_size];
while(quit != 0)
{
cout << "Enter a friends name.\n";
cin >> f.friends;
cout << "Enter the number of days sence you last saw them.\n";
cin >> f.days;
cout << "Enter '0' to quit the program.\n";
cin >> quit;
if(array_size == number_of_friends)
{
Resize(p_array, &array_size);
}
p_array[number_of_friends] = f;
number_of_friends++;
}
//print the array
cout << endl;
for(int i = 0; i < sizeof(p_array); i++)
{
cout << p_array[i].friends << " " << p_array[i].days << endl;
}
//delete the array
delete [] p_array;
return 0;
}
Friend Resize(Friend* p_array, int* size_of_array)
{
*size_of_array *= 2;
Friend *p_new_array = new Friend [*size_of_array];
for(int i = 0; i < *size_of_array; i++)
{
p_new_array[i] = p_array[i];
}
delete [] p_array;
p_array = p_new_array;
}
p_array = p_new_array;
This will assign the local Friend* parameter to p_new_array.
Therefor
p_array[number_of_friends] = f;
is an access to an invalid object.
Declare Resize as
Friend Resize(Friend** p_array, int* size_of_array)
or
Friend Resize(Friend*& p_array, int* size_of_array)
to solve this issue.
The crash is due to the resize function.
The following line causes the crash:
for(int i = 0; i < *size_of_array; i++)
{
p_new_array[i] = p_array[i];
}
You have doubled the size of size_of_array, but p_array has only 5 elements. So this means that you step out of bounds here.
The problem is that although your resize code is kind of OK, it only changes the pointer inside the Resize function. The pointer in main never gets changed at all. The other error is that you double the size_of_array variable before you copy the array, so you end up copying elements from the old array that don't exist.
Change your function like this
Friend* Resize(Friend* p_array, int* size_of_array)
{
Friend *p_new_array = new Friend [*size_of_array * 2];
for(int i = 0; i < *size_of_array; i++)
{
p_new_array[i] = p_array[i];
}
delete [] p_array;
*size_of_array *= 2;
return p_new_array;
}
And then in main use it like this
if(array_size == number_of_friends)
{
p_array = Resize(p_array, &array_size);
}
This way the Resize function returns the new array, and you assign it to the p_array variable in main.,