Console output and file contents unmatched - c++

I desire to output the file contents to the console using file handling. The variable marks is user defined.Now the contents are saved in the file correctly(I have attached a screenshot below). When I want to read the file the user defined functions gives inaccuarte output for the last two times.
Contents of file:
Calculus 11
FoP 22
AP 33
LCA 44
Workshop 55
Pak Studies 66
English 77
Output
Calculus 11
FoP 22
AP 33
LCA 44
Workshop 55
Pak Studies 0
English 1875928375
int marks[7],i=0;
string subject[7]={"Calculus","FoP","AP","LCA","Workshop","Pak Studies","English"};
ifstream file3("Task4.txt");
while(!file3.eof())
{
file3>>subject[i]>>marks[i];
cout<<subject[i]<<" "<<marks[i]<<"\n";
i++;
}
file3.close();

You have multiple problems here:
eof flag is only set on a failed read. This means by the time you check for it you already have a failed read.
streams read one token at a time, meaning you do not read the entire Pak Studies string (just "Pak").
then you attempt to read the second token into an integer ("Studies") which puts the stream in an error state. The stream is not in eof state though, so your loop continues, possibly traversing memory with i > 7 (and triggering undefined behavior).
The correct way (or rather "a more correct way") to do it:
read input as long as you have input lines:
std::string line;
while(std::getline(file3, line))
{
// find position of last space
int pos = line.rfind(' ');
subject[i] = line.substr(0, pos - 1);
mark[i] = std::stoi(line.substr(pos, std::npos));
i++;
if(i == 7)
break;
}

Your loop should be:
while (file3>>subject[i]>>marks[i])
{
++i;
cout<<subject[i]<<" "<<marks[i]<<"\n";
}
See Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())) considered wrong? for more details.

Related

What are all the condition that causes the while loop to break when streaming from file

I have some beginners questions about file handing and loops. For example, lets say the file contains words and integers. And the logic is to read only the integers from the file. I know the outer loop ends when the pointer is at end of file. But I don't know the conditions that causes the inner loop to break. Does the loop break if it encounters words? if so does it set the file pointer to next line or does the file pointer not move? If the inner loops fails to run the first time, where does it set the file pointer?
here is what's on the file.
some words 11 12 15 14 15 some words 122
some words 45 1 12 2135 words
//here is the logic
int someInt = 0, counter = 0;
while (!file.eof()) //Runs until end of file
{
while(file >> someInt) //only reads integers. when does this loop break?
{
counter++;
}
}

How can I read from the same input file multiple times from different points within the file using sentinel values (-1) in c++?

I have a task where I have to read different sections of an input file(.txt) of integers in c++. The file contains an unknown number of positive integers, each separated by white-space with several sentinel values of -1 placed randomly in the list to "break-up" the list into sections and another -1 at the end of the file.
Here is a sample of my input file(.txt):
3 54 35 4 9 16 -1 14 57 32 4 6 8 41 2 -1 5 6 54 21 3 -1
Here is what I've attempted so far:
int data[20],
index = 0;
ifstream fin;
fin.open("data_file.txt");
while (index < 20 && data[index] != -1 && fin >> data[index])
{
cout << data[index] << endl;
index++;
}
I can't get this to read past the first SV even if I repeat this while loop. It always just starts at the beginning of the file.
How do I read again STARTING AFTER the first SV to the second SV? The only methods I know involve reading a file from beginning to end. How do I read seperate sections?
Thanks in advance for any help,
Cheers
It sounds like you just want to group information from the file. I will not provide code since you didn't, but I may help you with the logic:
Create a file object, 2d vector, and a string
Read from the file object to the string
if the value is equal to "-1", then add a new row. Else, add a new column
The result will be a 2d vector with the rows being each group, and the columns being each positive number in that group.

C++ primer 5th 1.4.4

