Reading math equations in from file - c++

I'm making a program where the users get a menu like this
Multiplication 1
Division 2
Subtraction 3
Addition 4
Review 5
where they can choose an option and put in the number range they want to work with and how many problems they want to do and it generates math problems for them.
That part works and I have it so when they get one wrong it puts the problem into a file math.txt using fout and that works.
What I'm trying to do now is when they choose to review it reads in the file and gives them those problems.
The file is in the format of (for example)
1 + 1 =
2 * 2 =
I'm just not sure how to read in the numbers and identify what operation it is (multiplication, addition etc.)
I've tried just getting it to read in a number with
std::ifstream fin("math.txt");
int x;
fin>>x;
But that returns 0 everytime.
So to summarize, my question is-- How can I read in a file and pull the equation (ex. 4 + 4 = \n 3 / 3 = ) so that the user can solve it?

It sounds like the problem is that you haven't flushed the previous write operation. You can either do this explicitly with flush() or close() your fout instance. Example:
std::ofstream fou("math.txt");
fou << "1 + 1 =";
// Need this: fou.close();
std::ifstream fin("math.txt");
int x;
fin >> x;
std::cout << x;
I was able to reproduce your problem when fou.close() was missing.

Related

Moving through text file c++

I'm trying to save numbers from first txt file to second one in reversed order.
To be clear, inside 1st txt I have typed numbers from 1 to 10 (decimal notation). When I try to count them, I get 5 or 7, depending on what's between them (space or enter).
Then, another error is that inside 2nd txt program saves as much "0s" as dl's variable value is equal to instead of loaded numbers in reversed order.
I paste the whole code, because I don't know file operation rules good enough to determine which exact part could be the source of problem. Thank You in advance.
#include <fstream>
#include <iostream>
using namespace std;
int main() {
fstream plik1;
plik1.open("L8_F3_Z2a.txt", ios::in | ios::binary);
fstream plik2;
plik2.open("L8_F3_Z2b.txt", ios::out);
if(!plik1.good() || !plik2.good()) {
cout << "file(s) invalid" << endl;
return 1;
}
plik1.seekg(0, ios::end);
int dl = plik1.tellg() / sizeof(int);
cout << "length = " << dl << endl;
int a;
for(int i = 0; i < dl; i++) {
plik1.seekg((i + 1) * sizeof(int), ios::end);
plik1 >> a;
plik2 << a;
cout << i + 1 << ". a = " << a << endl;
}
plik1.close();
plik2.close();
return 0;
}
edit the output is:
length = 7
1. a = 0
2. a = 0
3. a = 0
4. a = 0
5. a = 0
6. a = 0
7. a = 0
--------------------------------
Process exited after 0.03841 seconds with return value 0
Press any key to continue . . .
Problem
When a file is encoded as text the binary size of the data is irrelevant.
int dl = plik1.tellg() / sizeof(int);
will get you the side of the file in integers, but the file isn't storing integers. It is storing a stream of characters. Say for example the file holds one number:
12345
which is five characters long. Assuming the file is using good ol ASCII, that's 5 bytes. When 12345 is converted to an int it will probably be 4 or 8 bytes and almost certainly not 5 bytes. Assuming the common 32 bit (4 byte) int
int dl = plik1.tellg() / sizeof(int);
int dl = 5 / 4;
int dl = 1;
Yay! It worked! But only by the grace of whatever deity or cosmic entity you worship. Or don't worship. I'm not going to judge. To show why you can't count on this, lets look at
123
this is three characters and 3 bytes, so
int dl = plik1.tellg() / sizeof(int);
int dl = 3 / 4;
int dl = 0;
Whoops.
Similarly
1 2 3 4 5
is five numbers. The file length will probably be the sum of one byte per digit and one byte per space, 9 bytes.
Where this gets weird is some systems, looking at you Windows, use a two character end of line marker, carriage return and a line feed. This means
1
2
3
4
5
will sum up to 13 bytes.
This is why you see a different size depending on whether the numbers are separated with spaces or newlines.
Solution
The only way to find out how many numbers are in the file is to read the file, convert the contents to numbers, and count the numbers as you find them.
How to do that:
int num;
int count = 0;
while (plik1 >> num) // read numbers until we can't read any more
{
count++;
}
From this you can determine the size of the array you need. Then you rewind the file, seek back to the beginning, allocate the array and read the file AGAIN into the array. This is dumb. File IO is painfully slow. You don't want to do it twice. You want to read the file once and store as you go without caring how many numbers are in the file.
Fortunately there are a number of tools built into C++ that do exactly that. I like std::vector
std::vector<int> nums;
int num;
while (plik1 >> num)
{
nums.push_back(num);
}
vector even keeps count for you.
Next you could
std::reverse(nums.begin(), nums.end());
and write the result back out.
for (int num: nums)
{
plik2 << num << ' ';
}
Documentation for std::reverse
If your instructor has a no vector policy, and unfortunately many do, your best bet is to write your own simple version of vector. There are many examples of how to do this already on Stack Overflow.
Addendum
In binary 5 integers will likely be 20 or 40 bytes no matter how many digits are used and no separators are required.
It sounds like storing data as binary is the bees knees, right? Like it's going to be much easier.
But it's not. Different computers and different compilers use different sizes for integers. All you are guaranteed is an int is at least 2 bytes and no larger than a long. All of the integer types could be exactly the same size at 64 bits. Blah. Worse, not all computers store integers in the same order. Because it's easier to do some operations if the number is stored backwards, guess what? Often the number is stored backwards. You have to be very, very careful with binary data and establish a data protocol (search term for more on this topic: Serialization) that defines the how the data is to be interpreted by everyone.

