c++ Dynamic array using strings won't accept strings - c++

I am trying to put the strings in a temporary array into a dynamic array. But the compiler just breaks when it hits that.
where dynaicArray is called:
string* dynamicArray = NULL;
Here is where it is breaking:
for (int i = 1; i <= (size); i++)
{
dynamicArray[i] = tempArray[i];
}
Where tempArray is filled:
void populateArray(int& size, string*& dynamicArray)
{
char decide;
string tempArray[100]; //Holds the strings until the size is known
bool moreStrings = true;
while (moreStrings == true)
{
cout << "\nEnter your string here:";
cin >> tempArray[size];
cout << "\nDo you want to enter another string? Y/N:";
cin >> decide;
decide = toupper(decide);
size ++;
dynamicArray = new string[size];
if (decide == 'N')
{
for (int i = 1; i <= (size); i++) //moves all of the strings from tempArray to dynamicArray
{
string temp;
temp = tempArray[i];
dynamicArray[i] = temp;
}
moreStrings = false;
}
}
}
PS: I know vectors are better. Unfortunately they're not an option.

Some design ideas:
the code in the if (decide == 'N') block is better placed after the while, to make the while smaller == more readable
once the above is implemented, you can set the moreStrings var directly with the result of your decide == 'N'; no need for an explicit if there anymore
you now do a dynamicArray = new string[size]; in each pass through the while, which is an enormous memory leak (you'r overwriting the newly created dynamic array with a new copy without reclaiming the old one out first - see dalete[])
as already mentioned: don't assume 100 will be enough - read "Buffer overflow" (only viable solution: make it a dynamic array as well and re-allocate it to a bigger one if it gets full)
better initialize size in the function before you use it - much safer; callers don't need to remember to do it themselves
C++ arrays are 0-based, so when you start copying them you'd also better start at 0 and not at 1
nitpick: for (int i = 1; i <= (size); i++): the () around size are superfluous
bonus advanced nitpick: use ++size and ++i in these contexts; it's a bit more efficient
you now use the var tmp to copy from the temp array to the dynamic one and the code is also somewhat structured to suggest you're using it to swap the strings between the two arrays (you're not) - rename the tmp variable or get rid of it altogether

Related

Dynamic resizing array code not working in 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.

C++ Dynamic Ragged Array