I'm a beginner of C++,while reading the book 《C++ Primer》 5th,I'm a little confused in chapter 1.4.4.
when I run the program in 1.4.4,here is the step in my computer:
#include <iostream>
int main()
{
// currVal is the number we're counting; we'll read new values into val
int currVal = 0, val = 0;
// read first number and ensure that we have data to process
if (std::cin >> currVal)
{
int cnt = 1; // store the count for the current value we're processing
while (std::cin >> val)
{ // read the remaining numbers
if (val == currVal) // if the values are the same
++cnt; // add 1 to cnt
else
{ // otherwise, print the count for the previous value
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
currVal = val; // remember the new value
cnt = 1; // reset the counter
}
} // while loop ends here
// remember to print the count for the last value in the file
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
} // outermost if statement ends here
return 0;
}
type the numbers:42 42 42 42 42 55 55 62 100 100 100
type Ctrl+D
the program run by itself(not waitting me to input Enter)
output the answer:
42 occurs 5 times
55 occurs 2 times
62 occurs 1 times
secondly type Ctrl+D
output the remained answer
100 occurs 3 times
my question is why I have to input second times of Ctrl+D,my code environment is Ubuntu+GCC,I also run it in VS2013,it only needs to input once Ctrl+D.
I've searched in stackoverflow,but I didn't got my answer.
Incorrect output. C++ primer 1.4.4
confused by control flow execution in C++ Primer example
C++ Primer fifth edtion book (if statement) is this not correct?
In Linux Ctrl+D does not unconditionally mean "end-of-file" (EOF). What it actually means is "push the currently pending input to whoever is waiting to read it". If the input buffer in non-empty, then hitting Ctrl+D does not create EOF condition at the end of the buffer. Only if you hit Ctrl+D when the input buffer is empty, only then it will produce EOF condition. (See here for a more technical explanation: https://stackoverflow.com/a/1516177/187690)
In your case you are inputting your data as a single line and then hitting Ctrl+D at the end. This pushes your input to your program and makes your program to read and process the data. But it does not produce EOF condition at the end of your input.
For this reason, once all input data is read by the cycle, your program does not see it as EOF. The cycle keeps waiting on empty input buffer for additional data. If at this point you press Ctrl+D again, it will be recognized as EOF and your program will exit the cycle and print the last line.
This is why you have to hit Ctrl+D twice: the first hit works pretty much as Enter key would. And only the second hit creates EOF condition.
It is possible that the program you have provided was not intended to accept input all at once as you have shown.
The reason it does not provide the output you expect is due to the fact that the program is still expecting input, because the >> operation's return value is still logically true/error-free. (It's blocked at: while (std::cin >> val)) This is so, because you have not provided an EOF to the input stream after the last 100. Said another way, your first Ctrl+D gets past the if (std::cin >> currVal). Your second Ctrl+D gets past the while (std::cin >> val).
See the accepted answer to this question for why the first Ctrl+D does not result in a eofbit error on your input stream: Why do I have to type ctrl-d twice? The bottom line is that Ctrl+D does not necessarily mean EOF; it results in a flush of the input stream.
Entering the numbers one at a time would provide the output you expect.
Alternatively, you could provide: 42 42 42 42 42 55 55 62 100 100 100\n.
http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/

Parsing columns into arrays, while discriminating whats in the rows

