CPP program consuming so much Ram - c++

One of my simple CPP file is taking so much f memory . Any suggestions? I use a macbook air 2017 model for coding
The code is :
#include <iostream>
#include <vector>
using namespace std;
int main()
{
std::vector<int> v;
int x = 0, y, i;
while (1) {
cin >> x;
if (x == 42) {
break;
}
v.push_back(x);
}
for (auto it = v.begin(); it != v.end(); it++) {
if (*it < 42) {
cout << *it << endl;
}
}
return 0;
}
Here's what I get inside the activity monitor

Apparently input file has invalid contents and you do not handle errors well.
Scenario 1:
Input has something what can't be read as int.
1 2 2.0 42 2
Here when 2.0 trying to read int wyo will get value 2. In next iteration attempt to read .0 will fail. std::cin is set to error state and any other read attempts are ignored.
Scenario 2:
Input do not contain termination value 42:
1 2 3 44 55 10
In this case you reach end of file std::cin is set to error state and any other read attempts are ignored.
In both cases x is never set to value 42 and you have infinitive loop which inserts last successful value read as log there is enough memory. When memory is consumed program terminates with std::bad_alloc exception.
To fix it just handle input errors.

Related

Why splitting a line separated by spaces with stream in C++ runs infinitely?

Before, when I was writing C++, I often used getch() for validation. However, now I am turning into competitive programming, I cannot use getch(); I had to use cin or getline. Thus, today, I replicated an instance of splitting a string using stringstream:
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main() {
string line;
getline(cin, line);
cout << line << endl;
stringstream reader;
reader.clear();
reader.str(line);
vector<long long int> list;
while (true) {
reader.clear();
if (reader.str().size() == 0) {
break;
}
long long int value;
reader >> value;
list.push_back(value);
}
}
Then, I ran the program, typed 1 2 3 4 5 6 7 8 9 and pressed enter. The program successfully displayed line, 1 2 3 4 5 6 7 8 9, but the program just didn't terminate. It never approached the end of the main() function. I tried to print reader.str(), but it just print 1 2 3 4 5 6 7 8 9 continually. I was confused. Why reader >> value didn't run and did not read any value? Why was the program running an infinite loop? How can I fix the issue? I appreciate any solution.
The reading operator >> does not change the underlying string. It uses an inner position of a next char to read.
int main() {
int n;
std::istringstream in; // could also use in("1 2")
in.str("1 2");
in >> n;
std::cout << "after reading the first int from \"1 2\", the int is "
<< n << ", str() = \"" << in.str() << "\"\n";
}
Outputs
after reading the first int from "1 2", the int is 1, str() = "1 2"
The loop may be terminated by replacing reader >> value; with
if (!(reader >> value))
break;
... but the program just didn't terminate.
This means that ...
while (true)
true is never false, or ...
reader.str().size() == 0
is never true.
true, in fact, is never false, and you never change the size of the reader's string object. Why would you expect this loop to break?
Please edit your question to make it more clear what you are trying to accomplish.

Segmentation fault when reading text file

