Extraction operator causing my program to exit? - c++

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!

Related

What is wrong with my program to find the longest word in a sentence?

#include <iostream>
using namespace std;
int main() {
char a[101]{0};
cin>>a;
cin.getline(a,101);
cin.ignore();
int currLen{0};
int maxLen{0};
int startInd{-1};
int endInd{-1};
for(int i=0; i<101; i++) {
if(a[i]!=' ' ) {
++currLen;
} else if(a[i]==' '||a[i]=='\0') {
if(currLen>maxLen) {
maxLen=currLen;
startInd=i-currLen;
endInd=i-1;
}
if(a[i]=='\0')
break;
currLen=0;
}
}
cout<<maxLen<<endl;
if(startInd==-1)
cout<<-1;
else
for(int i=startInd; i<=endInd; i++)
cout<<a[i];
return 0;
}
If I take an input here, for example, "My name is Manav Kampani"
It will output 5
Manav instead of 7
Kampani
But if I write "My name is Manav Kampani ", with space after the last word
than it is considering Kampani too printing Kampani.
Also when I input "Kampani Manav is my name" then too it's displaying the wrong output. That means it is not considering the first word of the sentence.
if(a[i]!=' ' )
{
++currLen;
}
else if(a[i]==' '||a[i]=='\0')
{
....
}
Consider the case of a[i] == 0. Which of these if-statements will apply.
Answer: the first one. Which means you'll never look at the final word in the string. You also don't exit at the end of the string, but instead loop through whatever is in your string all the way out to character 101.
As a general structure, be very, very careful with this:
if (condition)
else if (condition)
// without a final else section
If you do that, you need to think about what you're doing. In this particular case, you can have:
if (a[i] != 0 && a[i] != ' ')
else
It may not solve all your issues, but it should solve some.
A nice sliding window pattern implementation.
You have 3 problems in your code
You must not write cin >> a;
You must not write cin.ignore();
You need to modify your if statement like so: if (a[i] != ' ' && a[i] != '\0') Otherwise you will not detect the last word.
Your complete working code with that minor fixes will lokk like that.
int main()
{
char a[101]{ 0 };
//cin >> a;
cin.getline(a, 101);
//cin.ignore();
int currLen{ 0 };
int maxLen{ 0 };
int startInd{ -1 };
int endInd{ -1 };
for (int i = 0; i < 101; i++)
{
if (a[i] != ' ' && a[i] != '\0')// Add comparison
{
++currLen;
}
else if (a[i] == ' ' || a[i] == '\0')
{
if (currLen > maxLen)
{
maxLen = currLen;
startInd = i - currLen;
endInd = i - 1;
}
if (a[i] == '\0')
break;
currLen = 0;
}
}
cout << maxLen << endl;
if (startInd == -1)
cout << -1;
else
for (int i = startInd; i <= endInd; i++)
cout << a[i];
return 0;
}
Additionally. You should not use C-Style arrays in C++. And please use std::string
There is a couple of things here:
1- You don't need to do a cin>>a this is actually consuming the first word, and afterwards the content is overrided by cin.getline(). So removing the firsst cin>>ayou'll be fine.
2- The last word is not read because there isn't any if condition that matches the condition aka.
if(a[i]!=' ' ) case of not a space
//not end of word
else if(a[i]==' '||a[i]=='\0') case of space or null
//end of word
So your last character is not a space nor null, that means you don't detect the last word.

how to calculate polynomial (x^2^2^2^2+x^2^2^2)

