how to read characters and integers from a file? - c++

So I have a data file that looks something like this:
x + y + z
30 45 50
10 20 30
The only characters I needed was the operators, so '+' '+' I was able to use file.get() to successfully get those characters and put them in an array. Problem is I need to get the next line of numbers, and assign them to the values x , y z . I know I cant use .get() , I would have to use getline. Will i have to eliminate the file.get() and use getline instead for first part also?
I looked at some of the questions posted on here but none of them were quite like mines. Note I'm actually going to be using these values for another part of my program, just used cout to see if my values were being read correctly
Here's my previous code:
main(int argc, char *argv[])
{
int a=0;
int n;
fstream datafile;
char ch;
pid_t pid;
int a, b, c, result;
string line;
datafile.open("data1.txt");
if(datafile)
{
for(int i=0; i <9; i++)
{
datafile.get(ch);
if (ch == '*'||ch == '/'||ch == '+'||ch == '-')
{
operations[a] = ch;
cout<<operations[a];
a++;
}
}
}
else
cout<<"Error reading file";
}
So this is how I was getting the first line of the file in the beginning. It worked like I wanted it to, may have not been the nicest coding but it worked. Nevertheless I tried to get the rest of the file, this time using getline, but instead of getting the numbers I was getting a bunch of random gibberish/numbers. I know if I use getline, the first line cannot be in my loop. I know this is how I would get the numbers.
while(getline(datafile, line))
{
istringstream ss(line);
ss >> x >> y >> z;
cout<<x<<""<<y<<""<<z;
}

