Problem with dynamic array of structs using pointers

Hello, I am in a class where I have to receive values from a file (a string, an int, a dynamic array of floats, and a dynamic array of strings). I have to setup a dynamic array of structs in which I traverse them and add the elements stated above. For each section of the struct array there are several smaller sections which also get placed into arrays within the struct. My code is below. However, it doesn't output anything and don't even know if it is capturing anything. I know that I need to declare new dynamic arrays for the arrays within the structs before I can place values into them. Not sure if I am doing that wrong, that could be the case. Any help would be great. Also, please note, I am not asking to have someone write my code for me just some advice, guidance etc on where I am going wrong and how I could correct it.

Thank you all so much!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <fstream>
using namespace std;

const int TOURS = 3;
const int DETAILS = 3; //this will be used for the two dynamic arrays within the struct

struct Tours{
	string name;
	int number;
	float *tourLength; //dynamic array
	string *remarks; //dynamic array
	~Tours(){
		if(tourLength) delete [] tourLength;
		tourLength = nullptr;
		if(remarks) delete [] remarks;
		remarks = nullptr;
	}//destructor
};//tours

int main() {

	Tours *toursPtr = new Tours[TOURS]; //create dynamic array
	toursPtr->tourLength = new float[DETAILS];
	toursPtr->remarks = new string[DETAILS];

	ifstream fin("tours.txt");

	for(int i = 0; i < TOURS; i++){
		getline(fin, (toursPtr+i)->name);
		fin.ignore();
		fin >> (toursPtr+i)->number;
		fin.ignore();
		for(int g = 0; g < DETAILS; g++){
				//below will store the tour lengths for each 
				//sub-tour under the parent tour struct array
			fin >> (toursPtr+i)->tourLength[g];
			fin.ignore();
				//below will store the customer remarks for each 
				//sub-tour under the parent tour struct array
			getline(fin, (toursPtr+i)->remarks[g]);
		}
	}//tours input

	for(int i = 0; i < TOURS; i++){
		cout << "Tour: " << (toursPtr+i)->name << endl;
		cout << "Tour Number: " << (toursPtr+i)->number << endl;
		for(int g = 0; g < DETAILS; g++){
				//below will output the tour lengths for each 
				//sub-tour under the parent tour struct array
			cout << "Tour Length: " << g+1 << ": " << (toursPtr+i)->tourLength[g] << endl;
				//below will output the customer remarks for each 
				//sub-tour under the parent tour struct array
			cout << "Remarks: " << (toursPtr+i)->remarks[g] << endl;
		}
	}//tours output
	return 0;
}
Last edited on
1
2
	Tours *toursPtr = new Tours[TOURS];
	toursPtr->tourLength = new float[DETAILS];

The -> operator allows access to member via a pointer. That is not the only syntax to do so.
All these achieve the same:
1
2
3
4
toursPtr->tourLength
(*toursPtr).tourLength
(*(toursPtr+0)).tourLength
toursPtr[0].tourLength

You create TOURS Tours, but make only the first Tours' members to point to arrays.
Then you try to access arrays of every Tours that you have.

Why doesn't the constructor of a Tours allocate the memory? Its destructor does deallocate.

Think at what happens with:
1
2
3
{
  Tours doomed; // member pointers are uninitialized
} // destructor of doomed calls delete on unknown address 
- Tours should have a default constructor to initialise number, tourLength and remarks to nullptr. or this can be done by direct initialisation of the member variables such as

1
2
3
int number = 0;
float *tourLength = nullptr; //dynamic array
string *remarks = nullptr; //dynamic array 


- you don't need to check for nullptr before delete []. delete [] is OK if you pass a nullptr. Also you don't need to set the pointer to nullptr afterwards as the instantiation of the class ceases after the destructor ends

- what is the layout of the file? Having .ignore() (which removes and ignores 1 char) after a getline looks wrong as getline() removes the found terminator. There are issues with mixing getline() and >>, but usually you would use ignore after >> before a getline(). The problem is that getline() obtains the data from the current position until the specified delimiter is found and removes the delimiter. >> first ignores any white space (such as a new line) and obtains the required data until a white space is found but leaves the white space for the next extraction. If >> is then followed by a getline(), then the >> terminating white space char (new line) is read as the first input to getline() which removes the new line and returns nothing! Note that you cannot read a string from the stream if it contains a space using >>. You need to use getline() as >> will stop reading when it finds the space.

- if there is a problem reading the data - such as a number when the data isn't a number - then the stream enters 'fail state' and no further data can be read until the stream state is set to good again (use .clear()). Note that the bad data hasn't been removed/read.

> float *tourLength; //dynamic array
¿is there a good reason for that? you know that the size will be DETAILS, ¿why don't simply use an array?
1
2
3
4
5
6
7
struct Tours{
	string name;
	int number;
	float tourLength[DETAILS];
	string remarks[DETAILS];
	//no need for a custom destructor
};


if you insist on using dynamic allocation, you'll need a proper destructor, copy constructor, and assignment operator


> it doesn't output anything and don't even know if it is capturing anything.
run your code step-by-step through a debugger and watch your variables
also, valgrind is a good tool to detect invalid access.
Thank you all for the reply. So some of you asked what the input code looks like. Here it is:
1
2
3
4
5
6
7
8
Kauai
310
5
Gorgeous views.
3
Long lines for the bathrooms on this one.
4.5
The gnats are annoying on this tour.


Where 5 gets input into *tourLength[] and "Gorgeous views" gets input into *remarks[] but all are within the array of structs *tours[i].

So there are three different tour lengths and 3 remarks about each tour length. The output should look something like this:

Tour: Kauai
Tour Code#: 310
Tour #1 Length (hrs): 5
Remarks about this tour: Gorgeous views.
Tour #2 Length (hrs): 3
Remarks about this tour: Long lines for the bathrooms on this one.
Tour #3 Length (hrs): 4.5
Remarks about this tour: The gnats are annoying on this tour.

In reply to: keskiverto,.
Thank you for showing me the different ways to achieve that. In this certain assignment he wants us using -> instead of the . operator. Why I didn't allocate memory within the scruct itself is that the assignment specifically states to define a dynamic array within the program and then fill those with the data from the file. So to define a new dynamic array within the file I assigned the *tourPtr->tourLength = new float[DETAILS];.

When doing the below, as suggested by many of you, the program works flawlessly.

1
2
3
4
5
6
7
8
9
10
11
12
	struct Tours{
	string name;
	int number;
	float *tourLength = new float[DETAILS]; //dynamic array
	string *remarks = new string[DETAILS]; //dynamic array
	~Tours(){
		if(tourLength) delete [] tourLength;
		tourLength = nullptr;
		if(remarks) delete [] remarks;
		remarks = nullptr;
	}//destructor
};//tours 


However, the problem was that the instructor specifically requires us to define two new dynamic arrays for the float and string values and then input the file data into those two new dynamic arrays which fill the struct dynamic arrays.

That is where the problem was occurring I believe... the defining two new arrays and assigning the values to them and having them assign to the struct arrays.

ne555 and seeplus, Thank you both very much. With your feedback I was able to fix a few things and removed the fin.ignore() from after the getline. That was my mistake I did not intend to have it after the getline.

I was able to get the program running perfectly by following suggestions from everyone and tweaking my code around. Thank you all so much for the assistance, guidance and suggestions. I appreciate you all.
Last edited on
Topic archived. No new replies allowed.