I want to calculate (x^2^2^2^2+x^2^2^2) result should be [x^256+x^16]..but i am unable to do this completely..i also have written a code which is working for first half(before '+') but in other half it fails to do it...
#include<iostream>
#include<string>
#include <algorithm>
#include<sstream>
using namespace std;
int main()
{
string a;
cin >> a;
string s1 = "^";
string::size_type foud;
foud = a.find(s1);
int i = foud;
int flag = 0;
i++;
while (foud != std::string::npos)
{
flag = 0;
cout << i <<"I"<< endl;
while (flag != 1 && i < a.length())
{
if (a[i] == '(' || a[i] == '+' || a[i] == '-' || a[i] == ')')
{
flag++;
cout << "terminator" << endl;
}
else if (a[i] == '^')
{
/*int j = (int)(a[i - 1]);
j = j - 48;
int k = (int)(a[i + 1]);
k = k - 48;
i = k + 1;
int power =0;
power = pow(j, k);
;*/
int j = i;
int k = i;
k--;
j++;
string bcknumber;
while (a[k] != '^' && a[k] != '(' && a[k] != '+' && a[k] != '-' && a[k] != ')')
{
bcknumber = bcknumber + a[k];
k--;
}
cout << bcknumber << endl;
reverse(bcknumber.begin(), bcknumber.end());
cout << bcknumber << endl;
int BK;
BK = stoi(bcknumber);
int FD;
string frdnum;
while (a[j] != '^'&&a[j] != '\0' && a[j] != '(' && a[j] != '+' && a[j] != '-' && a[j] != ')')
{
frdnum = frdnum + a[j];
j++;
}
FD = stoi(frdnum);
int resil = pow(BK, FD);
frdnum.clear();
stringstream s;
string res;
s << resil;
res = s.str();
if (i == 15)
{
a.replace(14, 15, res);
}
else
{
a.replace(i - bcknumber.length(), i + frdnum.length(), res);
}
i--;
bcknumber.clear();
}
else
i++;
}
foud = a.find("^", foud + 1);
i = foud;
i++;
}
cout << a << endl;
system("pause");
}
This is not a trivial problem. You want to build an infix calculator (a + b). A prefix calculator (+ a b) or a postfix calculator (a b +) are simpler, since there are no ambiguities at all. An infix calculator can have a lot of them, depending on the degree of freedom you want the user to have.
In the problem you're exposing, one is tempted to say: well, if there is an operator next to the second operand, then I have to accumulate the last result and operate with that and the next operation. However, there are problems like precedence which will not be deal with with that approach.
I would start creating a prefix calculator. It is a lot easier:
calculate():
opr = match operator
op1 = match operand
if op1 is operator:
back
op1 = calculate
op2 = match operand
if op2 is operator:
back
op2 = calculate
return calc(opr, op1, op2)
Once you have mastered that, then there is the possibility to start with an infix calculator.
One thing to do in the last algorithm would be to change it to avoid recursion, for example.
This is a good exercise, enjoy it. Hope this helps.
This smells like homework/assignment so I will not provide code...
As I see it you want just string parser to string replacing the power part. I am assuming You still do not understand the power math or are wrongly writing/interpreting representation of the string. For example:
x^2^2^2^2 =
(((x^2)^2)^2)^2 =
(((x.x)^2)^2)^2 =
((x.x).(x.x))^2)^2 =
((x.x.x.x))^2)^2 =
((x.x.x.x).(x.x.x.x))^2 =
(x.x.x.x.x.x.x.x)^2 =
(x.x.x.x.x.x.x.x).(x.x.x.x.x.x.x.x) =
(x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x) =
x^16
And not yours x^256. You can not add parenteses where you want they must be placed according to order of math operations otherwise the resulting equation will not match the input string !!!. In case you got defined different parse rules for your parser then in standard math then you need to define them in the Question.
Now how to approach this:
read string
I would start with constant hard-coded string instead of typing it all the time while programing/debugin over and over (as many students do ... I saw few times people typing 5x5 matrix on each build :) ... which is insane)
When the program works only then use the cin reading... as you already do
detect which part of the string is power exponent
exponent=1
Search the string for first ^ and remember the start position i0 if not found goto #4.
Now depending on what follows:
If number multiply exponent by it.
If ^ skip it and goto to #2
if neither stop
Of coarse if you should support parentes then it will be much much more complicated and you need to decode the whole thing which is not trivial which you should also mention in the Question.
replace original exponent string with computed string (if computable)
so the computed string will be "^"<<exponent or "^"+exponent depends on what kind of string arithmetics you using ....
output string
with cout or whatever as you already do

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.

