Is integer overflow that evil? - c++

Consider the following code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n, k;
cin >> n >> k;
vector<int> a(n);
int sum = 0;
for (auto &it : a) {
cin >> it;
sum += it;
}
cout << sum << "\n";
for (int i = 0; i < n; i++) {
cout << a[i] << " ";
}
cout << endl;
}
Input like (or anything greater than INT_MAX into k)
5 1234567891564
1 2 3 4 5
makes the program print
0
0 0 0 0 0
What actually happens? We don't use the value of k at all.

There is actually no integer overflow in your code. Well in a wider sense it there is, but in a more narrow sense integer overflow would happen for example with:
int k = 1234567891564;
What actually happens is that in this line
cin >> n >> k;
operator>> tries to read a int but fails. 1234567891564 is never actually assigned to k. When reading the input fails 0 will be assigned. Hence k comes out as 0.
Once the stream is in an error state, all subsequent calls to operator>> will silently fail as well. You should always check the state of the stream after taking input. For example:
if (std::cin >> n) {
// input succeeded use the value
} else {
// input did not succeed.
std::cin.clear(); // reset all error flags
}

Related

Infinite loop when using exceptions in c++11

I would like to create a c++11 program that takes in 10 positive integers and gives the user the total. In the event of a negative number or a char input, the exception should be thrown and the user must re enter their value.
The program below works with negative numbers. However, when I enter a character like "a", the program goes into an infinite loop and I cannot figure out why.
Any and all help will be appreciated
#include <iostream>
int main(){
int array[10] = {0};
int total = 0;
for(int i =0; i < 10; i++){
std::cout<<"Number "<< i+1 << ": " <<std::endl;
std::cin >> array[i];
try{
if(array[i] < 0 || std::cin.fail())
throw(array[i]);
}
catch(int a){
std::cout<< a <<" is not a positive number! "<<std::endl;
i-=1; // to go back to the previous position in array
}
}
for(int k = 0; k < 10; k++)
total+=array[k];
std::cout<<"Total: " <<total<<std::endl;
}
If you get invalid input there are two things to thing you need to do:
Clear the stream status. This is done using the clear function.
Remove the invalid input from the buffer. This is usually done using the ignore function.
As for your program, you don't need exceptions here, just using unsigned integers and checking the status is enough:
unsigned int array[10] = { 0 };
...
if (!(std::cin >> array[i])
{
std::cout << "Please input only non-negative integers.\n";
// First clear the stream status
std::cin.clear();
// Then skip the bad input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Make sure the index isn't increased
--i;
}
To use exceptions similar to what you do now, the solution is almost exactly the same as above:
unsigned int array[10] = { 0 };
...
if (!(std::cin >> array[i])
{
throw i;
}
catch (int current_index)
{
std::cout << "The input for number " << current_index + 1 << " was incorrect.\n";
std::cout << "Please input only non-negative integers.\n";
// First clear the stream status
std::cin.clear();
// Then skip the bad input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Make sure the index isn't increased
--i;
}
Do not forget to include limits header file while using following line in your code :
std::cin.ignore(std::numeric_limits::max(), '\n');
because numeric_limits template is defined in this header file !

Floats breaking my code

I've written a program that returns the median value of a user-defined array. While I've put a few checks in my code (array size can not be negative) I keep running into one issue I simply can not fix (for clarity sake, assume strings and alphabetical characters will not be used).
All of my input values are int however the user could just as easily enter in a float. When they do this (either for size of array or entering in the element) it breaks my code. I've tried multiple things to try and catch this, but it seems like the way my program is getting the value doesn't allow for the catch in time.
#include <iostream>
using namespace std;
void sort(int * a,int n)
{
for(int i=0;i<n;++i)
for(int j=i+1;j<n;++j)
{
if(a[i]>a[j])
{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}\
}
return;
}
int main()
{
int n;
int check;
int x;
cout<<"Enter length of array:";
cin>>n;
if (n < 0){
while (n < 0){
cout << "Please enter a length greater than 0" << endl;
cin >> n;
}
} else if (n % 1 != 0){
while (n % 1 != 0){
cout << "Whole numbers only! Try again" << endl;
cin >> n;
}
}
if (n == 0){
cout <<"You try to enter numbers, but there's no place to put them." << endl;
cout << ":(";
return 0;
}
int a[n];
cout<<"Enter values one by one:\n";
for(int i=0;i<n;++i){
cin >> x;
a[i] = int(x);
}
sort(a,n);
if (n % 2 == 1){
cout<<"Median is:"<<a[n/2]<<endl;
}
else{
float z = (float(a[n/2]) + float(a[(n/2)-1])) / 2;
cout << "Median is:" << z << endl;
}
return 0;
}
First thing I tried was catching the float like so
`if (n % 1 !=0){
while(n % 1 !=0){
cout << "Enter a whole number"
cin >> n
}
}`
This still broke my program. The odd thing was that I entered a float and then printed the value of n and it only showed the int value.
I tried using typeid.n() with #include <typeinfo>and comparing that to an int type to check it was the correct value, but that slipped through as well.
I tried doing an int cast, something like int(n) immediately after number was stored in n but before it went into a[n] and yet again, it still broke my code.
How can I check against float user-input and loop them until they give me an int?
You're reading into an int:
int x;
...
cin >> x;
So it will read what it can, then stop at e.g. a . and leave the rest on the stream (like if the user enters "123.4" you'll get 123 and then ".4" won't be consumed from the input stream).
Instead, you could read into a float:
float x;
...
cin >> x;
And do the appropriate math.
Alternatively you could read into a string and parse it into a float. That way you won't get stuck at letters and such either.
And the final option is to read into an int but handle any errors and skip the bad input, which is detailed at How to handle wrong data type input so I won't reproduce it here.
Which option you choose really just depends on what you want the behavior of your program to be and how strictly you want to validate input (e.g. round vs. fail if "2.5" is entered but an integer is expected, how do you want to handle "xyz" as input, etc.).

C++ Segmentation Fault with no pointers (HackerRank)

I solved a problem in Hacker Rank.
Input Format. The first line of the input contains an integer N.The next line contains N space separated integers.The third line contains a single integer x,denoting the position of an element that should be removed from the vector.The fourth line contains two integers a and b denoting the range that should be erased from the vector inclusive of a and exclusive of b.
Output Format. Print the size of the vector in the first line and the elements of the vector after the two erase operations in the second line separated by space.
CODE:
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
int n = 0, x = 0, value = 0;
vector<int> vk, vm;
vk.reserve(100000);
string k, m;
cin >> n;
cin.ignore();
getline(cin, k);
cin >> x;
cin.ignore();
getline(cin, m);
stringstream sk(k);
while (sk >> value)
vk.push_back(value);
stringstream sm(m);
while (sm >> value)
vm.push_back(value);
vk.erase(vk.begin() + x-1);
vk.erase(vk.begin() + vm[0]-1, vk.begin() + vm[1]-1);
cout << vk.size() << endl;
for (int i = 0; i < vk.size(); i++)
cout << vk[i] << " ";
cout << endl;
return 0;
}
But with this test case produce a "Segmentation Fault":
6
1 4 6 2 8 9
2
2 4
Can you help me to review my code and provide some feedback on what is the problem?
EDIT
Thanks to #john for the answer. Here is how it looks without the seg fault:
#include <vector>
#include <iostream>
#include <string>
using namespace std;
int main() {
int n = 0, x = 0, y = 0, z = 0, value = 0;
vector<int> vk;
vk.reserve(100000);
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> value;
vk.push_back(value);
}
cin >> x >> y >> z;
vk.erase(vk.begin() + x-1);
vk.erase(vk.begin() + y-1, vk.begin() + z-1);
cout << vk.size() << endl;
for (int i = 0; i < vk.size(); i++)
cout << vk[i] << " ";
cout << endl;
return 0;
}
You're trying too hard with the your input code. It isn't correct because you seem to be assuming that cin.ignore() will skip the rest of the line, when it only skips the next character (which could be a space). I would guess this is the reason for the seg fault. You can tell how many numbers you have to read after you've read the first one. There is no need to use getline or stringsteam at all.
You don't need the vm vector. It will always contain two values, so just declare two variables. You could also pick much better names for all your variables.
cin >> n;
for (int i = 0; i < n; ++i)
{
cin >> value;
vk.push_back(value);
}
cin >> x >> vm0 >> vm1;

