Joshua Theeuf
Joshua Theeuf

Reputation: 27

strtol help why does it return a 0

so i am confused as to why the inbuilt strtol is returning 0. From the manual it says it will return 0 if no conversion is possible. Though too me it should convert properly. This is the function.

struct coin * addCoins(char *val){
    char *ptr =NULL;
    long int denomination = strtol(val, &ptr,10);
    long int count = strtol( &ptr,NULL, 10);
        printf("%d",count);
    struct coin *k;
    k = malloc(sizeof(struct coin));
    k->denom = denomination;
    k->count = count;
    return k;
}

This returns long integers for the denomination of the coin, and how many of the coin's there are which are then stored in a struct of type coin. Which has the following typedef.

/* Each coin in the coins array will have a denomination (20 cents, 
 * 50 cents, etc) and a count - how many of that coin do we have on hand
 */
struct coin
{
    enum denomination denom;
    unsigned count;
};

The format of the file being read in is as follows. The first column is the denomination, and the second is the count.

1000,3
500,4
200,20
100,30
50,5
20,3
10,40
5,20

the delimiter being the comma. We where specifically told to use strtol, otherwise i would use strtok_r.

Upvotes: 1

Views: 5220

Answers (2)

user3386109
user3386109

Reputation: 34829

Your code

long int denomination = strtol(val, &ptr,10);
long int count = strtol( &ptr,NULL, 10);

The second line has some problems.

The first argument &ptr should simply be ptr. That's because strtol wants a simple pointer-to-char as its first argument. So although the ampersand was correct in the first call to strtol, it is not correct in the second call.

Problem number two is that the endptr returned from strtol points to the first character that's not part of the first number. In other words, it points to the comma. It's up to you to advance the pointer past the comma.

Which then introduces another problem. Before advancing the pointer past the comma, you have to make sure that it actually does point to a comma. If it doesn't, then something's amiss, and you have to fail gracefully. Since your function returns a pointer, you should return NULL to indicate that an error occurred.

Hence, your function should be

struct coin * addCoins(char *val)
{
    char *ptr;
    long int denomination = strtol( val, &ptr, 10 );
    if ( ptr == val || *ptr != ',' )   // verify that we found the comma
        return NULL;
    ptr++;                             // advance the pointer past the comma

    char *endptr;
    long int count = strtol( ptr, &endptr, 10 );
    if ( endptr == ptr || *endptr != '\0' )   // verify that the second conversion succeeded
        return NULL;

    struct coin *k;
    k = malloc(sizeof(struct coin));
    k->denom = denomination;
    k->count = count;
    return k;
}

Upvotes: 1

Joshua Theeuf
Joshua Theeuf

Reputation: 27

The solution i came up with was the to tokenise the string before passing to strtol, but imagine there is a more elegant way to perform this operation.

char *ptr =NULL;
char *ptrs =NULL;
const char *deli = ",";
char *denominations = strtok_r(val, deli, &ptrs);
char *counts = strtok_r(NULL, deli, &ptrs);

long int denomination = strtol(denominations, &ptr,10);
long int count = strtol( counts,NULL, 10);

Upvotes: 0

Related Questions