how to read characters and integers from a file?

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

C++ input operator overload ">>"

I have a rational number class is made up of two integers: num, the nominator, and den, the denominator.
The following operator is supposed to read the rational number from a stream.
istream& operator >> (istream& Is, rational& r) {
char c; //Test char.
double n; //Could be either the numerator of the fraction or the antiperiod of the repeating decimal number.
Is >> n;
int i = 0;
for (; n*10-pow(10, i+1) < 1 && int(n) != 0; i++) {
n *= 10;
}
for (; int(n*10) % 10; i++) {
n *= 10;
}
n /= pow(10, i);
if (i == 0) {
r.num = n;
Is >> ws;
c = Is.peek();
if (c == '/') {
c = Is.get();
Is >> r.den;
} else {
r.den = 1;
}
r.normalize(); //This function normalizes the fraction.
} else {
Is >> ws;
c = Is.peek();
if (c == 'p' || c == 'P') {
int p; //Period of the repeating decimal number.
c = Is.get();
Is >> p;
vector<int> a = genFrac(n, p); //This function returns the fraction which express the decimal repeating number. It returns a "vector<int>" with the nominator at index 1 e denominator at index 0.
r.num = a[1];
r.den = a[0];
} else {
i = 0;
for (; n*10-pow(10, i+1) < 1 && int(n) != 0; i++) {
n *= 10;
}
for (; int(n*10) % 10 != 0; i++) {
n *= 10;
}
int pot10 = pow(10, i);
r.num = n;
r.den = pot10;
}
r.normalize();
}
return Is;
}
I wrote this code to implement the input of my "rational" class.
I modified it from the one written in my C++ book in order to make possible the input of decimal numbers, including repeating ones.
It should be able to handle these types of input:
9/8
9
9.87
1.p3 (= 1.3333333333)
But it doesn't work, not even the part I copied from the book.
Can anyone help me?
I think I'd write this somewhat differently1.
Unless you really need to do otherwise, I'd start by reading an entire "chunk" of input (i.e., all the characters up to the next white space), then sort out how that's supposed to represent a number, and call a separate function for each possible representation:
std::istream &operator>>(std::istream &is, rational &r) {
std::string temp;
Is >> temp;
if (temp.find('/') != std::string::npos)
r = cvt_fraction(temp, Is);
else if (temp.find_first_of("pP") != std::string::npos)
r = cvt_repeating(temp, Is);
else if (temp.find('.') != std::string::npos)
r = cvt_float(temp, Is);
else
r = cvt_int(temp, Is);
return Is;
}
I've passed the istream to each for two reasons: first, so if they find garbage in the input, they can set the stream's fail bit. Second, so if they really do need to read more input, they can (but I'd be a little surprised if that's ever really needed).
It seems to me that each of those conversion functions should be fairly trivial: if I'm starting from the fact that a string should be digits "/" digits or `digits "p" digits", doing a conversion is generally going to be pretty simple -- specifically, simple enough that I think just about anybody can probably glance at the code and sort out what each piece is supposed to do.
I honestly don't mean to be nasty, but if I was maintaining code, and ran across your operator>>, I would have one of two possible reactions: if it apparently had a bug, replace it immediately. Otherwise, put it on the "technical debt" list, and replace it as soon as possible. The simple fact is that as it stands right now, it takes a fair amount of study to even be sure what input formats are supposed to be supported, not to mention which part of the code handles each, or how the whole thing is supposed to work together to produce a meaningful result.
The issue mentioned in the comment (the p not appearing in the c=is.peek() statement) comes from the fact that the p is actually stored in ws (it is stored there in is >> ws).
The above code also contains no mention of ws, but I assume it is a char.