terminate called after instance of std::out of range what() substr?

Can anyone tell me why this code throws the error:
Enter a fraction expression: terminate called after throwing an instance of 'std
::out_of_range'
what(): basic_string::substr
But it only throws the error once I have finished with the do{} part of my code, and choose to continue by pressing 'y' or 'Y'.

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
  #include <iostream>
#include <sstream>
#include <string>
void calcOperator(int,int,int,int,std::string);
void calcReduction(int, int);
void calc();
int main()
{
	char answer;
	do
	{
		calc();
		std::cout << "\nDo you wish to continue? (y/n): ";
		std::cin >> answer;
	}while(answer == 'y' || answer == 'Y');

	

	


	/*** Saving for later
	if(s.find("*") != std::string::npos){std::cout << "\nMultiply";}
	else if(s.find("+") != std::string::npos){std::cout << "\nAdd";}
	else if(s.find("/") != std::string::npos){std::cout << "\nDivide";}
	else if(s.find("-") != std::string::npos){std::cout << "\nSubtract";}
	***/
	
	return 0;
}
void calc()
{
	int nOneInt,dOneInt,nTwoInt,dTwoInt;
	std::string nOne,dOne,nTwo,dTwo,operatorValue,s,delimiter,delimiter2,resultInString;
	
	std::cout << "\nEnter a fraction expression: ";
	std::getline(std::cin,s); //get the fraction expression from the user and store in string var s

	delimiter = "/";
	delimiter2 = " ";
	//establish delimeters that are expected to be in the fraction expression
        std::cout << "check1";
	nOne = s.substr(0, s.find(delimiter)); //make numerator one equal to any string before delimeter one
	std::istringstream (nOne) >> nOneInt; //convert nOne from string to int
	s = s.substr(nOne.size() + delimiter.size(),s.size() - nOne.size()); //remove the numerator plus the first delimeter
   
	dOne = s.substr(0,s.find(delimiter2)); //find demoinator one by finding delimeter 2 and extracting before value
	std::istringstream (dOne) >> dOneInt; //convert dOne from string to int
	s = s.substr(dOne.size() + delimiter2.size(), s.size() - dOne.size()); //remove first denominator plus space

	operatorValue = s.substr(0, s.find(delimiter2)); //make operator equal to - or / or * or +
	s = s.substr(operatorValue.size() + delimiter2.size(), s.size() - operatorValue.size()); //remove operator from string

	nTwo = s.substr(0,s.find(delimiter)); //make numerator two equal to fractional numerator 2
	std::istringstream (nTwo) >> nTwoInt; //convert nTwo from string to int
	s = s.substr(nTwo.size() + delimiter.size(), s.size() - nTwo.size()); //remove second slash plus numerator 2

	dTwo = s; //the only thing left is the value of denominator 2
	std::istringstream (dTwo) >> dTwoInt; //convert dTwo from string to int

	calcOperator(nOneInt,dOneInt,nTwoInt,dTwoInt,operatorValue);
	operatorValue.clear();
	nOne.clear();
	dOne.clear();
	nTwo.clear();
	dTwo.clear();
	s.clear();
}

void calcOperator(int num1, int den1, int num2, int den2, std::string instructionString)
{
	int newN,newD;
	if(instructionString.find("*") != std::string::npos)
	{
		//n1/d1 * n2/d2 = n1*n2 / d1*d2
		newN = num1 * num2;
		newD = den1 * den2;
		calcReduction(newN,newD);
	}
	else if(instructionString.find("+") != std::string::npos)
	{
		//n1*d2 + d1*n2 / d1*d2
		newN = (num1 * den2) + (den1 * num2);
		newD = den1 * den2;
		calcReduction(newN,newD);
	}
	else if(instructionString.find("/") != std::string::npos)
	{
		//n1/d1 / n2/d2 = n1*d2 / d1*n2
		newN = num1 * den2;
		newD = den1 * num2;
		calcReduction(newN,newD);
	}
	else if(instructionString.find("-") != std::string::npos)
	{
		//n1/d1 - n2/d2 = n1*d2 - d1*n2 / d1*d2
		newN = (num1 * den2) - (den1 * num2);
		newD = den1 * den2;
		calcReduction(newN,newD);
	}
}
void calcReduction(int num, int den)
{
	bool reductionFlag = false;
	for(int i = den; i > 0; i--)
	{
		if(num % i == 0 && den % i == 0)
		{
			num = num / i;
			den = den / i;
			reductionFlag = true;
		}
	}
	std::cout << num << "/" << den << ".";
	if(reductionFlag == true){
		std::cout << " The result was reduced.";
	}
}


Edit 1: I inserted the last check the code prints, meaning, this is the last thing it process before the instance is thrown. At "check 1"

Edit 2: It seems to be a problem with me trying to pull out a larger substr than the size of the string. On running the program a few more times I realized that check 1 was after my code was supposed to ask the user to enter a new fraction. However, the program never prompted me to. This is why what I'm trying to remove from s is bigger than the actual size of s which is why it's calling an out of range.
s = s.substr(nOne.size() + delimiter.size(),s.size() - nOne.size()); <-- removing this line allows it go further. Why isn't getline() prompting me again after running a second time with while loop.

Edit 3: error is solved by insertingstd::cin.ignore(); before getline()
Last edited on
Topic archived. No new replies allowed.