I'm trying to parse a text file that is outputted like the example below, my example has limited entries but my actual one has over 15000 lines, so i can't read these in individually:
ID IC TIME
15:23:43.867 /g/mydata/dataoutputfile.txt identifier
0003 1233 abcd
0043 eb54 abf3
000f 0bb4 ac24
000a a325 ac75
0023 0043 ac91
15:23:44.000 /g/mydata/dataoutputfile.txt identifier
0003 1233 abcd
0043 eb54 abf3
000f 0bb4 ac24
000a a325 ac75
0023 0043 ac91
Is kind of the output I have. The time column resets every so often.
What I am doing now is making 2 additional columns in addition to the 3 i have in my example. The first column is the conversion of the ID column, into a translation into an understandable message. The second additional column will calculate the difference between each time code, except when the time code resets.
My logic is, is to read each column into an array so I can perform the necessary translations and operations.
I am focusing on getting the timecode differential first, as I think getting the translation will be a bit simpler.
The problem I'm having is getting the entries read into their matrices:
my code looks a bit like this:
while(readOK && getline(myfile,line))
{
stringstream ss(line);
string ident,IC,timehex,time,filelocation;
string junk1,junk2;
int ID[count];
int timecode[count2];
int idx=0;
if(line.find("ID") !=string::npos)
{
readOK=ss>>ident>>IC>>timehex;
myfile2<<ident<<"\t\t"<<IC<<"\t\t"<<timehex<<"\t\t"<<"ID Decoded"<<"\t\t"<<"DT"<<endl;
myfile3<<"headers read"<<endl
}
else if(line.find("identifier") != string::npos)
{
readOK=ss>>time>>filelocation;
myfile3<<"time and location read";
myfile2<<time<<"\t\t"<<filelocation<<endl;
}
else //this is for the hex code lines
{
readOK=ss>>hex>>ID[idx]>>IC>>timecode[idx];
if (readOK)
{
myfile2<<setw(4)<<setfill('0')<<hex<<ID[1000]<<"\t\t"<<IC<<"\t\t"<<timecode[1000]<<endl;
myfile3<<"success reading info into arrays"<<endl;
}
else
myfile3<<"error reading hex codes"<<endl;
}
idx++;
}
Although this code doesn't work correctly. I can't just read in every line quite the same because of the intervening time and file location entries that are inserted to help keep track of when I am looking at in my code.
My gut is telling me that I'm calling the matrix entries too early and they haven't been filled yet, because if I cout number 1000, I get a 0 (i have well over 15000 lines in my input file and I have the boundaries of my arrays set dynamically in another part of my program).
I can't seem to figure out how to get the entries assigned correctly as I am having some inheritance issues with the count variable resetting to 0 every time through the loop.
Define int idx outside of the scope of the while loop (before the while). As it is now, each time through the loop it will be reset.

sorting through a file/returning info

Just need general project help.
Basically I need to do this for 8 players. The numbers come from a file im supposed to call in. The first 5 numbers for for the first 5 games, the next for rebounds, and then for blocks. Im assuming I need to call in a loop to read the first name, last name, points, rebounds and blocks, process that info and then output the information.Any tips/ suggestions?
ex from the text file:
Thomas Robinson 17 28 10 16 10 11 12 13 8 9 1 1 1 0 1
ex from what I'm supposed to return that information to
Game Log
-----------------------------------------------------------------------------
Player Name : Thomas Robinson
-----------------------------------------------------------------------------
Game # Points Rebounds Blocks
-----------------------------------------------------------------------------
1 17 11 1
2 28 12 1
3 10 13 1
4 16 8 0
5 10 9 1
-----------------------------------------------------------------------------
I think this is homework, but since I don't know which functions can be used, and which functions can't, my answers may be can't fit the request.
At a first look, I got three ideas.
1) using ifstream::get()
ifstream in_file;
in_file.open("your_file_name.txt");
char ch;
string str = "";
while(in_file.get() != '\n')
{
str = "";
while((ch = in_file.get()) != ' ')
{
// add ch to str.
str += string(&ch, 1);
}
// push str into an array, vector, stack, etc.
/*...*/
}
in_file.close();
2) read the line into a string, and then use a split function, you can find how to implement a split function everywhere.
3) use the ifstream::getline() function, it provides a delemiter parameter.
you can find the usage of ifstream::get() and ifstream::getline() here and here
The code I provide in 1) is probably not a good practice, you should check the 'EOF' stream error, in_file.open()'s exceptions etc.
btw, the code I first wrote was an error code, you can't use str += string(ch), you should either write str += string(&ch, 1) or str += string(1, ch) or str += ch you can find string's constructors here. Sorry for the error code again.
You can parse the file with the ">>" operator pretty nicely if everything is separated by spaces and newlines. Which is how the ">>" operator works. So, yes, you need a loop. Basically you want the loop to work like this:
(I never knew you could do this in Comp Sci 1. It would've saved me so much trouble...I used to do things like what the other answer is doing.)
(I'm also assuming you know how to open a txt file as an ifstream. If not, see http://www.cplusplus.com/reference/iostream/ifstream/open/.)
int temp;
int n = 0;
int x = 1;
while(textfile >> temp) // Each time through the loop, this will make temp
// the next value in the file. It will stop when
// there's nothing more to read.
{
/* Now it's going to go from left to right through the file, so you
need some logic to put it in the right place. you know that every
five numbers start a new column, so:*/
array[x][n] = temp; //Start x at 1 because you're skipping the first column
n++;
if (n == 5) {
n = 0;
x++; //Every five values, move on to the next column
}
Now your array will have the stuff where it needs to be. Just output it according to plan.