Unexpected std::string behavior and pointers

The code below is a little long but I'm not sure I can explain the problem accurately enough to not include it. Basically my issue is that my struct string members seem to be getting destroyed after an inner loop exit though all other struct members remain. I don't really understand why and I'd appreciate any information you can provide.

If you have any other feedback I'll take that as well but my main problem is the disappearing strings. This started originally as a homework assignment (the assignment was very basic) but has turned into something much more as I try to really understand pointer manipulation concepts.

Thank you!

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// IA4SullivanD.cpp : Defines the entry point for the console application.

//Includes
#include "stdafx.h"  
#include <iostream>  
#include <math.h>    
#include <string>
#include <time.h>
#include <iomanip>

//Standard namespace std
using namespace std;

class MortgageInfo
{
	public:

		//Struct within class
		struct userInfo
		{
			int RecordIdentifier;
			string LastName;
			string FirstName;
			double InterestRate;
			int LoanPeriod;
			double Principal;
			double MonthlyPayment;
			char* QuoteDate; //Pointers to
			char* QuoteTime; //Date and time
		};
		
		double Pay(); //prototype member function
		void set_UserInfo(int i, string f, string l, float rate, int y, float m, double p, char* d, char* t);
		void get_UserInfo(int i);


		MortgageInfo() //Constructor
		{}

		MortgageInfo(float i, float m, int y):Interest(i),Mortgage(m),Years(y) //Constructor
		{
			MonthlyInterest = (Interest/100)/MonthsPerYear;  //Takes interest rate from percentage to decimal and then divides by months in year to determine monthly interest
			TotalMonths = MonthsPerYear*Years;               //Total loan term mortgage multiplied by the months in a year to acquire total months
		}

		~MortgageInfo() //Deconstructor
		{
		
		}

	protected:
		double Payment;
		float Interest;
		float Mortgage;
		float MonthlyInterest;
		int Years;
		int TotalMonths;
		static const int MonthsPerYear = 12; //Variable to hold months per year for mortgage formula.
		static const int ArraySize = 10;
		userInfo loan[ArraySize];
		userInfo *ptrloan;

};

double MortgageInfo::Pay()
{
	return Payment = (Mortgage * MonthlyInterest) / (1 - pow((1 + MonthlyInterest), - TotalMonths)); //Actual mortgage formula stored in double payment;
}
void MortgageInfo::set_UserInfo(int i, string f, string l, float rate, int y, float m, double p, char* d, char* t)
{
	ptrloan = &loan[i];

	ptrloan->RecordIdentifier = i;
	ptrloan->FirstName = f;
	ptrloan->LastName = l;
	ptrloan->InterestRate = rate;
	ptrloan->LoanPeriod = y;
	ptrloan->Principal = m;
	ptrloan->MonthlyPayment = p;
	ptrloan->QuoteDate = d;
	ptrloan->QuoteTime = t;
}

void MortgageInfo::get_UserInfo(int index)
{
	ptrloan = &loan[index];

	cout << ptrloan->RecordIdentifier << setw(11) << ptrloan->LastName << " " << ptrloan->FirstName << setw(6) 
		 << ptrloan->InterestRate << setw(6) << ptrloan->LoanPeriod << setw(12) 
		 << ptrloan->Principal << setw(11) << ptrloan->MonthlyPayment << setiosflags(ios::fixed) << setprecision(2) << setw(12) 
		 << ptrloan->QuoteDate << " " << ptrloan->QuoteTime << endl;

	cout << "LastName: " << loan[index].LastName << " " << "FirstName: " << loan[index].FirstName
		 << "Principal: " << loan[index].Principal << endl;
}



