2
\$\begingroup\$

Exercise 1-21. Write a program entab that replaces strings of blanks by the minimum number of tabs and blanks to achieve the same spacing. Use the same tab stops as for detab. When either a tab or a single blank would suffice to reach a tab stop, which should be given preference?

The code I wrote :

#include <stdio.h>
#include <ctype.h>

#define TAB 8 /* number of characters between two tab stops */

int main()
{
    int i, r, c;

    i = 0; /* number of space characters replaceable by a tab character */
    r = 0; /* number of unreplaceable characters since the last tab stop */

    while ((c = getchar()) != EOF)
    {
        if (c == ' ')
        {
            if (r + (++i) == TAB)
            {
                i > 1 ? putchar('\t') : putchar(' ');
                r = i = 0;
            }
        }

        else if (isspace(c))
        {
            while (i--)
                putchar(' ');
            
            putchar(c);
            r = i = 0;
        }

        else
        {
            for (r += i+1; i; i--) /* encountered a nonblank character, spaces are now unreplaceable */
                putchar(' ');
            
            putchar(c);

            r %= TAB;
        }
    }

    return 0;
}
\$\endgroup\$
1
  • \$\begingroup\$ What compiler, what C standard? \$\endgroup\$
    – Reinderien
    Aug 23, 2023 at 1:50

1 Answer 1

5
\$\begingroup\$

Review goals

Best to state them. I'll assume a general review.

What characters are blank and tab?

C has standard (the "C" locale) whitespaces including: space (' '), form feed ('\f'), new-line ('\n'), carriage return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').

Code treats space (' ') as blanks, which is reasonable.
C has a isblank() which is true for space (' '), and horizontal tab ('\t'), which is not suitable for this task. Good that it is not used.

Code treats the non-space whitespaces as tab and so r and i are set to 0. This is reasonable in the "C" locale. Yet else if (isspace(c)) deserves a comment expressing this since isspace() does not look like a tab test.

Advanced: Outside the "C" locale, other white spaces could be better treated as a space such as non-breaking space

Trailing blanks bug?

With input like "ab " (note no trailing '\n'), code outputs "ab", which is reasonable yet by strict reading of the requirements I'd say "ab " is expected.

Consider initialization at declaration time

//int i, r, c;
//i = 0;
//r = 0;

int i = 0;
int r = 0;
int c;

Good type choice

c is correctly an int and not a char to handle the 257 values from getchar() and is...() usage..

Variable names are quite terse

Instead of c, perhaps ch?
Instead of i, perhaps space_count?
Instead of r, perhaps TBD?

Re-word comment?

r = 0; /* number of unreplaceable characters since the last tab stop */ deserves re-wording. It is not only the last tab stop, but any non-space whitespace. I do not have a good alternative.

Implementation choice not explicit

Requirements have "When either a tab or a single blank would suffice to reach a tab stop, which should be given preference?", yet it take code analysis to determine what was done. An explicit comment is deserved.

Perhaps steer code via a macro to allow either approach.

Minor: Unpack side effects

if (r + (++i) == TAB) is OK.

I find the below more clear.

i++;
if (r + i == TAB)

Minor: style issues

Why the blank line between lines of code?

            putchar(c);

            r %= TAB;
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Kind of the opposite, but it's irrelevant in context so I deleted the comment \$\endgroup\$
    – Reinderien
    Aug 24, 2023 at 0:50

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.