Checking the int limits in stoi() function in C++ [duplicate] - c++

This question already has answers here:
c++ parse int from string [duplicate]
(5 answers)
Closed 9 years ago.
I have been given a string y in which I'm ensured that it only consists digits. How do I check if it exceeds the bounds of an integer before storing it in an int variable using the stoi function?
string y = "2323298347293874928374927392374924"
int x = stoi(y); // The program gets aborted when I execute this as it exceeds the bounds
// of int. How do I check the bounds before I store it?

you can use exception handling mechanism:
#include <stdexcept>
std::string y = "2323298347293874928374927392374924"
int x;
try {
x = stoi(y);
}
catch(std::invalid_argument& e){
// if no conversion could be performed
}
catch(std::out_of_range& e){
// if the converted value would fall out of the range of the result type
// or if the underlying function (std::strtol or std::strtoull) sets errno
// to ERANGE.
}
catch(...) {
// everything else
}
detailed description of stoi function and how to handle errors

Catch the exception:
string y = "2323298347293874928374927392374924"
int x;
try {
x = stoi(y);
}
catch(...) {
// String could not be read properly as an int.
}

If there is a legitimate possibility that the string represents a value that's too large to store in an int, convert it to something larger and check whether the result fits in an int:
long long temp = stoll(y);
if (std::numeric_limits<int>::max() < temp
|| temp < std::numeric_limits<int>::min())
throw my_invalid_input_exception();
int i = temp; // "helpful" compilers will warn here; ignore them.

Related

Handling an error condition in the compare function of std::qsort

I am trying to figure out a way for qsort to throw an exception or indicate an error condition if the compare function finds that the elements are, for some reason, invalid for sorting.
For example, in this compare function, I need to indicate an error condition that my sorting is invalid if the return value of some_function is 5.
How should I modify my compare function?
int compare (const void * a, const void * b)
{
int ret1 = some_func(a);
int ret2 = some_func(b):
return ( ret1 - ret2 );
}
I am dealing with a legacy code base so I'm not in the position to use std::sort and due to the nature of the implementation calling some_func before hand might also involve huge amount of changes so I'm looking to understand if a workaround is possible.
C++ allows you to throw whatever you need, not only exceptions but also other types, you could do something like throw an int if it suits your purposes and catch where you call the function with a try-catch block.
For what you need I think you can use STL exception library:
Demostrative example:
#include <iostream>
#include <exception>
int count = 0;
int compare(const void *a, const void *b)
{
int ret1 = *(int*)a > *(int*)b;
if (++count == 5) //throws exception when count reaches 5
throw std::invalid_argument("Argument is not sortable");
//you could throw count by simply using throw count
return ret1;
}
int main()
{
int x[]{2,1,3,5,6,1,7,2,5,3};
try
{
//will sort until exception is thrown
qsort(x, sizeof x / sizeof *x, sizeof(int), compare);
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl; //print exception in the console
//handle the exception here
//if you were to throw count you could cach it with
//catch (int &e)
}
//note that the values were sorted until the exception was thrown
for (int i = 0; i < sizeof x / sizeof *x; i++){
std::cout << x[i] << " ";
}
}
Output:
Argument is not sortable
1 2 3 5 6 1 7 2 5 3
^
sorting
stopped
here
Throwing an exception is potentially expensive, so you probably want to return an error condition. However, doing either approach inside the compare function is needlessly expensive in this case, since you would be doing the check multiple times for every element. Instead, you could just check for the error condition before calling qsort which is much more efficient:
auto ok = std::none_of(/* range */, /* predicate */);
if (ok)
std::qsort(/* ... */)
else
// report error

What can be inputted in the following program to access the array?