Would the following make sense for the first line, or am I missing something:
string input;
std::getline(datafile, input)
for (int i = 0; i < input.size(); i++)
if (input[i] == '+' || ...)
{
operations[a] = input[i];
a++;
}
If you don't want to use getline, you could simply read the entire file stream (note that the bool is a rather naive way to handle the problem, I'd recommend something more elegant in your actual code):
bool first = true;
string nums;
int lines = 0;
vector<vector<int>> numlines;
vector<int> topush;
while (!datafile.eof())
{
char ch = datafile.get()
if (ch == 12 && first) //I don't know if '\n' is valid, I'd assume it is but here's the sure bet
first = false;
else if (first && (ch == '+' || ...))
{
operator[a] = ch;
a++;
}
else if (!first && (ch >= '0' && ch <= '9'))
{
if (!(datafile.peek() >= '0' && datafile.peek() <= '0'))
{
numlines[lines].push_back(atoi(nums.c_str());
nums.clear();
if (datafile.peek() == 12)
{
numlines.push_back(topush);
lines++;
}
}
else
nums = nums + ch;
}
Honestly, I can't be sure the above will work exactly right, I'd recommend you just modify your code to use getline exclusively. You'll need to add #include to get atoi.

Add this to your code:
while(!datafile.eof()){
string s;
getline(datafile, s);
istringstream in(s);
string tmp;
while(in >> tmp){
int i = stoi(tmp)
//Do something with i....
}
}

Related

I want to write a c++ program in which I have a file and I want to see how many times the word "good" appears in the file. Why does this not work

So this is what I have tried doing. This is also the logic I mostly use to do word searching codes. I am basically seeing if I can find the character "g" and then I look if there are letters matching with good. If they are matching then I do count++ to count it and in the end I output my results:-
#include<iostream> //headers
#include<fstream>
using namespace std;
int main()
{
char arr[10000];
//declaration
fstream fileis;
fileis.open("fileis.txt",ios::in);
while (!fileis.eof( ))
{ //reading loop
fileis>>arr;
cout<<arr<<endl;
}
int count=0;
for(int i=0; arr[i] != '\0'; i++) //main loop
{
if(arr[i] == 'g' && arr[i+1] == 'o' && arr[i+2] == 'o' && arr[i+3] == 'd') //condition to check if the word is there
{
count++;
}
}
fileis.close();
cout<<"The word good appeared "<<count<<" times."<<endl;
return 0;
}
Here's my suggestion:
std::string word;
count = 0;
//...
while (fileis >> word)
{
// Convert word to all lower case for easy comparison.
std::transform(word.begin(), word.end(), word.begin(), tolower);
if (word == "good") ++count;
}
The above code fragment has some issues for the OP to find (such as what happens when a punctuation character is read in after "good").
By default reading a string from a stream reads in a "word", whitespace separated.

Inputting a relationship array

I am trying to input an binary array which represents a relationship. As an example, the array:
001
000
100
would output (0,2),(2,0)
To do this I'm trying to grab characters one at a time from input, and then change counters based on encountering a newline.
Here is my code so far.
char inChar;
int x = 0;
int y = 0;
while (inChar = ins.get() != '$') {
//$ is used to terminate input
vector <int> orderedPair;
if(inChar == '\n') {
y++;
x=0;
} else {
x++;
}
cout << inChar;
int isPair = inChar - '0';
if(isPair == 1){
orderedPair.push_back(x);
orderedPair.push_back(y);
pointsList.push_back(orderedPair);
orderedPair.clear();
}
}
However, that cout line just outputs... smiley faces? No matter what I enter, I just get smiley faces. I'm lost here. I've looked for any accidentally assignment, and I thought it might be an issue with my typecasting but that is later.
inChar = ins.get() != '$' means inChar = (ins.get() != '$') and whether the character read is equal to '$' or not will be stored to inChar instead of the character itself. You can use (inChar = ins.get()) != '$' to save the input with checking if the input is '$'.
Also note that orderedPair will be cleared on each iteration because it is declared as local variable of the block, so you won't need orderedPair.clear();.

Assertion Error using a struct vector c++

I have a program where I want to update a variable from a string. The function will read in a string, find if it is addition, subtraction, etc. and then add it to the variable. The function is this:
using namespace std;
struct variable{
string name;
int value;
};
void update_varabile(string line, vector<variable> & v)
{
char c = line[0]; //variable to be updated
string b;
char d[0];
int flag = 0; //counter
int a = 0;
int temp_value = 0;
int perm_value = 0;
for (int i = 0; i < v.size(); i++) {
if (c == v[i].name[0]) {
flag = 1;
temp_value = v[i].value;
break;
}
}
if (flag == 1) { //variable is present
for (int i = 0; i< line.size(); i++) {
if (line[i] == '+'|| line[i] =='-'|| line[i] == '*'|| line[i] =='/') {
b[0] = line[i+1]; //assuming the integer is between 0 and 9
d[0] = b[0];
a = atoi (d);
if (line [i] == '+') {
perm_value = temp_value + a;
} else if (line [i] == '-') {
perm_value = temp_value - a;
} else if (line [i] == '*') {
perm_value = temp_value * a;
} else if (line [i] == '/') {
perm_value = temp_value / a;
}
}
}
for (int i = 0; i < v.size(); i++) {
if (v[i].name[0] == 'c') {
v[i].value = perm_value;
break;
}
}
}
}
The call in main looks like this:
int main()
{
variable a;
int val = 0;
string up = "c=c+2";
string f = "c";
vector<variable> q;
a.name = f;
a.value = val;
q.push_back(a);
update_varabile(up, q);
return 0;
}
However, when I run the code, I get this error message:
Assertion failed: ((m_->valid == LIFE_MUTEX) && (m_->busy > 0)), file C:/crossdev/src/winpthreads-git20141130/src/mutex.c, line 57
Process returned 1 (0x1) execution time : 0.014 s
Press any key to continue.
I have run the debugger line by line and it shows that the function properly executes. I have also tried to look for that C:/ file on my computer and it doesn't exist. Not sure why this isn't working.
First thing first, get rid of all the breaks. Only place breaks should be used in C++ is at the end of each case statement. Makes near impossible to read code with a bunch of breaks, because I have to go down and figure out what each break is there and why. If you need to get out of a for loop early, then use a while loop. you don't need breaks at the end of if and else statements because they cause the program to leave a function early, your if and else statements will naturally skip over if you are using if, else if, and else condition formatting.
Now having said that, you need to break down better what you are trying to do.
example you get a string value like this.
2+3+4-5+6
Your program is going to read from left to right. I am assuming you want it to take the first value which is two and then add three to it then four and so on and so fourth.
The way to do this is first parse the string for int values and then parse the addition and subtraction values. In other words read the int values out of the string untill you hit a value that is not between 0 and 9. Then see if that non-numerical value is an operator you are looking for. This way your program wont trip up on a value like 2555 and 2.
IE
//intValueHolder is a string.
while(i < line.size() && line[i] >= '0' && line[i] <= '9' ) {
intValueHolder.push_back(string[i]);
}
Then when you hit a '+' or something like that put the char value through a case statements. and don't forget to add a default value at the end to account for garbage input like 'a'. You may want to hold the value just incase you need to get your left side value first before you can get your right side value. But it sounded like you start out with a left side value so you really only need to find right and which operator it needs. I'm not going to rewrite your program because this looks like an assignment for school. But I will point you in the right direction. Let me know, if I was off on understanding your question.
You may also want to look into using queues for this, if you are not being restricted to just strings and vectors.

Extraction operator causing my program to exit?

I'm a usual lurker but this is my first post! I understand you guys like detail so I will do my best. I will appreciate whatever input anyone has.
I am working on an overloading the extraction operator for an object with a dynamic array of digits. The console input will have leading white space, then an int, then anything after. I need to ignore white space, extract the int, and then leave the rest alone. Easy right?
Here is an example of code I found online:
istream & operator >> (istream &m, MyInt & p)
{
int x = 0;
p.currentLength = 0;
while ((m.peek() == '\n') || (m.peek() == '\0') ||
(m.peek() == '\t') || (m.peek() == ' '))
{
m.get();
}
while ((m.peek() >= '0') && (m.peek() <= '9'))
{
if (p.currentLength >= p.maxSize)
{
p.grow();
}
m >> p.theNumber[x];
x++;
p.currentLength++;
}
m.get();
// reverse the order (i.e. - 123 to 321)
char * temp = new char[p.maxSize];
for (int y = 0; y < p.currentLength; y++)
{
temp[y] = p.theNumber[p.currentLength - 1 - y];
}
delete [] p.theNumber;
p.theNumber = temp;
return m;
}
Now, I understand this method may work, however to me, that seems like an extremmeelly inefficient method. For a trillion digit number, Grow() would reallocate the array a trillion times! Perhaps this is not as bad as I think it is?
My current method has been using seekg() and peek() and get(). Like so:
istream& operator >> (istream& is, MyInt& z)
{
int i = 0, j = 0;
// check if next char is white
while (is.peek() == 38)
{
j++;
is.seekg(j); // skip if white
}
while (isdigit(is.peek()))
{
i++;
is.seekg(j + i);
if (!is.peek())
{
is.clear();
break;
}
}
is.seekg(j);
z.length = i;
z.digits = new int[i + 1];
for (i = 0; i < z.length; i++)
{
z.digits[i] = C2I(is.get());
}
return is;
}
Also, here is my main:
int main()
{
MyInt B;
cout << "\n\nChange B to what num? ---> ";
cin >> B;
cout << "B is now: " << B;
char c;
cout << "\n\n\n\n\nEnter char to exit : ";
cin >> c;
return 0;
}
For the life of me I can not find what is causing my program to exit. The last output seems to say, 'B is now: -1'
I believe the this means the << B failed. I have B initialized to 0 currently, and the rest of my code has presented no other issues. It's private member data only include the pointer and a length (num of digits). Also C2I() is a function that converts '0' through '9' to 0 through 9.
A big issue for me is I am fairly new to parsing, so I don't have very eloquent ways to test this, or other ideas.
Again I appreciate everything you guys do. I have already learned a great deal from browsing here!

c++ parse string using multiple delimiters using inbuilt c/c++

I am trying to parse a string that looks like "1,4-6,8-10,12" and push_back the results into a vector of ints/char*. While parsing, if the logic comes across 4-6 then it should push the ints 4,5 and 6 in the vector. I am trying to do this using strtok but it modifies the only copy of the input string so I am not getting anywhere. I cannot use boost or else tokenizer would have been very easy and useful.
#include <stlport\sstream>
#include <stlport\vector>
using namespace std;
...
stringstream ss("1,4-6,8-10,12");
vector<int> v;
int x, x2;
char c;
while (ss >> x)
{
v.push_back(x);
if (!(ss >> c))
break; // end of input string
if (c == '-')
{
if (!(ss >> x2))
throw; // incorrect input string
for (int i = x+1; i <= x2; i++)
v.push_back(i);
if (!(ss >> c))
break; // end of input string
}
else if (c != ',')
throw; // incorrect input string
}
// check
int s = v.size();
// s = 8, v:{1,4,5,6,8,9,10,12}
std::stringstream ss("1,4-6,8-10,12");
std::vector<int> v;
int x;
while(ss >> x)
{
v.push_back(x);
char c;
ss >> c; //will just discard a non space char.
if(c != ',' || c != '-') ss.unget(); //... unless is just , or -
}
Time to write this: 1 minute.
Time to search for an appropriate algorithm function: 5 minutes at least.
Decide yourself what's more productive.