cin infinite loop when reading in a non-numeric value

I had a strange behavior in a program and I spent long time trying to deduce why. it was an infinite loop with no sense. Testing these lines of code(under suspicion) i got the same result. Every time I type in a non-numeric value such a symbol, the program runs through an infinite loop printing zeros, which i guess is how cout represents the wrong value entered. I'd like to know why is that weird behavior from cin, printing all those zeros instead of stopping when it finds a wrong reading.
#include <iostream>
using namespace std;
int main()
{
int n = 0;
while(n >= 0) {
cin >> n;
cout << n << endl;
}
return 0;
}
the program runs through an infinite loop printing zeros, which i guess is how cout represents the wrong value entered.
That is not quite right: when you ask cin for an int, but there's no int, you get no value back, but the invalid input remains in the buffer. When you ask for int again in the next iteration of the loop, same thing happens again, and no progress is made: bad data remains in the buffer.
That's why you get an infinite loop. To fix this, you need to add some code to remove bad data from the input buffer. For example, you could read it into a string, and ignore the input:
int n = 0;
while(n <= 0) {
cin >> n;
if (!cin.good()) {
cin.clear();
string ignore;
cin >> ignore;
continue;
}
cout << n << endl;
}
Demo.
You need to "eat" the non-numerical input i.e.
#include <iostream>
using namespace std;
int main()
{
int n = 0;
while(n >= 0) {
cin >> n;
if (!cin) {
char c;
cin >> c;
} else {
cout << n << endl;
}
}
return 0;
}

