8

See this main:

int main(void)
{
    int i;
    int ch;
    char str[512];
    fgets(str, sizeof str, stdin);

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

    return 0;
}

I want to get line with numbers from user and get all the numbers without any spaces or tabs.

For example:

The input 1 2 3. But in this case this the output:

1
2
2
3
3

So why i received 2 and 3 twice?

5
  • 2
    How do you develop your code? Do you just edit it in Notepad? Get yourself an IDE, such as Eclipse CDT, NetBeans, MS Visual Studio, etc. Learn how to set breakpoints, step through the code, line by line, examine variables. You have just been taught how to fish :-) Commented Nov 23, 2017 at 9:08
  • 2
    You have a for loop that, for no logical reason whatsoever, attempts to process every character in the input and output some number for it. It's immediately obvious that for "1 2 3", five numbers will be printed, since there are five characters in that string that are not nul or newline. Commented Nov 23, 2017 at 10:13
  • 2
    @Mawg to fish you don't need a trawler: a fishing rod would be enough in many cases (a simple debugger instead of an IDE, in this analogy). Commented Nov 23, 2017 at 11:00
  • A good point, but a visual debugger is simpler. Rather the IDE showing GDB, thak just running GDB from the command line Commented Nov 23, 2017 at 11:51
  • 1
    You want to get the numbers without spaces or tabs, but nowhere do you check for either spaces or tabs. Commented Nov 23, 2017 at 14:30

7 Answers 7

6

Here's how I would do it:

char line[256];
if (fgets(line, sizeof line, stdin) != NULL)
{
    const char *ptr = line;
    while (*ptr != '\0')
    {
        char *eptr = NULL;
        const long value = strtol(ptr, &eptr, 10);
        if (eptr != ptr)
            printf("%ld\n", value);
        else
            break;
        ptr = eptr;
    }
}

This uses strtol() so it will also handle negative numbers; if this is incorrect you can of course add checks to filter them out. I think this is way better than anything using strtok().

Sign up to request clarification or add additional context in comments.

1 Comment

Perhaps mention that, in addition to not telling you where it stopped parsing, atoi() also triggers UB in case of overflow... strto*() is definitely the right choice here.
5

Because the you also pass the position of the string which starts with spaces. they get the first number to be 2 and 3 respectively twice. That is what is returned.

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

Prints:

1
2
3

For the purpose of tokenizing you can use strtok and to convert it to number strtol etc. These provides much better control over the error cases than atol/atoi do.

5 Comments

In this case thats works but in case my input is 12 the output is 12 and 2
@user2908206.: To be honest use strtok...that gies with your vehbavior that you expect. here also It points to 12's 1 once an dthen again in 2.
Any chance to fix it without strtok ?
@user2908206.: To give you hint you will have to tokenize it (between spaces and all) and then pass each of them to atoi() ot even better strtoletc
1

When it reaches the space character in the input it will call atoi() with " 2 3" (resulting in 2) and later on " 3" (resulting in 3) which creates the unexpected numbers.

Comments

0

From the ref of atoi():

The function first discards as many whitespace characters (as in isspace) as necessary until the first non-whitespace character is found. [...]

That means that if you give as input to that function " 2", it will return 2.


Change this:

if (str[i] != '\0' && str[i] != '\n')

to this:

if (str[i] != ' ' && str[i] != '\0' && str[i] != '\n')

and you will get:

1
2
3

Here is a tip about debugging this code: In your output, you got 2 and 3 twice, but not 1.

In other words, you get the number that were after a space twice. 1 didn't have a space before it.

This should make you thing that there is something spooky about the spaces there.

Indeed, you would enter the body of the if statement, even if str[i] was a space!

By adding a condition to check if the current character is not a space, to enter the boby of the if statement, you actually skip the spaces.

2 Comments

Wouldn't this turn multi-digit numbers into multiple numbers too? (As in 12 -> 12 and 2)
Yes @ilkkachu! ;)
0

It is a good idea to always think of error handling. What if the user wrongly press space and tabs. So first remove spaces and tabs if exist :

char *c = string;
while ((*c == ' ') || (*c == '\t'))
    ++c;

and then use atoi().

Comments

0

The solution with strtok isn't that hard either:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    char s[128];
    fgets(s, sizeof s, stdin);
    const char *delim = " \t\n";

    char *p = strtok(s, delim);
    while(p) {
        int val = strtol(p, NULL, 10);
        printf("%d\n", val);
        p = strtok(NULL, delim);
    }
    return 0;
}

Though do keep in mind that it's a bit iffy in that it uses hidden state (not good for multithreaded programs), and of course it modifies the input string, so it can't be a constant (but why would you do that).

Comments

-1

You can use isdigit or isalpha() function (based upon your use) available in ctype.h. following is code snippet using isdigit function:

for (i = 0; i <= (strlen(str)); i++)
{
    if (isdigit(str[i]))
    {
        int num = atoi(&str[i]);
        if(i && str[i-1]=='-') num *= -1;
        printf("%d\n", num);
        i += ( num==0 ) ? 1 : (int)log10(abs(num))+1;
    }
}

See it working here.
Check here for example on isdigit and isalpha() functions.

Regarding your question that:

So why i received 2 and 3 twice?

See following explanation available at cplusplus.com which explains the atoi() function.

The function first discards as many whitespace characters (as in isspace) as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many base-10 digits as possible, and interprets them as a numerical value.

7 Comments

Yes but in case my input is 12 the output is 12 and another 2 and i try to understand how to fix it
What while(num) doing ?
This is really convoluted and overly complicated, in my opinion.
Endless loop in case i have 0 in my input
Updated the code snippet to resolve the logical error. Hope it would work fine now.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.