string conversion problem in big number class

I am trying to create a "BigNum" class that will handle numbers greater than 32 bits for problems on projecteuler.net. Here is the implementation file:

BigNum.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include "BigNum.h"

BigNum::BigNum(string sNum)
{
    //ensure proper place value alignment by filling the string with leading zeros
    while(sNum.length() < MAX_DIGITS){
        sNum = "0" + sNum;
    }


    for(int i = 0; i < MAX_DIGITS; i++){        //need a sentinel to indicate invalid string
        char place = sNum.at(i);

        number[i] = (int)place - '0';
    }
}

BigNum::~BigNum(void)
{
    //dtor
}

BigNum BigNum::add(BigNum addend){
    BigNum *newNum = new BigNum("0");
    int carry = 0;

    for(int i = MAX_DIGITS; i > 0; i--){        //iterate through place values, starting with the first, and add them together, keeping track of carries
        newNum->number[i] = number[i] + addend.number[i] + carry;

        if(newNum->number[i] > 9){
            newNum->number[i] -= 10;
            carry = 1;
        }
        else carry = 0;
    }

    return *newNum;
}

string BigNum::out(void){
    string sNum;

    for(int i = 0; i < MAX_DIGITS; i++){
        sNum.at(i) = (char)number[i];
    }         //convert big number to string

    int j = 0;

    while(sNum.at(j) == 0){     //removes leading zeroes for output

        if(sNum[j] == 0){
            sNum = sNum.substr(j + 1, MAX_DIGITS);
        }

        j++;
    }

    return sNum;
}


And here is my main source file, which is purely to test the "add" function of the class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<iostream>
#include "BigNum.h"

using namespace std;

int main(){
    BigNum firstNum("432"), secondNum("986"), answer("0");

    answer = firstNum.add(secondNum);

    cout << answer.out();

return 0;
}


The idea is I want to create a number with maximum digits of 20 as a string, create a big number class and give it the string, add leading zeroes to the string until it has the maximum number of digits (20) to ensure place value alignment, place the string into an integer array, and then perform operations on the array as if it were a number, as in the example of the "add" function above, it takes two such arrays and adds them starting with the least significant digits to the most (i.e. it adds from number array[20] to array[0]. It will compile and run, but I get the following error message from the console window:

terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::at
Aborted

Process returned 134 (0x86) execution time: 0.011s

I'm assuming the problem is where I call string.at(), the string length is shorter than the array, and thus there is no string.at(20), for example. However, I can't see a problem with the way I've set it up. Can somebody tell me what I'm doing wrong?

I'm using Code::Blocks IDE with ming gw compiler on ubuntu.
Last edited on
I haven't read the code, but change 20 to 21 and see if that works, it is probably because of the newline character.
I tried that but I still have the same problem. I also tried just changing my while that looks checks for the string length to "(string.length() < MAX_DIGITS + 1)"

The code above was edited after I noticed having an if statement before a while loop that checks for the same thing was redundant. Same problem, however.

I also need to change the while loop that converts it back to a string for output, since it will be skipping however many characters 'j' is equal to each loop. That's a separate issue though, I'll probably just replace it with a for loop.
Last edited on
Do you know exactly where (which line) it's crashing in?

Might be this:
1
2
3
4
5
6
string BigNum::out(void){
    string sNum; // This is an empty string!

    for(int i = 0; i < MAX_DIGITS; i++){
        sNum.at(i) = (char)number[i]; // So this would crash because sNum has size 0
    }
Thanks to both for the help. I went back and changed it to:

1
2
3
for(int i= 0; i < MAX_DIGITS; i++){
sNum += (char)number[i]
}


Which should fix that problem. Same error. I ran the debugger and it crashes on after line 7 in the code above, where I've placed a leading zero in sNum and return to the beginning of the while loop. It only gets through it once. Here is the output from the debugger:

#0 0x7ffff75543a5 __GI_raise(sig=6) (../nptl/sysdeps/unix/sysv/linux/raise.c:64)
#1 0x7ffff7557b0b __GI_abort() (abort.c:92)
#2 0x7ffff7b90d7d __gnu_cxx::__verbose_terminate_handler() () (/usr/lib/x86_64-linux-gnu/libstdc++.so.6:??)
#3 0x7ffff7b8ef26 ??() (/usr/lib/x86_64-linux-gnu/libstdc++.so.6:??)
#4 0x7ffff7b8ef53 std::terminate() () (/usr/lib/x86_64-linux-gnu/libstdc++.so.6:??)
#5 0x7ffff7b8f04e __cxa_throw() (/usr/lib/x86_64-linux-gnu/libstdc++.so.6:??)
#6 0x7ffff7b3b737 std::__throw_out_of_range(char const*) () (/usr/lib/x86_64-linux-gnu/libstdc++.so.6:??)
#7 0x7ffff7b78d6a std::string::at(unsigned long) () (/usr/lib/x86_64-linux-gnu/libstdc++.so.6:??)
#8 0x4011ff BigNum::BigNum(this=0x7fffffffe3d0, sNum=...) (/win7/Users/neros1x/Dropbox/c_projects/project_euler5/src/BigNum.cpp:10)
#9 0x400da7 main() (/win7/Users/neros1x/Dropbox/c_projects/project_euler5/project_euler5.cpp:11)
Last edited on
It should probably be
1
2
3
for(int i= 0; i < MAX_DIGITS; i++){
sNum += (char)(number[i] + '0');
}

assuming "number" is an array of ints.

Because (char)(3) != '3'

I don't know if that'll fix your error, but I don't really see anything else that looks wrong (looking at the code in your first post)...

Oh, by the way, instead of
1
2
3
4
5
6
7
8
9
10
int j = 0;

while(sNum.at(j) == 0){     //removes leading zeroes for output

     if(sNum[j] == 0){
        sNum = sNum.substr(j + 1, MAX_DIGITS);
    }

    j++;
}

you could just simply do
sNum = sNum.substr(sNum.find_first_not_of('0'));
http://www.cplusplus.com/reference/string/string/find_first_not_of/

(but be careful that sNum is not 0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
BigNum BigNum::add(BigNum addend){
    BigNum *newNum = new BigNum("0");
    int carry = 0;

    for(int i = MAX_DIGITS; i > 0; i--){     
        newNum->number[i] = number[i] + addend.number[i] + carry;

        if(newNum->number[i] > 9){
            newNum->number[i] -= 10;
            carry = 1;
        }
        else carry = 0;
    }

    return *newNum;
}


Memory leak. No reason to use a pointer and new here. In addition the prototype should probably be:

BigNum BigNum::add(const BigNum & addend) const

You might save yourself some trouble later by using a vector in the implementation and not limiting the size of your numbers arbitrarily.

for(int i = MAX_DIGITS; i > 0; i--){

If MAX_DIGITS is the size of your array, then i should be set to MAX_DIGITS-1.


Last edited on
I used both your suggestions, thanks for the help.

The problem turned out to be here:
1
2
3
4
5
for(int i = 0; i < MAX_DIGITS; i++){        
        char place = sNum.at(i);  //<---------------When it started the loop, there is no position "0" in a string

        number[i] = (int)place - '0';
    }
Last edited on
Topic archived. No new replies allowed.