3
\$\begingroup\$

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 '&'.

With the getchar and putchar functions:

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

    if (isdigit(c) && !(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] != '&')
{
    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.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

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 '&' 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 '&'). 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' && *in != '&'; 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 >= 0 && ++places > max_places)
        {
            continue;     // Excess precision; don't copy
        }
        *out++ = *in;
    }
    *out = '\0';
    return s;
}
\$\endgroup\$
0
\$\begingroup\$

This is bad... Partially because of very bad and unreadable style of the code, partially because of very vague problem definition.

You didn't specified what to do with incorrect strings (-2a.2345) for example?

I'm not ready to provide you with a clean code that does your problem yet, but I'd like to point couple places where you can improve:

  • Name your variables properly. I can agree with c being current character you're processing, but not with _c and flag. They should be called something like lastChar and insideFloat if I understand your algorithm correctly.

  • Separate logic to process float number into a separate function. Clearly define what that function should do in case of invalid input.

  • Refactor two digits skipping code into a loop with a counter of digits.

Post updated question and we will go from there.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.