I am trying to run a code sorting the ages of Titanic survivors from a text file. It compiles fine, but the program terminates simply saying "segmentation fault" when I choose option B (option A is not written yet.)
Here is a small sample of the text file for reference.
29 1stClass TRUE
0.9 1stClass TRUE
2 1stClass FALSE
30 1stClass FALSE
I've isolated the error to the chunk where the file is processed (//actual processing), but I'm not sure what exactly is wrong.
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <fstream>
#include <ctype.h>
void sortSurvivors();
void sortAgesLiving();
int main()
{
char options;
std::cout << "Titanic Data \nOptions \nA) Display count of people who lived and died... \nB) Display count of people who lived by age... \nPlease select option (A-B)...";
std::cin >> options;
switch (options)
{
case 'A':
sortSurvivors();
break;
case 'B':
sortAgesLiving();
break;
}
}
void sortSurvivors()
{
}
void sortAgesLiving()
{
std::ifstream inputFile;
std::string filename = "TitanicData.txt";
std::string age;
std::string classBoat;
std::string survival;
bool survived;
int eldest = 0;
//pre-sort processing
while (inputFile >> age >> classBoat >> survival)
{
int ageConv = stoi(age);
//G is for the ghetto fix I am pulling here, because I recieve an error when using "TRUE" as a string
char gchar = 'G';
survival += gchar;
if (survival == "TRUEG")
{
survived = true;
}
else
{
survived = false;
}
if (eldest < ageConv)
{
eldest = ageConv;
}
}
//initialize vector
std::vector<int> survivorVector;
for (int i = 0; i < eldest; i++)
{
survivorVector.push_back(0);
}
inputFile.open(filename);
//actual processing (ERROR HERE)
if (inputFile)
{
while (inputFile >> age >> classBoat >> survival)
{
int ageConv = stoi(age);
if (survived = true)
{
survivorVector[ageConv] = survivorVector[ageConv] + 1;
}
for (int j = 0; j <= eldest; j++)
{
std::cout << j << "\t" << survivorVector[j] << "\n";
}
}
// Close the file.
inputFile.close();
}
else
{
std::cout << "I don't know what broke, but uhhhhhhhhhh oops.";
}
}
As per usual I'm sure it's something dumb I overlooked.
In sortAgesLiving(), you have forgotten to open the file before starting your pre-sort processing. As a consequence, your first reading loop will fail to read anything at all. Therefore eldest will stay 0.
You then construct a vector and populate it. But since the loop is based on eldest, the vector survivorVector will stay empty.
When you finally open the file and read it, the first line will be considered as a survivor since you accidentally overwrite the boolean with true (i.e. if (survived = true) instead of if (survived == true) or simply if (survived). You'll then try to access the vector out of bounds.
Even if you correct this error, at the first survivor you'll get again out of bounds. Accessing a vector out of bounds is UB and one of the many possible symptoms can be segmentation fault.
Miscellaneous advices (not related to your issues):
You have an ambiguous age of 0.9. Converting it to an int will cause it to be 0. Is this ok, or do you need to round this up?
If it's rounding up, you could make the age variable a double and read it directly without conversion. You could then convert it mathematically to an integer age rounding it up or truncating it, as needed. If you're sure to have only integers, you could make the variable an int and not worry at all.
It is unsafe to trust a value in a file to directly index a vector. What if between the two reading phases, an additional line would have been added by someone else to the file with a value higher than eldest ? What if the value read would be negative? Better always check that it's in an acceptable range before using a value as an index. It can save you hours of debugging and your customers some nightmares.
Finally, the two-phase read is not necessary: you could just read the age, and after having checked that it's positive and smaller than 150 years (quite optimistic), you could, if needed, resize your vector if the age is equal or larger than the current vector size. Why? Imagine you work one day for US census with files having millions of lines: the fewer passes over the file, the better ;-)

Second cin is either skipped or does not work properly

I have a couple of problems, that I think are closely connected, but I couldn't get them fixed following what I previously found on the website.
My problems are related to the double use of cin in my main function. I need to read numbers from keyboard in order to either build small vectors or store single coefficients. I cannot know in advance the length of the vectors that I am going to build.
Here are the lines involved:
#include <vector>
#include <iostream>
#include <limits>
int main() {
...
double a=0;
std::vector<double> coefficients;
while (std::cin>>a) {
coefficients.push_back(a);
}
...
std::vector<double> interval;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max());
while(std::cin>>a) {
interval.push_back(a);
}
std::cout<<interval.size()<<std::endl;
std::cout<<*interval.cbegin()<<" "<<*(interval.cend()-1)<<std::endl;
...
}
I am using both macOS with g++ 6.3.0 and Linux with g++ 5.3.0. The flags I send to the compiler are -Wall -std=c++14 -o.
On the macOS machine the second cin is completely skipped, while on the Linux one the second reading process does not behave like it is expected to. I mean that if i give -1 1 at the second cin, the printed vector size is 0 and, obviously, the program stops because of a segmentation fault.
At each cin I enter the requested numbers in a single line, like 1 0 0 1, then press enter and then ctrl+D.
Thanks in advance to all! :)
Your call of std::cin.ignore(...) set the fail bit of the stream. This makes it impossible to enter the loop. You need to move the std::cin.clear() call right before the loop, in order to make it run. Also you have an out-of-bound read when there are no data in the second container.
#include <vector>
#include <iostream>
#include <limits>
#include <string>
int main() {
double a=0;
std::vector<double> coefficients;
while (std::cin>>a) {
coefficients.push_back(a);
}
std::cout << coefficients.size() << '\n';
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'X');
std::cin.clear();
char c;
std::cin>>c;
if(c != 'X')
{
std::cerr << "Invalid separator\n";
return 1;
}
std::vector<double> interval;
while(std::cin >> a) {
interval.push_back(a);
}
std::cout<< interval.size()<<std::endl;
if(interval.size())
std::cout<<*interval.cbegin()<<" "<<*(interval.cend()-1)<<std::endl;
return 0;
}
With the following data file,
$ cat data.txt
12 23
42
X
1 2
3 4 5
this output is generated:
$ ./a.out < data
3
5
1 5
You need to add a linefeed '\n' as a second parameter to cin.ignore() so it kills the ignore on an enter press

Read a sequence of ints from cin and store them in a vector

