Accumulator and while loops - c++

while(true) {
infile >> studentCode >> test1 >> test2 >> lab >> finalExam;
finalG = finalGrade(test1, test2, lab, finalExam);
gradeSum = gradeSum + finalG;
letterG = letterGrade(finalG);
gradePrinter(); // Prints grades to outfile.
if (infile.eof())
break;
}
In my while loop, the variable finalG does not add to gradeSum at the end of every loop. (gradeSum is initialized to 0 before the while loop). Instead, the value of gradeSum stays at zero and just adds whatever the last number the function finalGrade(test1, test2, lab, finalExam) outputs. For example, if the following numbers are outputted by function:
10
15
30
35
40
The gradeSum will return 40 + 0, which just gives me 40 rather than the sum of the numbers. How can I fix this?

Problem
Your use of the while loop is faulty. You end up processing the grades one more time than is valid.
Let's say you have two lines in your file:
101 18 20 15 48
102 19 20 14 50
After the second line is read, infile.eof() is false. Hence, you continue reading. Reading does not succeed. Yet you process those numbers. You will probably end up processing the last line twice.
A solution
Simplify the while loop by using:
while ( infile >> studentCode >> test1 >> test2 >> lab >> finalExam )
{
finalG = finalGrade(test1, test2, lab, finalExam);
gradeSum = gradeSum + finalG;
letterG = letterGrade(finalG);
gradePrinter();
}
Disclaimer: This won't fix other logic errors in your code.

Related

C++: How to find the sum of a series of numbers separated by spaces

I am trying to create a programme taking two lines of imput, say
n
m1, m2, m3, ... , mn
where 1, 2, 3 ... n are all subscipts, so that n is the total number of integers that will be entered, and m1...mn are the integers themselves. Now, I want to find a way to sum m1 to mn up.
For example, if the user entered 5 as the first input line, we know that the user will input 5 numbers separated by space, but in the same line, say 12 14 17 19 28, the expected output should be 90. I understand that to take in inputs we need to use cin >> a >> b >> c >> d >> e after all the five variables have been defined. However, I am unable to find a way to solve it as the input on the first line is not always 5, and if it's 1000, it is not realistic to write cin >> a >>b ... 1000 times. Anyone can help? Thanks!
You said in comments:
If different lines I can still use for loop + cin. But single line when the quantity is not confirmed is hard :(
You can use a for loop regardless of whether the numbers are on a single line or on different lines. operator>> skips leading whitespace, and then stops reading on whitespace. Space and NewLine characters both count as whitespace. So, the following will work just fine (error handling omitted for brevity):
int n, num, sum = 0;
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> num;
sum += num;
}

cin >> val sometimes reads 0 depending on Ctrl-Z

I was trying to write a code in C++ in Windows using MinGW compiler, my code counts and prints the number of consecutive times a number occurs in a given set of input. The code is as follows:
#include <iostream>
int main()
{
int c_val = 0,val = 0,cnt = 1;
std::cin>>c_val;
while(std::cin>>val){
if(val==c_val)
cnt++;
else{
std::cout<<c_val<<" occurs "<<cnt<< " times"<<std::endl;
c_val = val;
cnt = 1;
}
}
std::cout<<val<<" occurs "<<cnt<<" times";
}
INPUT: 42 42 42 12 13 13 ^Z (press Enter)
OUTPUT:
42 occurs 3 times
12 occurs 1 times
0 occurs 2 times
But if I press Enter before ^Z then it looks like:
INPUT: 42 42 42 12 13 13 (press Enter) ^Z (press Enter)
OUTPUT:
42 occurs 3 times
12 occurs 1 times
13 occurs 2 times
I want to know why the variable val in my code stores 13, when I use ^Z key after pressing my return key and why does it store 0 if I give the ^Z key along with my input.
Here is what happens. I observed this using MinGW-w64 4.9.2. The behaviour was the same whether running the executable in a Windows console, or under Cygwin (but not using cygwin-mingw).
Pressing ^Z at the beginning of a line sets the end-of-file condition
Pressing ^Z anywhere else actually sends ASCII 26 character to the stream
I also observed:
cin >> val sets val to 0 if it fails due to the input not containing a number.
cin >> val leaves val unchanged if input fails due to end-of-file.
According to this thread that is the correct behaviour specified by C++11.
So your results can be explained. When you input 42 42 42 12 13 13^Z, it is the same as if you had written 42 42 42 12 13 13x. The first six numbers are read, and then when x is encoutered, cin >> val fails and sets val to 0.
But when you press Enter and then ^Z, it is as if you were reading from a file and you reached the end of the file. cin >> val leaves val unchanged and it is still holding the value that it had after the last successful cin >> val.
If you make the change suggested by Gautam Jha suggested then you will get 13 in both cases. This is because he effectively reads into a temporary int, and then only stores the temporary int into the real val if the read succeeded, thereby avoiding the behaviour where a failed read sets val to 0.
This is probably the desired behaviour although you might also want to check cnt > 0 to avoid a weird output in the case of totally empty input.
See the difference
#include <iostream>
int main()
{
int c_val = 0,val = 0,cnt = 1;
std::cin>>c_val;
int curr_val = 0;
while(std::cin>>val){ // in case of no value cin will set val =0
curr_val = val;
if(curr_val == c_val)
cnt++;
else{
std::cout<<c_val<<" occurs "<<cnt<< " times"<<std::endl;
c_val = curr_val;
cnt = 1;
}
}
std::cout<<curr_val<<" occurs "<<cnt<<" times";
}