parsing /proc/stat using c++

I'am new to c++ and a little bit in Linux. I have simple project that need to parse CPU stat from /proc/stat file and compute CPU usage. I have tried doing it on full bash script. but what i need is c++. I just need a little help. /proc/stat gives a lot of numbers and i know different column represent on something. like User,Nice,System,Idle etc. For example i just want to get the Idle value, and store it as Integer using c++, how would i do it? Please Help. What I tried right now is just getting the whole line i need using ifstream and getline()
std::ifstream filestat("/proc/stat");
std::string line;
std::getline(filestat,line);
and what i get is this.
cpu 349585 0 30513 875546 0 935 0 0 0 0
To clarify my question, for example i want to get the 875546 value and store it to an integer using c++. how would i do it? thank you
The format of stat is described in detail under the proc(5) manual page.
You can see it either by running the command man 5 proc from a Linux terminal or online.
The methods described above for parsing the stat file are fine for academic purposes, but a production grade parser should take extra precaution when using these methods.
If you need a production grade parser in C++ for files in /proc, you can check out pfs - A library for parsing the procfs. (Disclaimer: I'm the author of the library)
The biggest issue is usually the comm field (The second field in the file).
According to the man pages, this field is a string that should be "scanned" using some scanf flavor and the formatter %s. But that is wrong!
The comm field is controlled by the application (Can be set using prctl(PR_SET_NAME, ...)) and can easily include spaces or brackets, easily causing 99% of the parsers out there to fail.
And a simple change like that won't just return a bad comm value, it will screw up with all the values that come after it.
The right way to parse the file are one of the following:
Option #1:
Read the entire content of the file
Find the first occurrence of '('
Find the last occurrence of ')'
Assign to comm the string between those indices
Parse the rest of the file after the last occurrence of ')'
Option #2:
Read the PID (the first value in the file)
Read 18 bytes (16 is the largest comm value + 2 for the wrapping brackets)
Extract the comm value from that buffer just like we did for option #1
Find out the actual length of the value, fix your stream and continue reading from there
You really need to study up on how file input works. This should be simple enough. You just need to ignore the first 3 characters "cpu" and then read through 4 integer values:
unsigned n;
if(std::ifstream("/proc/stat").ignore(3) >> n >> n >> n >> n)
{
// use n here...
std::cout << n << '\n';
}
Alternatively if you already have the line (maybe you are reading the file one line at a time) you can use std::istringstream to turn the line into a new input stream:
std::ifstream filestat("/proc/stat");
std::string line;
std::getline(filestat, line);
unsigned n;
if(std::istringstream(line).ignore(3) >> n >> n >> n >> n)
{
// use n here...
std::cout << n << '\n';
}
There are several ways to the problem. You can use regular expression library to get the part of the string or if you know this is always going to the 5th element then you can use this:
std::string text = "cpu 349585 0 30513 875546 0 935 0 0 0 0";
std::istringstream iss(text);
std::vector<std::string> results(std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>());
int data = std::stoi( results[4] ); //check size before accessing
std::cout << data << std::endl;
I hope it helps.

C++: How can I perform an operation on every number inside a text file?

If I have a text file which only has numbers inside. Such as:
1
2
3
4
5
6
How can I, for example, multiply each number by two and get the result of each individual operation as output to my screen? Would I have to set each number to a variable?
The best solution to your problem is to follow these steps:
Open a file, and create an int variable ( for instance a)
In Do...while loop take number from a file like this
Filehandler >> a;
multiply the a like this
a = a * 2;
or do whatever you want with it.
Print an value
cout << a;
till you get EOF
Of course there is another possibility like storing each value in array and then multiplying it. It depends on you what you will choose.
Do you know for Loops for example.
you can read the the numbers and store them in an array and use a for loop to multiply or div or whatever and print that .

Using stringstream to indent/center output

I'm learning c++ and got the project to send a pascal's triangle to output (after n-rows of calculation)., getting output like this, stored in a stringstream "buffer"
1
1 1
1 2 1
1 3 3 1
But what I want is rather
1
1 1
1 2 1
1 3 3 1
My idea was: calculate the difference of the last line and current line length (I know that the last one is the longest). Then pad each row using spaces (half of the line-length-difference).
My Problem now is:
I didn't get how getLine works, neither how I might extract a specific (-> last) line
I don't know and could not find how to edit one specific line in a stringstream
Somehow I got the feeling that I'm not on the best way using stringstream.
So this is rather a common question: How'd you solve this problem and if possible with stringstreams - how?
To know the indentation of the first line, you would need to know the number of lines in the input. Therefore you must first read in all of the input. I chose to use a vector to store the values for the convenience of the .size() member function which will give the total number of lines after reading in all input.
#include<iostream>
#include<sstream>
#include<vector>
#include<iomanip> // For setw
using namespace std;
int main()
{
stringstream ss;
vector<string> lines;
string s;
//Read all of the lines into a vector
while(getline(cin,s))
lines.push_back(s);
// setw() - sets the width of the line being output
// right - specifies that the output should be right justified
for(int i=0,sz=lines.size();i<sz;++i)
ss << setw((sz - i) + lines[i].length()) << right << lines[i] << endl;
cout << ss.str();
return 0;
}
In this example, I am using setw to set the width of the line to be right justified. The padding on the left side of the string is given by (sz - i) where sz is the total number of lines and i is the current line. Therefore every subsequent line has 1 less space on the left hand side.
Next I need to add in the original size of the line (lines[i].length()), otherwise the line will not contain a large enough space for the resulting string to have the correct padding on the left hand side.
setw((sz - i) + lines[i].length())
Hope this helps!
If you have access to the code that writes the initial output, and if you know the number of lines N you are writing, you could simply do:
for(int i = 0; i < N; ++i) {
for(int j = 0; j < N - 1 - i; ++j)
sstr << " "; // write N - 1 - i spaces, no spaces for i == N.
// now write your numbers the way you currently do
}

Getting input from external files?

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 ..