How To Use Atol() Function to turn array of characters into two numbers (Getting EXTREMELY strange behaviour)

So the ordinary usage of atol is convert a array of characters into numbers.
But I tried to split up the first half of the array and second half and atol() them separately. I got very strange results.

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
#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

int main()
{

    char buf[3]; //Initial buffer in which I read data
    buf[0] = '1';
    buf[1] = '2';
    buf[2] = '3';

    char layer[] = {buf[0]}; //First number
    char led[] = {buf[1], buf[2]}; //Second number
    //2 char d1 = buf[1]; //A test for myself
    //2 char d2 = buf[2]; //A test for myself

    cout << atol(buf) << endl;
    cout << atol(layer) << endl;
    cout << atol(led) << endl;
    //1 cout << atol(buf);
}

So I played around with them. As the code is right now with all the comments, I get this output:
123
1123
231123

Comment in the commented out line designated as 1. You get as expected (sorta):
123
1123
231123
123

Now comment in the lines designated as 2. You get:
12332
112332
23112332
12332

I can't put two and two together and the docs on the atol function are giving my nothing.

I appreciate an explanation (I am REALLY curious) and the proper way of splitting up one number into two!
Last edited on
C-style strings need a null character at the end to signify their termination. Things tend to go awry when there isn't one - functions that deal with c-strings will usually keep going until they hit a null character.

In this case, however, atol stops at the first non-numeric character. When the lines marked as '2' are uncommented, atol includes them because it hasn't found a null character or a non-numerical character yet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

int main()
{

    const char buf[] = "123"; // null character is automatically added

    char layer[] = {buf[0], '\0'}; //First number
    char led[] = {buf[1], buf[2], '\0'}; //Second number
    char d1 = buf[1]; //A test for myself
    char d2 = buf[2]; //A test for myself

    cout << atol(buf) << endl;
    cout << atol(layer) << endl;
    cout << atol(led) << endl;
    //1 cout << atol(buf);
    return 0;
}
Last edited on
Ah, thanks a lot! You were correct. Any ideas why though? If anyone here knows the exact way the compiler works.
Any ideas why though?

Why c-strings need a null character? A c-string is simply a pointer to a location in memory. That pointer, when passed to a function, tells nothing about what lies ahead. The pointer is then treated as a stream of characters. A null character has to be included to signify that the function has reached the end of the "string."

As for the implementation, here is a (very) rough and inefficient, but completely standards-compliant version of atol. I made this just to show you what logic is going on behind the scenes here - don't use this as a replacement for atol. Also, the actual implementation of atol (and other functions like it) are most likely written in assembly by hand for performance reasons.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
long myatol(const char* str)
{
    while(*str++ == ' '); // ignore leading whitespace
    bool neg = false;
    char c = *(--str); // find first character
    switch(c) { // handle +/-
        case '-' :
            neg = true;
        case '+' :
            c = *(++str);
        default :
            break;
    }
    long ret = 0;
    while(c >= '0' && c <= '9') { // loop until non-numerical value is hit
        ret = (ret * 10) + (c - '0');
        c = *(++str);
    }
    return neg ? -ret : ret;
}
Last edited on
Interesting. Thanks a lot!
Topic archived. No new replies allowed.