I have been trying to figure out this assignment for hours and can't grasp it yet. I'm trying to read in names from a txt document, which is working, and I need to store them in an char pointer array. Once the number of names is as big as the array size, I need to use REALLOCATION to make the array bigger (I can't use vector library).
I'm struggling with changing the name array size to make it bigger and deleting the old array from memory (it just crashes when I write delete [] names;).
Here is my currently broken code:
int numNames = 2;
char * names[numNames] = {};
ifstream namesFile("names.txt");
//get names from user, put names in ragged array
int i = 0;
while (i < numNames) {
if (namesFile.good() && !namesFile.eof()) {
//add name to ragged array
names[i] = new char[257];
namesFile >> setw(256) >> names[i];
i++;
if (i == numNames) {
//need a bigger array
numNames *= 2;
char * temp[20] = {};
for (int j = 0; j < numNames / 2; j++) {
temp[j] = names[j];
}
delete [] names;
names = temp;
}
}
else {
//end of file or corrupt file
break;
}
}
namesFile.close();
Any help is appreciated!
The following statement does not do any dynamic allocation. It just declares an array of pointers to char (char*) on a stack of size numNames. So, it is not dynamic by any means:
char * names[numNames] = {};
As such, you cannot change its size.
Instead you need to create a pointer to the array like the following:
char **names = new (char*)[numNames];
Same story for your temp down the road. Now you are free to delete/new and to assign pointers as well: names = temp.
Now, you need to read your char data from a file line by line and put it in the 'names' array. When you read a string, you can allocate space for it in the array member, i.e.
names[i] = new char [strlen(inputString) + 1]; // you need '+1' for termination char
and you can copy data from your string after allocation, i.e.
strcpy(name[i], inputString); // this is a standard 'c' string copy
you can also use std::copy or a for loop do do a copy or whatever. Another method is to use a standard 'c' malloc function to do allocation:
name[i] = (char *)malloc(strlen(inputString) + 1);
The difference is that when you would need to free memory, you would use delete[] name[i] in the first case and free(name[i]) in the second. Though it looks like you do not need to free the memory in your task.
Now you just have to figure out how to read from the file.

Memory Location as last value in enlarged dynamic array [duplicate]

This question already has answers here:
Function does not change passed pointer C++
(4 answers)
Closed 5 years ago.
I am passing a dynamic array to a function with a value that is meant to be added to the array and when I enlarge and reset the array dynamically and iterate over the array I find the last value of the array is a garbage value rather than what is expected. I've looked at a few other posts on SO as well as some documentation and i'm stumped on what i'm doing wrong. I would prefer to use a vector, but my assignment requires a dynamic array unfortunately. Any thoughts? Thanks.
Post above is passing pointers to vectors by reference and has nothing to do with enlarging dynamic arrays
Main
cout << "Please enter the size of the array of integers you would like to create: ";
cin >> size;
cout << "\nPlease enter your integers:\n";
int *integerArray = new int[size];
//store values in array
for (int dynamicArrayDataCounter = 0; dynamicArrayDataCounter < size; dynamicArrayDataCounter++)
cin >> integerArray[dynamicArrayDataCounter];
cout << "\n Please enter the integer you would like to insert into this array: ";
cin >> userInt;
InsertIntegerToSortedList(integerArray, userInt, size);
//Print array for proof
for (int counterPrinter = 0; counterPrinter < size + 1; counterPrinter++)
cout << endl << integerArray[counterPrinter];
//Remove memory and repoint dangling pointer
delete [] integerArray;
integerArray = NULL;
return 0;
}
Function
void InsertIntegerToSortedList(int *integerArray, int userInteger, int size)
{
//Declare new array to add index position for integerArray
int *resizedArray = new int[size + 1];
bool numInserted = false;
for (int counter = 0; counter < size + 1; counter++)
{
if (integerArray[counter] < userInteger)
{
resizedArray[counter] = integerArray[counter];
}
else if ((integerArray[counter] > userInteger && integerArray[counter - 1] < userInteger) || integerArray[counter] == userInteger || (integerArray[counter] <= userInteger && size - counter == 1))
{
resizedArray[counter] = userInteger;
numInserted = true;
}
else if (numInserted)
resizedArray[counter] = integerArray[counter - 1];
}
//Store resizedArray values in integerArray
integerArray = resizedArray;
//Remove dynamic array on heap and repoint dangling pointer
delete[] resizedArray;
resizedArray = NULL;
}
In
void InsertIntegerToSortedList(int *integerArray, int userInteger, int size)
you are passing the pointer integerArray by value, hence at the exit of the function you end up not modifying it. Pass it by reference, like
void InsertIntegerToSortedList(int* & integerArray, int userInteger, int size)
Furthermore, as mentioned in the comments, you're doing it slightly wrong. First, copy the array elements into resizedArray. Next, you need to delete the old array,
delete[] integerArray;
and finally assign to the newly allocate array to integerArray
integerArray = resizedArray;
That's all is needed, now integerArray will point to the memory that was allocated via resizedArray. No need to set resizedArray to NULL, it is just a local variable that will cease to exist at the exit of the function. What you care about is just the address of the memory you allocated, and you already have that stored into integerArray pointer.

How to insert an object in the array of pointers

I have an array of pointers:
Hotel *hotels[size];
for (int i = 0; i < size; ++i)
hotels[i] = new Hotel();
And I want to insert an object in this array after some object with name I know:
cin >> tmp_name;
for (int i = 0; i < size; i++) {
if (hotels[i]->get_name() == tmp_name) {
hotels[size] = new Hotel();
size += 1;
Hotel *tmp_hotel;
tmp_hotel = hotels[i+1];
hotels[i+1]->fillHotel();
for (i = i + 2; i < size; i++) {
hotels[i] = tmp_hotel;
tmp_hotel = hotels[i+1];
}
break;
}
}
What I do wrong?
UPD:
My solution:
cin >> tmp_name;
for (int i = 0, j = 0; i < size; i++, j++) {
new_hotels[j] = hotels[i];
if (hotels[i]->get_name() == tmp_name) {
new_hotels[j+1]->fillHotel();
++j;
system("clear");
}
}
hotels[size] = new Hotel();
++size;
for (int i = 0; i < size; i++) {
hotels[i] = new_hotels[i];
}
I can see different errors in your code.
For example:
Hotel *hotels[size];
size should be a constant expression and something let me think this is not the case. VLA are not part of the C++ standard. In short you cannot allocate dynamic memory on the stack. The proper initialization should be:
Hotel* hotels = new Hotel*[size];
The line in the loop:
hotels[size] = new Hotel();
you're actually accessing out of bounds of your array: size index is some memory is not included in your array and this will produce an undefined behaviour.
Another strange line is the following:
size += 1;
Despite the fact that confirms size is not a constant, you cannot increase your size of vector simply changing that variable. You're actually just changing a variable size, but the allocated memory for your array will be the same.
How resolve?
In order in increase (or change) the size of an array, the solution is almost always to create a new array, copy the old one. In your case that solution is pretty reasonable because you should copy just pointers and not entire objects.
There are a lots of question on S.O. where this topic is, for example here.
Despite of that, I strongly suggest you to use the most practical alternative, that is to use a real C++ code.
The most efficient class is std::vector which is a C++ way to handle dynamic array.
Finally, you should also consider the std::unique_ptr<T> class to handle dynamic memory and pointers.
The final solution will be a class:
std::vector<std::unique_ptr<Hotel>> hotels;

