-1

I want to implement simple task:

I have single line input with numbers:

2 1 2 3

And i want to print it so currently this works fine for most of scenarios:

char str[512];

for (i = 0; i < (strlen(str)); i++)
{
    if (str[i] != '\0' && !isspace(str[i]))
    {
        int num = atoi(&str[i]);
        printf("%d ", num);

    }
}

Now in case my input is with number with mote then one digit things start to mess.

For example:

2 12

In this case i can see that i have this input:

2 12 2

So in case i have number > 9 i can just raise i by 1:'

if (i > 9)
  i++;

And in case my number is with 3 digits i can just do i+=2 but is there is another solution maybe that is more 'clean' ?

EDIT

fgets(str, sizeof str, stdin);

char *ptr;
long ret;

for (i = 0; i < (strlen(str)); i++)
{
    if (str[i] != '\0' && !isspace(str[i]))
    {
        ret = strtol(str[i], &ptr, 10);
        printf("%ld\n", ret);
    }       
}
Dana Yeger
  • 617
  • 3
  • 9
  • 26

1 Answers1

1

You already found out what's wrong with your solution. The idea you present is bad, what if the string contains something like 01? This is two characters, but still smaller than 10.

There are several possibilities to do better, I can think of two approaches immediately:

  • instead of atoi(), use strtol() (you should anyways). strtol() has a parameter endptr -- pass it the address of a char * pointer, then this pointer will point to the first character that wasn't converted. To use this, you must probably rewrite your loop to use pointers. Here's an example:

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    char str[512] = "2 15 42 7 11";
    
    int main(void)
    {
        for (const char *c = str; *c;)
        {
            if (!isspace(*c))
            {
                char *endptr;
                long num = strtol(c, &endptr, 10);
                if (endptr == c) exit(1);   // nothing was converted, just error out here
                printf("%ld\n", num);
                c = endptr;
            }
            else
            {
                ++c;
            }
        }
    }
    
  • Even simpler, if it doesn't matter to destroy your input string in the course, use strtok() (see the manpage for how it works) to split your strings at the whitespace, like strtok(str, " \t\n") in the first iteration and strtok(0, " \t\n") in the subsequent iterations. Then you can just convert the parts you get from strtok().

  • Please see my edit, this works only for str, and then prong the first number several times, if i change it inside the for to str[i] this crash – Dana Yeger Nov 23 '17 at 19:14
  • @DanaYeger the code in your edit is chaos, as I wrote, you need to **make use** of `endptr` and therefore have to rewrite your loop to operate on pointers. See the example I edited in. –  Nov 23 '17 at 19:17
  • Why i need this code: const char *c = str ? – Dana Yeger Nov 23 '17 at 19:20
  • Initialize your pointer to the start of your input string? The loop operates on the pointer now (instead of on an index). –  Nov 23 '17 at 19:21