int _tmain(int argc, _TCHAR* argv[])
{
    //Variables for mortgage loop.
	const int ArraySize = 10;
	double Payment;
	float Interest;
	float Mortgage;
	int Years;
	int Identifier = 0;			//Unique record identifier
	char* QDate;
	char* QTime;
	string FName; 
	string LName;
	char inControl = 'N';      //Control variable for do-while loop defaulted to 'N' (No)
	char outControl = 'N';
	
	MortgageInfo *ptrUserInput;

	
	do
	{
		cout << "Please enter your first name: ";
		cin  >> FName;
		cout << "Please enter your last name: ";
		cin  >> LName;


		do
		{
			Identifier++; //increment unique identifier

			//Get time code
			QDate = new char[80];
			QTime = new char[80];

			struct tm * timeinfo;
			time_t rawtime;

			time(&rawtime);
			timeinfo = localtime(&rawtime);

			strftime(QDate,80,"%x",timeinfo); //Format for date saved in QDate
			strftime(QTime,80,"%X",timeinfo); //Format for time saved in QTime
			//End get time code

			cout << "What is the interest rate? ";
			cin	 >> Interest;                     //Prompt user for interest rate
			cout << "How many years is this mortgage? ";
			cin  >> Years;                        //Prompt user for mortgage term in years
			cout << "What is the amount you are borrowing(number without commas)? ";
			cin  >> Mortgage;                     //Prompt user for mortgage amount

			//Creates object userInput then obtains payment amount into variable Payment
			MortgageInfo userInput(Interest,Mortgage,Years);
			Payment = userInput.Pay();
		
			cout << "Your monthly payment is $" << Payment << endl << endl;  //Display user monthly payment

			userInput.set_UserInfo(Identifier, FName, LName, Interest, Years, Mortgage, Payment, QDate, QTime);
			ptrUserInput = &userInput;

			ptrUserInput->get_UserInfo(Identifier);

			cout << "Would you like to enter another quote(Y/N)? ";
			cin  >> inControl; 


		}while(inControl == 'Y' || inControl == 'y' && Identifier < ArraySize);  //While the control variable equals Y or y (yes) continue the inner loop.

		ptrUserInput->get_UserInfo(Identifier);

		cout << "Would you like to enter a different user(Y/N)? ";
		cin  >> outControl;

		system("cls");

	}while(outControl == 'Y' || outControl == 'y' && Identifier < ArraySize); //Outer loop

	//Header for loop
	cout << "RecNo" << setw(6) << "Name" << setw(15) << "Rate" << setw(10) << "Period" << setw(12) << "Principal" << setw(8) << "Pay" << setw(20) << "Time Stamp" << endl;

	//Dump array data
	for(int index = 1; index <= Identifier; index++)
	{
		//userInput.get_UserInfo(index);
		ptrUserInput->get_UserInfo(index);
	};

	//delete memory
	delete[] QDate;
	delete[] QTime;


	system("pause");
	return 0; //Clean exit
}

userInput is an object local to the inner do, which means it gets destructed after each cycle. Assigning a pointer to it will just get you segmentation faults. You should use new to prevent this.

also note that the char arrays are allocated several times, but deallocated just once.
Last edited on
Thank you, may I ask why the other struct members don't seem to be experiencing the behavior when userInput is local to the inner do?
You're accessing data that is no longer there, so the exact behavior is unpredictable. It's not uncommon for variables to be leftover even after the stack has been popped.
Thanks again, I appreciate the help. I'm a little confused though if I were using new like:

 
MortgageInfo *ptrUserInput = new MortgageInfo;


I'm not calling the constructor I'd like but I don't *think* that I can include the arguments in that statement either. I've done some googling and forum searching and can't really find too much information on it. That leads me to believe that a) it's not a smart idea or b)it's not that easy.

Do you have a link perhaps? most of what I pull up relates to function pointing which I can do.

Again, I appreciate your assistance in this learning experience for me.
MortgageInfo *ptrUserInput = new MortgageInfo(/*put your arguments here*/);
I ended up going with a pointer to an array of pointers to suite my needs as I felt that gave me the best flexibility that i currently know of (code changed quite a bit). If you have the time for one last question I knew that I called new char multiple times but only deleted once. However, since the struct is using a pointer to its address how can I cleanup the memory mess I make after the fact?

Thanks again, you gave me some good key words to search the material cpp offers that I simply could not think of either.
Topic archived. No new replies allowed.