Issue with swapping addresses

I am doing an assignment in which i must write a function that does the following - "You will allocate an array the size of the number of vacancies and load the dynamic array with the pointers to all of the current vacancies. Build the array using the last vacancy first. in this same function, you will move all of the transfers to the available rooms (and mark them as OCCUPIED) using the dynamic array of pointers. You must do this by performing a swap of the transfer addresses with the vacant ones. Start from the back of the array of pointers and continue to the front for these operations until all transfers are done. DO NOT REPROCESS the array of pointers." This is what i wrote in an attempt to do this -
char** tranfers(char hospitalFloors[FLOOR_ARRAY_SIZE][ROOM_ARRAY_SIZE], int &num)
{
int x = 0;
char *temp;
for (int i = 0; i < FLOOR_ARRAY_SIZE; i++)
{
for (int k = 0; k < ROOM_ARRAY_SIZE; k++)
{
if(hospitalFloors[i][k] == 'V')
{
num++;
}
}
}
char **arr = new char*[num];
for (int i = (FLOOR_ARRAY_SIZE - 1); i >= 0; i--)
{
for (int k = (ROOM_ARRAY_SIZE - 1); k >= 0; k--)
{
if (hospitalFloors[i][k] == 'V')
{
arr[x] = &hospitalFloors[i][k];
x++;
}
}
}
for (int i = 0; i < FLOOR_ARRAY_SIZE; i++)
{
for (int k = 0; k < ROOM_ARRAY_SIZE; k++)
{
if (hospitalFloors[i][k] == 'T')
{
x--;
temp = arr[x];
arr[x] = &hospitalFloors[i][k]
&hospitalFloors[i][k] = temp;
}
}
}
return arr;
}
i have no doubt in my mind that there is a problem with trying to set &hospitalFloors[i][k] to a pointer, but no matter what i try differently i cant seem to come up with a solution.
my question is, given what the assignment is asking, how would i swap the address of the room with a transfer to a room with a patient, making sure that the array of pointers keeps its order, but without reprocessing it?
Any help is greatly appreciated.
The wording of the question is quite a bit vague. It looks like what you need to do is move any room marked as a transfer ('T') to a vacant room ('V') and mark it as occupied (assuming 'O') and mark the room transferred from as vacant.
So all you need to do is take the appropriate steps in your last if block.
*arr[x] = 'O'; // set vacant room as occupied.
hospitalFloors[i][j] = 'V'; // set transfer room as vacant
arr[x] = &hospitalFloors[i][j]; // make the vacancy element point at the now vacant room
Of course keeping x--
You do need to work on the pointed-to data, of type char. While the assignment says "swap", it also says to mark the moved transferee rooms occupied, which you could do directly:
*arr[x] = 'O';
hospitalFloors[i][k] = 'V';
To do it literally using a "swap" first:
char temp = *arr[x]; // was vacant
*arr[x] = hospitalFloors[i][k]; // assign transfer
hostpitalFloors[i][k] = temp; // make vacant
*arr[x] = 'O'; // make occupied
The array does say...
You must do this by performing a swap of the transfer addresses with the vacant ones.
It's unclear if addresses above alludes to the [floor][room] aspect, or the char* aspect. There's ostensibly no point in modifying the pointer addresses in arr though, so I'm assuming the former.
You are asked to do this in reverse order of the array though, but you're currently looping over the floors and rooms again. I'm sure you can fix that yourself.