standard input stream cin failing to prompt for input

1 #include<iostream>
2 using namespace std;
3
4 int main()
5 {
6 const double yen_to_euro=0.007215;
7 const double euro_to_dollar=1.12;
8 char currency;
9 double x;
10
11 while(currency!='q')
12 {
13 cout << "enter currency and unit(y , e, or d)";
14 cin >> x >>currency;
15
16 switch(currency){
17
18 case 'y':
19 cout <<"euro:"<< x*yen_to_euro<<" dollar:"<<x*yen_to_euro*euro_to_dollar<<'\n';
20 break;
21 case 'e':
22 cout <<"yen:"<< (x*(1.0/yen_to_euro))<<" dollar:"<<(x*euro_to_dollar)<<'\n';
23 break;
24 case 'd':
25 cout <<" yen:"<< x*(1.0/yen_to_euro)*(1.0/euro_to_dollar)<<" euro:"<<x*(1.0/euro_to_dollar)<<'\n';
26 break;
27 case 'q':
28 currency='q';
29 break;
30 default:
31 cout << "invalid";
32 break;
33
34 }
35
36 }
37
38
39 }
~
The intended function of the code above is to convert a selected currency( y for Japanese Yen, e for Euro , and d for US dollar) into the other currencies.
For instance, if I want to convert to 12 Japenese Yen, I would enter:
12y
which then the program would output
euro:0.08658 dollar:0.0969696
However, if I were to input 12e, I would receive an infinite loop. Double checking the code, there doesn't seem to be any logical errors.
Nevertheless, I sense the source of the trouble has to do with the cin at line 14 because if I take the amount x and the currency type separately like this:
cin>> x;
cin>> currency;
The code works fine, but I need to input the amount , followed by pressing enter, and then pressing the character that represents the currency-type. Is there a way to just enter all in one line, no spaces?
Furthermore, why is it behaving this way? This unusual behavior of going through infinite loop only happens when I enter e for Euro and q for quit.
12e is interpreted as the begin of a floating point number like 12e03. But the end is missing, so your stream is put on error (failbit). This state causes all subsequent input to fail until the failstate is cleared.
You could have an inner loop that checks such formatting errors:
while (...) {
...
while ( (cin >> x >> currency).fail() && !cin.eof()) { // loops as long as there's input and it's invalid
cout << "invalid format";
cin.clear();
}
if (cin.eof()) // if there's no longer input stop looping
break;
...
}
live demo
Note that you should initialize currency to something different than 'q' if you want to make sure that your loop is executed in every circumstance.
By the way, if you enter 12 e (with a space), 12 will be interpreted as the number and put to x and e to currency, as you expect.
As explained by other answers 12e refers to the scientific notation of floating point numbers and hence currency does not store 'e'.
To get the input in a single line without space, you should use std::getline and then parse the input string.
Since you know that the last character is always indicative of currency, the front characters can be converted to a number using std::stoi.
Replace cin >> x >>currency;
with
try{
std::string myLine;
std::getline (std::cin, myLine); // store line into myLine.
currency = myLine.back(); // get last character from line.
myLine.pop_back(); // remove last character from myLine.
x = std::stod(myLine); // try to conver the rest of the string to a double.
}
catch (...) {
//The user typed in something invalid.
currency= 'i';
}
Also, make sure to #include <string>
Note this solution assumes you are using C11.