Since x is not really validated and is received through scanf, there should be potentially tainted data that can be used to access bytes.
Code (not really logically doing anything productive):
void getMyBytes(){
int x, byte;
int bytes[20];
scanf("%u %u", &x, &byte);
bytes[x-1] = byte;
}
A known simple (ugly) fix for this code is:
void getMyBytes(){
int x, byte;
int bytes[20];
scanf("%u %u", &x, &byte);
if (x > sizeof(bytes)/sizeof(*bytes)) return; --> validation fix
bytes[x-1] = byte;
}
What inputs can I enter in scanf so that I can access bytes?
This depends on your application but you should always bound check external input when accessing your internal members. How you report this is up to you. But consider using the std::vector or std::array to help you out. In your example:
void getMyBytes(){
int x, byte;
std::array<int, 20> bytes; // Bad name btw, an int is very unlikely to be a byte.
scanf("%u %u", &x, &byte); // scanf is not type safe. Consider using cin <<
bytes.at(x-1) = byte; // Automatically bound checks for you and will throw an exception
// in the case that you are out of bounds. Very useful :)
}
std::array::at:
Returns a reference to the element at specified location pos, with bounds checking.
If pos is not within the range of the container, an exception of type std::out_of_range is thrown.
Other ways you might report the error include:
Hard death in debug: assert(x >= 0 && x < bytes.size() && "I crashed here because you gave me bad input!")
Error reported to function caller: if (x < 0 || x > bytes.size()) { return false; }
Throw with more info: if (x < 0) { throw my_special_underrun_exception; } and if (x > bytes.size()) { throw my_special_overrun_exception; }
Finally consider visiting the CppCoreGuidelines for plenty of tips about how to write good code.

C++ memory allocation for a structure