This is what I have done to read integers with std::cin and store them in a vector:
int number;
vector<int>ivec;
while (cin>>number)
{
ivec.push_back(number);
}
for (auto v: ivec){
cout << v;
}
Then, I am stuck with the problem that how to stop entering integers and move to the next process of printing the vector out. Any pointer will be appreciated.
It depends on the terminal in use and the precise mechanism varies quite a lot but, conventionally, typing Ctrl+D (Linux) or Ctrl+Z (Windows) will result in an end-of-file "signal" being transmitted along the pipe, causing the EOF bit to be set on cin, and thus the next cin >> number attempt to fail.
That will break the loop.
Conveniently, the same will happen if you ran your executable with redirected input from a file. Which is kind of the point.
The code you posted reads numbers from cin as long as it succeeds. There are two ways to have it stop succeeding: If you enter something that is not a number, reading data still succeeds, but converting it to number fails. This puts cin into the bad state. It can be recovered from using the clear methode. The other way is making the reading of characters from cin fail (for example the end of a file that gets used as input). This puts cin into the failed state. Usually, recovering from a failed state is impossible.
To produce the you can no longer read state at end of file when entering data at the keyboard, operating system specific methods have to be used (likely Control-D or Control-Z). This is final for the invocation of your program.
If you need a way for the user to signal: "Please go on, but let me enter other stuff later", the most clean way is likely reading cin line-by-line and parse the input using strtol or a stringstream, and comparing for a magic stop-token (e.g. empty line, "end") to exit the loop.
You can do it the following way
#include <vector>
#include <iterator>
//...
vector<int> ivec( std::istream_iterator<int>( std::cin ),
std::istream_iterator<int>() );
for ( auto v: ivec ) std::cout << v << ' ';
std::cout << std::endl;
In Windows you have to press key combination Ctrl + z and in UNIX system Ctrl + d
Or you can introduce a sentinel. In this case the loop can look like
int number;
const int sentinel = SOME_VALUE;
for ( std::cin >> number && number != sentinel ) vec.push_back( number );
Please find a simple solution to your problem, let me know if you see any issue with this solution.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> va;
int x;
while ( cin >> x ) {
va.push_back(x);
if ( cin.get() == '\n' ) break;
}
//Vector output
for ( int i = 0; i < va.size(); i++ ) {
cout << va[i] <<" ";
}
return 0;
}

C++ reading from file function failing to exit while cycle [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
End of File in C++
I wrote a function to read data from a .txt file, but when I call it, it keeps crashing.
Here's the code:
void beolvas(vector<int> &charge, vector<int> &deliver, vector<Robot*> &robots) {
string s;
ifstream f;
do {
cout << "Add meg a filenevet" << endl;
cin >> s;
f.open(s.c_str());
} while (!f.good());
cout << "adatok beolvasasa..." << endl;
int napok;
if (!(f >> napok)) throw 1;
charge.resize(napok);
deliver.resize(napok);
for (int i = 0; i<napok; i++) {
if (!(f>>charge[i])) throw 1;
if (!(f>>deliver[i])) throw 1;
}
string type, name;
int battery;
while (!f.eof()) {
cout << " a ";
if (f>>type && f>>name && f>>battery) {
if (type=="Mac") {
Mac r = Mac(name,battery);
robots.push_back(&r);
};
if (type=="Eco") {
Eco r = Eco(name,battery);
robots.push_back(&r);
};
if (type=="Pro") {
Pro r = Pro(name,battery);
robots.push_back(&r);
};
};
};
}
It seems the problem occurs in the while loop. If I want to read from a 3 row long text, I get 4 letter a-s on the screen (I have the program print one before reading every row).
Is f.eof() not the function I need to use here?
This is one of the most common problems with reading from files. Checking f.eof() will only tell if you the previous read hit the end of the file. Hence, after the last successful read (where you got your third "a" printed), eof() returns false and your loop executes one more time, outputting an extra "a".
Instead, use your extraction line as the condition for your while loop:
while (f>>type && f>>name && f>>battery) {
if (type=="Mac") {
Mac r = Mac(name,battery);
robots.push_back(&r);
}
if (type=="Eco") {
Eco r = Eco(name,battery);
robots.push_back(&r);
}
if (type=="Pro") {
Pro r = Pro(name,battery);
robots.push_back(&r);
}
}
This works because as soon as one of your extractions hits the end of the file, the while condition will be false and the loop won't execute.
If you want to continue after badly formatted lines, I recommend that you use std::getline instead:
std::string line;
while (std::getline(f, line)) {
std::stringstream ss(line);
if (ss >> type && ss >> name && ss >> battery) {
// ...
}
}
The reason for using this std::getline approach is because you would have had a problem if half of a line had been correctly formatted. Your approach would have read in perhaps type and name then failed on battery and the next iteration of the loop would have started from the same place.
You're also going to have a problem with the fact you're pushing pointers to objects that have automatic storage duration into some vectors. When the block in which the objects are created ends, the pointers will be pointing to an invalid object.
This is a FAQ. In C/C++, the end-of-file condition is triggered only after you have tried to read past the end. So, you can't assume from feof() == false that input is available (because you could be exactly at the end of the file, but not yet past it). You should always test for valid input after a read operation.