Why won't my code print anything from the screen? (C++)

I am working with a file that contains a set of data:
x values y values
20.00 0
20.02 15
20.04 27
20.06 39
20.08 54
20.10 65
20.12 75
The program is supposed to calculate the area under curve. In this part I am to do so for the first 6 x-y sets. My algorithm for finding the area is the sum of each trapezoid , which for these constraints, should only be 5 trapezoids. The each of each trapezoid is defined by: A = 0.5(base-base_0) * (height + height_0).
This is my code:
int main()
{
ifstream infile;
double AreaCurve = 0.0, NumberTraps = 0.0, height, height_0, base, base_0, AreaTrap;
infile.open("xydata.dat");
cin.ignore(20, '2');
while (NumberTraps < 6)
{
infile >> base_0;
infile >> height_0;
infile >> base;
infile >> height;
AreaTrap = 0.5 * (base - base_0) * (height + height_0);
AreaCurve += AreaTrap;
NumberTraps++;
}
cout << "The area under the curve is: " << setprecision(4) << AreaCurve << endl;
infile.close();
return 0;
}
When I compile the program nothing prints to the screen. I am not sure why this is happening but I believe it may have to do with an error in the line of my code containing the cin.ignore function (I can't edit the data, and I need to skip the line that reads: "x values\t\t y values")
Remove the line cin.ignore(20, '2'); .
This line will make your program wait for user input until they either enter twenty 2s, or enter a different character.
You shouldn't be reading any user input in this program, your input data comes from infile.
You will need to add code to ignore the first line of infile. A simple way to do that is string s; getline(infile, s);
Your program's main loop has a logic bug as well. You are reading in 2 lines at a time and considering that trapezoid, but then you are ignoring the trapezoid just after that one. (So you only count about half of the trapezoids).
Finally you should check for input success before processing that trapezoid:
if ( !infile )
break;
To ignore the first line of the infile stream (regardless of its length) you need:
infile.ignore( numeric_limits<streamsize>::max(), '\n' ) ;
Note, this needs the <limits> header.
You do not need to ignore to the first '2'. For starters the first x value would always have to start with '2', but more usefully std::istream::operator>> (double&); skips white-space including line ends in any case.
There are other issues with this code, such as attempting to read more values that the file contains, an incorrect integration algorithm, and having no error checking for a valid stream. Consider:
infile.ignore( numeric_limits<streamsize>::max(), '\n' ) ;
infile >> base_0;
infile >> height_0;
while( infile.good() )
{
infile >> base;
infile >> height;
if( infile.good() )
{
AreaTrap = 0.5 * (base - base_0) * (height + height_0);
AreaCurve += AreaTrap;
base_0 = base ;
height_0 = height ;
}
}

Problems getting values from ifstream correctly

**EDIT: I got it to work by changing the 'inStream >> next' to 'inStream >> skipws >> next'. In one of my earlier functions (to pull the last and first name) I had toggled noskipws. Apparently that toggle lasts between functions?
I have a program that is part of an assignment that is supposed to read a text file that is set up in the format of: "lastname firstname 1 2 3 4 5 6 7 8 9 10" (where each of the 10 numbers are integer scores).
I am able to read in the lastname and firstname fine, but when I go to start reading in the numbers, I am only able to read in the first one and then all the rest get set to 0.
Below is the function that is supposed to read the scores in. inStream has already had the lastname and firstname taken off. The textfile I am using has one line:
Tosis Halley 85 23 10 95 43 12 59 43 20 77
When run the program and print out the student.score values from 0 to 9, the first one displays correctly as '85' but all the reset show as '0'. Thoughts?
void GetScores (ifstream& inStream, record& student)
{
int score[10] = {-1, -1, -1, -1 ,-1 ,-1 ,-1 ,-1 ,-1 ,-1};
int next;
int counter = 0;
string test;
for (int i = 0; i < 10; i++)
{
inStream >> next;
student.score[i] = next;
}
}
Assuming the input is indeed all numbers, the function should actually work. However, you should always verify that inputs were indeed read correctly:
for (int i = 0; i != 10 && inStream >> next; ++i) {
student.score[i] = next;
}
if (!inStream) {
std::cout << "an input error occured\n";
}