I have a text file which first describes some lines and then describes some colorful lines:
1 2 3 4
5 6 7 8
9 10 11 12
red 1 0 0 1 2 3 4
green 0 1 0 5 6 7 8
blue 0 0 1 9 10 11 12
The number of lines in each section is unknown at time of execution
I overloaded the std::cin >> operator for these structs:
struct Point { int x, y; }
struct Line { Point a, b; }
struct Color { float r, g, b; std::string name; };
struct ColorfulLine { Line line; Color color; };
(Full example here: http://ideone.com/bMOaL1 [already works - edited according to the accepted answer])
Now I need to iterate over the file using Lines and ColorfulLines:
Line line;
while(cin >> line) { cout << "We've got a line!\n"; }
ColorfulLine color_line;
while(cin >> color_line) { cout << "We've got a colorful line!\n"; }
// actually I'm putting them into std::lists but I skipped this part for simplicity
And here is the problem - the colorful lines are never fetched, i.e. the second loop is not executed.
I have an assumption why it happens but don't know how to fix it:
When std::cin tries to fetch the 4th Line, it fails because instead of a number there's the string "red".
Next, in the second while loop, std::cin tries to read a string (Color.name) but it sees a number, and then fails too.
I tried to put some random word before the ColorfulLines section hoping that when the first loop fails, the second will start reading from the "red" string, but it didn't.
How to fix this?
After the first loop breaks, std::cin is in a bad state. That's why the loop breaks in the first place. Performing reads on a bad stream fails immediately, thus the second loop is never entered.
To solve this, reset the error state after the first loop breaks with
std::cin.clear();
Related
We were asked to write a simple C++ program by our teacher to add two numbers in the following format:
input: 12 14
output: m+n = 26
The program must also work for other inputs in the form:
input: Hello please add 12 and 14 !
output: m+n = 26
The solution that was given was:
#include <iostream>
using namespace std;
int main(){
int m,n;
char ch;
while(cin.get(ch)){
if(isdigit(ch))
{
cin.putback(ch);
cin>>m;
break;
}
}
//cin.putback() restores the last character
//read by cin.get() back to the input stream
while(cin.get(ch)){
if(isdigit(ch))
{
cin.putback(ch);
cin>>n;
break;
}
}
cin.ignore(80,'\n');
cout<<"m + n = "<<m+n<<endl;
return 0;}
But now I need to know why this program also works for numbers that are not single digits. Shouldn't cin.get(char) just read one digit and cin.putback() return the same? Please help me I am a beginner.
Yes, cin.get() will read only one character at a time.
The important part, where the number is actually read, is 4 lines below: cin>>m;. This will consume as many digits as possible and store the resulting integer in m.
Some more details:
// example with input 524 42
while(cin.get(ch)) // extract one character at a time
{ // ch='5', remaining input="24 42"
if(isdigit(ch)) // if it's a digit (0-9), then:
{
cin.putback(ch); // Put it back into the stream, "unread" it
// remaining input="524 42"
cin >> m; // extract an integer from stream
// m=524, remaining input="42"
break;
}
}
The reason for the loops seems to be to skip over any non-numeric input before a number appears. Note that there is a little bug here, since it will also ignore leading signs. (e.g. input -4 4 will output m + n = 8)
I have a really big csv file with 10 comma seperated values in each line, at the end of each line is a \n.
Now I have a row with just semicolons. The amount of values corresponds to how many comma seperated values are in the other lines
5696;Neusser Strasse;49;1;50670;Neustadt-Nord;18.09.1990;um;1890;Wohn- u. Geschäftshaus
;;;;;;;;;
5698;Richard-Wagner-Strasse;18;1;50674;Neustadt-Süd;18.09.1990;;1905;Wohnhaus
When I now start to run my program, it gets the "5698" from the 3rd line as the last value of the 2nd line, so what I get is this:
0 Denkmalnummer: 5696
1 Strasse: Neusser Strasse
2 Nummer: 49
3 Bezirk: 1
4 PLZ: 50670
5 Ort: Neustadt-Nord
6 unter Schutz: 18.09.1990
7 Baujahr Zusatz: um
8 Baujahr: 1890
9 Kurzbezeichnung: Wohn- u. Geschäftshaus
****************
0 Denkmalnummer:
1 Strasse:
2 Nummer:
3 Bezirk:
4 PLZ:
5 Ort:
6 unter Schutz:
7 Baujahr Zusatz:
8 Baujahr:
9 Kurzbezeichnung: 5698
****************
0 Denkmalnummer: Richard-Wagner-Strasse
1 Strasse: 18
2 Nummer: 1
3 Bezirk: 50674
4 PLZ: Neustadt-S├╝d
5 Ort: 18.09.1990
6 unter Schutz:
7 Baujahr Zusatz: 1905
8 Baujahr: Wohnhaus
9 Kurzbezeichnung: 5699
This continues and messes up the proper alignment of the data.
My major code looks like this (via getline the file's data is stored in a vector):
if (denkmallist.is_open()) {
if (counter < 1) {
while (getline(denkmallist, line)) {
stringstream ss(line);
while (getline(ss, line, ';')) {
ausgelesenes.push_back(line);
counter++;
daten.push_back(ausgelesenes);
ausgelesenes.clear();
}
}
}
else{
while (getline(denkmallist, line)){
ausgelesenes.push_back(line);
}
daten.push_back(ausgelesenes);
ausgelesenes.clear();
}
}
and the code which then displays the results looks like this:
for(int x=0, y=semis; x<=semi2+2, y<daten.size(); x++, y++){
if (x > semi2-1){
x = 0;
cout << '\n' << "****************" << '\n' << endl;
}
cout << x << " " << daten[x][0] << ": " << daten[y][0] << endl;
}
Semi represents the amount of entires.
I would be very happy if someone could help me out :)
The inner loop uses the call to getline to decide when it has finished parsing the text string that was read by the outer call to getline. That's okay, but you have to watch out for extraneous failures.
For the first line, the inner loop runs ten times; once for each field that ends with a ; and once more to read the remaining text.
For the second line, there is no text after the last ;. After the ninth time through the loop, getline sees no text and no delimiter, so it concludes that it's at the end of the input. The call fails, and the inner loop exits after reading only nine inputs instead of the expected ten.
I'm trying to create a simulation in which I have objects moving within a rectangular grid. Information is given in the form of a text file. Sample input is as follows:
5 5
0 1 N
PFPFFSF
2 3 S
FSFFSFFSPF
First line is the dimension of the grid (in this case 5 x 5 assuming the bottom left coordinate is 0,0)
The rest of the input is just info in regards to the object and how it moves. Each object has 2 lines of input. First line is it's starting coordinates and orientation while the second line describes its movements.
When using an input stream, how can I grab the input so that it groups accordingly?
I know for the first line, I can just use
simulationSettings >> x >> y;
to grab the size of the grid.
However, is there a way of grabbing the rest of the input and grouping the info by 2 lines (for each object)?
So, for example, stream the input so that my object1 will have 0 1 N and PFPFFSF while object 2 has 2 3 S and FSFFSFFPF and so on should there be more objects.
If you can simply ignore how the file is actually structured in line, you structure is just:
2 integer values for the grid size
n times (per object):
2 integers for the initial position
one string for the initial direction
one string for the movements
You could just use:
simulationSettings >> x >> y;
if (! simulationSettings.good()) {
// process error condition and exit
}
for(;;) {
int xinit, yinit;
std::string direction, movements;
simulationSettings >> xinit;
if (simulationSettings.eof()) break; // normal end of file
simulationSetting >> yinit >> direction >> movements;
if (! simulationSettings.good()) {
// process error condition and at least break from the loop
}
// process the object
}
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.
I need to get very basic input from an external file in C++. I tried searching the internet a few times but nothing really applied to what I need. This would be a .txt file that the input it coming from, and it would be filled with lines like this:
131
241
371
481
I have code already to manually get this input, and it looks like this:
using namespace std;
//Gets the initial values from the user.
int control=0;
while (rowb!=0){
cout << "Row: ";
cin >> rowb;
cout << "Column: ";
cin >> columnb;
cout << "Number: ";
cin >> numb;
row[control]=rowb-1;
column[control]=columnb-1;
num[control]=numb;
control++;
}
This is part of a program that solves sudoko boards. The inputed numbers are the initial values that a sudoko board holds, and the user is inputing the row, column, and number that comes from a board.
What I need is to be able to create a .txt file with these numbers stored in rows so that I do not have to enter so many numbers. I have very little idea how to go about doing this. Mainly I'll only be using the txt file for testing my program as I move along with adding more code to it. It takes 150+ entered numbers within my program just to get a single board, and it takes a lot of time. Any accidentally wrong entered value is also a huge problem as I have to start again. So how would I get C++ to read a text file and use those numbers as input?
Aside from the other suggestions, you can simply redirect a file to standard input, like so (where $ is the command prompt):
$ myprogram < mytextfile.txt
That will run myprogram just as normal but take input from mytextfile.txt as if you had typed it in. No need to adjust your own program at all.
(This works on both Unix/Linux systems and on Windows.)
You can open a file for input with std::ifstream from the header <fstream>, then read from it as you would from std::cin.
int main()
{
std::ifstream input("somefile.txt");
int a;
input >> a; // reads a number from somefile.txt
}
Obviously, you can use >> in a loop to read multiple numbers.
Create an std::ifstream object, and read from it just like you would from std::cin. At least if I understand what you're trying to do, the 131 as the first input is really intended to be three separate numbers (1, 3, and 1). If so, it's probably easiest to change your input file a bit to put a space between each:
1 3 1
2 4 1
3 7 1
4 8 1
Personally, I would start with a different format of the file: enter a value for each cell. That is, each row in the input file would represent a row in the sudoko board. Empty fields would use a space character. The immediate advantage is that the input actually pretty much looks like the sudoko board. Also, you would enter at most 90 characters: 9 characters for the board and a newline for each line:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
int main(int ac, char* av[])
{
std::ifstream in(ac == 1? "sudoko.init": av[1]);
char board[9][9];
for (int i(0); i != 9; ++i)
{
in.read(board[i], 9).ignore();
}
if (!in)
{
std::cout << "failed to read the initial board\n";
}
else
{
typedef std::ostream_iterator<char> iterator;
std::fill_n(iterator(std::cout << "board:\n\n+", "+"), 9, '=');
for (int i(0); i != 9; ++i)
{
std::copy(board[i] + 0, board[i] + 9, iterator(std::cout << "\n|", "|"));
std::fill_n(iterator(std::cout << "\n+", "+"), 9, (i + 1) % 3? '-': '=');
}
std::cout << "\n";
}
}
This would take input like this:
4 5 3 8
71 3
16 7
6 4 7
6 8
1 9 5
6 42
5 94
4 7 9 3
Note that each of these lines uses 9 characters. You might want to use something more visible like ..