I was given a task to create dll where I need to allocate and free memory for structure. Unfortunately, I don't know how to check if the code works.
#pragma once
#include "stdafx.h"
#include "RandomBlockHeader.h"
#include <iostream>
#include <ctime>
using namespace std;
namespace RandBlock {
unsigned long RandBlockFuncs::GenerateRandomBlock(RANDOM_BLOCK ** ppRandomBlock) {
try {
srand(time(NULL));
ppRandomBlock = (RANDOM_BLOCK**)malloc(sizeof(RANDOM_BLOCK));
int random = rand() % 129;
(**ppRandomBlock).ulRandomLen = random;
(**ppRandomBlock).pRandomData = new unsigned char[random];
for (int i = 0; i < random; i++) {
(**ppRandomBlock).pRandomData[i] = (char)(rand() % 256);
}
return 0;
}
catch (exception& e) {
return -1;
}
}
unsigned long FreeRandomBlock(RANDOM_BLOCK * pRandomBlock) {
try {
delete pRandomBlock;
return 0;
}
catch (exception& e) {
return -1;
}
}
}
Can anybody point out where I can have possible errors? And is this a correct way to allocate memory for two pointer structure?
ppRandomBlock = (RANDOM_BLOCK**)malloc(sizeof(RANDOM_BLOCK));
is not good. I suspect it needs to be:
*ppRandomBlock = (RANDOM_BLOCK*)malloc(sizeof(RANDOM_BLOCK));
Better yet, since you are using C++, change the function interface to:
unsigned long RandBlockFuncs::GenerateRandomBlock(RANDOM_BLOCK*& ppRandomBlock) { ... }
Then, the function will look cleaner (don't use malloc at all):
unsigned long RandBlockFuncs::GenerateRandomBlock(RANDOM_BLOCK*& ppRandomBlock) {
try {
srand(time(NULL));
ppRandomBlock = new RANDOM_BLOCK;
int random = rand() % 129;
(*ppRandomBlock).ulRandomLen = random;
(*ppRandomBlock).pRandomData = new unsigned char[random];
for (int i = 0; i < random; i++) {
(*ppRandomBlock).pRandomData[i] = (char)(rand() % 256);
}
return 0;
}
catch (exception& e) {
return -1;
}
}
I assume that a RANDOMBLOCK is a struct type that contains (at least) two members - ulRandomLen which is of type int (not withstanding its name) and pRandomData which is of type pointer to unsigned char.
Based on those assumptions, the code has the following problems
The function has return type of unsigned long and returns -1. That (fortunately) has a well-defined effect - it returns the largest value an unsigned long can represent. However, that may not be what the caller expects.
The code calls srand() every time the function is called. This will - unless the program runs for a very long time - reinitialise the random number seed, and result in the same sequence of random values being returned by rand(). You need to ensure srand() is only called ONCE within the COMPLETE program, before the first call of rand().
The statement ppRandomBlock = (RANDOM_BLOCK**)malloc(sizeof(RANDOM_BLOCK)) needs to allocate sizeof(RANDOMBLOCK *), not sizeof(RANDOM_BLOCK). Better yet, replace the statement with ppRandomBlock = new (RANDOM_BLOCK *), and get away from needing to worry about the sizing.
The problem with the preceding statement (whether fixed or not) is that it does not allocate a RANDOMBLOCK, and leaves *ppRandomBlock uninitialised. This causes all the accesses via **ppRandomBlock to have undefined behaviour. So, it would need to be followed by a *ppRandomBlock = new RANDOMBLOCK.
The inner for loop has a statement (*ppRandomBlock).pRandomData[i] = (char)(rand() % 256) despite pRandomData[i] being of type unsigned char. It is implementation-defined whether a straight char is signed or unsigned. If it is signed, the maximum value a char can hold is not guaranteed able to hold a value greater than 127. That causes the conversion to char to have undefined behaviour.
As a partial fix, change RANDOMBLOCK to contain a std::vector<unsigned char> RandomData and eliminate the members ulRandomLen and pRandomData completely. Then change the function to
unsigned long RandBlockFuncs::GenerateRandomBlock(RANDOM_BLOCK*& ppRandomBlock)
{
try
{
// assume `srand()` has been called, for example, in main()
ppRandomBlock = new RANDOM_BLOCK;
int random = rand() % 129;
ppRandomBlock.RandomData.resize(random);
for (int i = 0; i < random; i++)
{
ppRandomBlock.RandomData[i] = (unsigned char)(rand() % 256);
}
return 0;
}
catch (exception& e)
{
return -1;
}
}
Note that the above does not fix the problem with an unsigned return type and -1 return value.
More generally, the overarching problem in the OP's code is that it is a rough translation of some C code - with adornment - into C++. Even if it was good C code, good C technique is not always good C++ technique and vice versa. And, on the face of it, the original code involved bad technique in C.
It would be better to rewrite the code completely to use C++ library features (I've demonstrated one element of that, more are possible) and not use operator new directly at all.

C++ using 1 function for multiple varaibles. Only first run works

Newish to C++ but been researching alot so please bear with me.
I've been trying to use 1 function to relate 8 global double variables [ mA mB ... mG which ranges from values 1 to 10] to another double value.
I first obtain these 8 variables by obtaining the data from a csv file, throwing them to an array and then equating the set global variables. This all works fine. I cout the values correctly.
mA =10, mB=1 ,.... mG=2
However I need to use these variables to relate to another set value. So i Use:
double Function1(double Mvalue1)
{
if (Mvalue1 == 1) { double value = 10; return value ; }
if (Mvalue1 == 2) { double value = 20; return value ; }
.... // cont to 10 only increasing value by 10
if (Mvalue1 == 10) { double value = 110; return value ; }
}
void VarFunction()
{
mA2= Function1(mA); **//SHOULD output 110**
cout << "Vaule A " << mA2 << endl;
mB2= Function1(mB); **//SHOULD output 10**
cout << "Vaule B " << mB2 << endl;
....//.... 8 times
mG2 = Function1(mG); **//SHOULD output 20**
cout << "Vaule G " << mG2 << endl;
}
int main()
{
VarFunction()
return 0;
}
So the output i get here is
Value A 110
Value B -1.#IND
....
Value G -1.#IND
Why isnt the next call of function1 with the next variable not working?
In your code you have mA set to 12, but Function1 doesn't have a case for 12. So, I'm surprised you're even getting 110 printed for the first line. You aren't handling the case inside Function1 where Mvalue1 isn't one of the desired values, so this is the first thing to fix.
Also, assigning a number to a double and then returning it is unnecessarily complicated. A case statement would work well, assuming you really want to pass integers:
double Function1(int Mvalue1)
{
switch(Mvalue1) {
case 1: return 10;
case 2: return 20;
//...
case 10: return 110; // are you sure you don't want 100?
default: return -1; // handle the case here so that you always return a value.
}
}
Of course, if you really just want 10 times your input, why not:
double Function1(double mValue1)
{
return mValue1*10;
}
Not all paths in your function return a defined value, i.e. there's no return statement after all the conditionals.
The compiler is probably telling you that. If not - compile with higher warning level.
Use the std::map container when building relationships like this.
#include <iostream>
#include <map>
typedef std::map<double, double> rel_t;
int main()
{
rel_t mymap;
// You can directly
// std::map<double, double> mymap;
mymap[1] = 10;
mymap[2] = 20;
mymap[10] = 110;
std::cout << mymap[1] << std::endl; // Prints 10
std::cout << mymap[2] << std::endl; // Prints 20
std::cout << mymap[10] << std::endl; // Prints 110
}
This program seems to be working for me when I run it. However, I had to add declarations for mA2, mB2, and mG2 in your VarFunction(). You're also missing a semicolon after your call to VarFunction() in main().
I'd also suggest you return some default double in the function double Function(double Mvalue1), just in case Mvalue1 does not satisfy any of the if statements.
As already said, Function1() should return a value in case all if statements are false!
If the numbers your are dealing with have no fractional digits, use short, int, long or any other integer type for the variables. Then you can use a switch()/case construct or keep on using the comparison operator ==.
In case you must deal with floating point values, never use the == operator! When reading floating point values from text files (like CSV) or a database, a conversion from text to float/double is done. The result from such conversion can end in e.g. 9.999999999 or 10.000000001 instead of 10. And then the comparison with == is false!
To compare two double variables use a method like this:
bool dEqual( double dVal1, double dVal2, double dTolerance)
{
if( fabs( dVar1 - dVar2) < dTolerance) {
// dVar1 is nearly equal to dVar2
return true;
}
// dVar1 is not equal to dVar2
return false;
}
Then this comparison is true:
if( dEqual( 10.0, 9.999999998, 0.000001))
Apply a value for tolerance that meets the accuracy you need.

Getting segmentation fault after destructor

I'm making a small file reading and data validation program as part of my TAFE (a tertiary college) course, This includes checking and validating dates.
I decided that it would be best done with a seperate class, rather than integrating it into my main driver class.
The problem is that I'm getting a segmentation fault(core dumped) after my test program runs. Near as I can tell, the error occurs when the program terminates, popping up after the destructor is called. So far I have had no luck finding the cause of this fault, and was hoping that some enlightened soul might show me the error of my ways.
date.h
#ifndef DATE_H
#define DATE_H
#include <string>
using std::string;
#include <sstream>
using std::stringstream;
#include <cstdlib>
using std::exit;
#include <iostream>
using std::cout;
using std::endl;
class date {
public:
explicit date();
~date();
bool before(string dateIn1, string dateIn2);
int yearsBetween(string dateIn1, string dateIn2);
bool isValid(string dateIn);
bool getDate(int date[], string dateIn);
bool isLeapYear(int year);
private:
int days[];
};
#endif
date.cpp
#include "date.h"
date::date() {
days[0] = 31;
days[1] = 28;
days[2] = 31;
days[3] = 30;
days[4] = 31;
days[5] = 30;
days[6] = 31;
days[7] = 31;
days[8] = 30;
days[9] = 31;
days[10] = 30;
days[11] = 31;
}
bool date::before(string dateIn1, string dateIn2) {
int date1[3];
int date2[3];
getDate(date1, dateIn1);
getDate(date2, dateIn2);
if (date1[2] < date2[2]) {
return true;
} else if (date1[1] < date2[1]) {
return true;
} else if (date1[0] < date2[0]) {
return true;
}
return false;
}
date::~date() {
cout << "this is for testing only, plox delete\n";
}
int date::yearsBetween(string dateIn1, string dateIn2) {
int date1[3];
int date2[3];
getDate(date1, dateIn1);
getDate(date2, dateIn2);
int years = date2[2] - date1[2];
if (date1[1] > date2[1]) {
years--;
}
if ((date1[1] == date2[1]) && (date1[0] > date2[1])) {
years--;
}
return years;
}
bool date::isValid(string dateIn) {
int date[3];
if (getDate(date, dateIn)) {
if (date[1] <= 12) {
int extraDay = 0;
if (isLeapYear(date[2])) {
extraDay++;
}
if ((date[0] + extraDay) <= days[date[1] - 1]) {
return true;
}
}
} else {
return false;
}
}
bool date::getDate(int date[], string dateIn) {
string part1, part2, part3;
size_t whereIs, lastFound;
whereIs = dateIn.find("/");
part1 = dateIn.substr(0, whereIs);
lastFound = whereIs + 1;
whereIs = dateIn.find("/", lastFound);
part2 = dateIn.substr(lastFound, whereIs - lastFound);
lastFound = whereIs + 1;
part3 = dateIn.substr(lastFound, 4);
stringstream p1(part1);
stringstream p2(part2);
stringstream p3(part3);
if (p1 >> date[0]) {
if (p2>>date[1]) {
return (p3>>date[2]);
} else {
return false;
}
return false;
}
}
bool date::isLeapYear(int year) {
return ((year % 4) == 0);
}
and Finally, the test program
#include <iostream>
using std::cout;
using std::endl;
#include "date.h"
int main() {
date d;
cout << "1/1/1988 before 3/5/1990 [" << d.before("1/1/1988", "3/5/1990")
<< "]\n1/1/1988 before 1/1/1970 [" << d.before("a/a/1988", "1/1/1970")
<<"]\n";
cout << "years between 1/1/1988 and 1/1/1998 ["
<< d.yearsBetween("1/1/1988", "1/1/1998") << "]\n";
cout << "is 1/1/1988 valid [" << d.isValid("1/1/1988") << "]\n"
<< "is 2/13/1988 valid [" << d.isValid("2/13/1988") << "]\n"
<< "is 32/12/1988 valid [" << d.isValid("32/12/1988") << "]\n";
cout << "blerg\n";
}
I've left in some extraneous cout statements, which I've been using to try and locate the error.
I thank you in advance.
Change:
private:
int days[];
to:
private:
int days[12];
The problem is that you never actually initialize the days field in the type date. This means that when you are setting the values in the constructor you are accessing uninitialized memory.
You need to explicitly initialize the days value in some way. The easiest fix is to use a vector for the type or to hard code the size of the array to 12.
private:
int days[12];
Or
private:
std:vector<int> days;
...
date::date() {
days.push_back(31);
days.push_back(28);
...
}
You don't say which compiler you are using, but if I compile this code using g++ with the -Wall and -pedantic flags:
struct S {
int a[];
};
int main() {
S s;
}
I get the warning message:
warning: ISO C++ forbids zero-size array 'a'
The moral is that you should always compile using as many compiler warnings as possible - it can save you mountains of time and result in more correct code.
int days[];
This is a non-standard extension. You must specify a size for the array, such as:
static const MonthCount = 12;
int days[MonthCount];
To actually have an array to use. Otherwise you have a "zero-sized array" (not standard!). Your program is tromping over memory every time you use any element of your current array.
I agree with the previous answers to this question, but I would add the rationale for their correctness:
Segmentation faults are caused whenever you attempt to access memory you are not allowed to access.
http://en.wikipedia.org/wiki/Segmentation_fault
You were not allowed to access "days[0]" through days "[11]" because the computer had not given the "days[]" variable that you declared enough memory to hold any elements, thus when you tried to access said elements, it threw a segfault.
Any variables not declared with the "new" operator are placed on the "stack," which is a contiguous chunk of memory the computer has sectioned away for use by the program. In order to keep everything stored in the stack contiguous, the computer will only give exactly the amount memory you require for you to use whenever you request it, so that if you request to create an int, for example, it will only give you enough memory to store that single int.
When you wrote the line int days[]; the computer attempted to evaluate how much memory it would require, assessed it as an empty array, and gave you enough memory to store said empty array. Because the computer did not give your array any extra space beyond what was needed for an empty array, it knew that the memory you tried to access in that array had not been assigned to it, so it threw a segmentation fault and crashed.
If you have not yet learned about the "stack" and "heap" in your computer science class, then sorry if this is a bit overwhelming, but I perhaps overcomplicated things, and I think you likely soon will.