Getting user input upon pressing a space

I am trying to tackle this condition where the user has to input a number n. and then entering n numbers after it on the same line. Therefore my program needs to know this number n before the user continues to input so that the programs knows how large of a dynamic array it needs to save these numbers inputted after n. (It is crucial that all of this happens on one line).
I tried the following but it doesn't seem to work.
int r;
cin >> r;
//CL is a member function of a certain class
CL.R = r;
CL.create(r); //this is a member function creates the needed dynamic arrays E and F used bellow
int u, v;
for (int j = 0; j < r; j++)
{
cin >> u >> v;
CL.E[j] = u;
CL.F[j] = v;
}
You can do that as usual on a single line:
#include <string>
#include <sstream>
#include <iostream>
#include <limits>
using namespace std;
int main()
{
int *array;
string line;
getline(cin,line); //read the entire line
int size;
istringstream iss(line);
if (!(iss >> size))
{
//error, user did not input a proper size
}
else
{
//be sure to check that size > 0
array = new int[size];
for (int count = 0 ; count < size ; count++)
{
//we put each input in the array
if (!(iss >> array[count]))
{
//this input was not an integer, we reset the stream to a good state and ignore the input
iss.clear();
iss.ignore(numeric_limits<streamsize>::max(),' ');
}
}
cout << "Array contains:" << endl;
for (int i = 0 ; i < size ; i++)
{
cout << array[i] << ' ' << flush;
}
delete[] (array);
}
}
And here is the demonstration, you can see that the input is one line 6 1 2 3 4 5 6.
Once again, I did not check everything, so take care of that the way you need.
Edit: added reset of the stream after a bad read.