Cut float numbers in a stream (putchar, getchar) and in a string For example, the following row:

"a+12.3456-b-0.456789+1.3-45678"

will be transformed into

"a+12.34-b-0.45+1.3-45678"

That is, we need to cut out the figures after the point from the third figure. The signal of the row's end is the sign '&amp;'.

With the getchar and putchar functions:

char c = 0, c_ = 0,flag=0;
while ((c = getchar()) != '&amp;')
{

    if (isdigit(c) &amp;&amp; !(isdigit(c_)))
    {
        flag = 1;
    }

    putchar(c);

    if (flag)
    {
        while ((c = getchar()) != '.') putchar(c);

        putchar(c);

        c = getchar();
        putchar(c);
        if (!isdigit(c)){ flag = 0; continue; }

        c = getchar();
        putchar(c);
        if (!isdigit(c)){ flag = 0; continue; }

        while (isdigit(c=getchar()));
        putchar(c);
        flag = 0;
    }
    c_ = c;
}


Using strings:

char s[100] = { 0 }, s1[100] = { 0 };
inti = 0, j = 0;

gets(s);

while (s[i] != '&amp;')
{
    if (isdigit(s[i])
    {
        while (s[i] != '.')
        {
            s1[j++] = s[i++];
        }

        s1[j++] = s[i];

        s1[j++] = s[++i];
        if (!isdigit(s[++i])) continue; 

        s1[j++] = s[i];
        if (!isdigit(s[++i])) continue; 

        while (isdigit(s[++i]));

        continue;

    }

    s1[j++] = s[i++];
}
puts(s1);


The programs are confusing and ugly, but they're the best ones I ended up with. Please suggest a better algorithm or change mine to help it make more sense.
For input/output, it's generally better to work with strings rather than one character at a time with getchar() and putchar() — that is, if you can manage to write the code elegantly.  String-processing code would be more reusable, and it would likely avoid the overhead of repeatedly calling getchar() and putchar().

Note, however, that gets() is a deprecated function that you should never use because it offers no way to protect against buffer overflow.  Instead, use fgets() (which lets you specify a buffer size) or getline() (which automatically resizes the buffer).

Neither implementation is easy to follow.

The first version has calls to getchar(), putchar(), and isdigit() all over the place, as well as nested loops and mysterious flag variable.  Only the outer loop test for the '&amp;' terminator character, which seems wrong.

The second version increments i and j all over the place, and has nested loops (of which only the outer one tests for '&amp;').  It's clear that the output string will be no longer than the input, so it should be possible to reuse the original s buffer.

A better approach would be to have one loop that looks at each input character in turn.  The loop copies one character of input to the output per iteration, except when excess decimal precision is seen.  Instead of s[i] and s1[j], it would be easier to use char pointers named in and out.

/**
 * Overwrites string s with a string in which numbers are truncated after
 * some number of decimal places.  The input s may be terminated by a NUL
 * or an ampersand character.
 */
char *truncate_decimals(char *s, int max_places)
{
    int places = -1;
    char *out = s;
    for (char *in = s; *in != '\0' &amp;&amp; *in != '&amp;'; in++)
    {
        if (*in == '.')
        {
            places = 0;   // Decimal point encountered. Start counting places
        }
        else if (!isdigit(*in))
        {
            places = -1;  // Non-digit encountered. Resume normal copying
        }
        else if (places &gt;= 0 &amp;&amp; ++places &gt; max_places)
        {
            continue;     // Excess precision; don't copy
        }
        *out++ = *in;
    }
    *out = '\0';
    return s;
}