4
\$\begingroup\$

I'm learning C with K&R 2nd Ed. I've just completed the exercise 1-20 and I would know if my code is correct (i.e. answering the question) and if my style is not too bad. Or just some feebacks to improve myself!

K&R Exercise 1-20 p.34

Write a program detab that replaces tabs in the input with the proper number * of blanks to space to the next tab stop. Assume a fixed set of tab stops, say every n columns. Should n be a variable or a symbolic parameter?

More info here

I put '-' because it's more readable than ' '. But you can totally change it.

#include <stdio.h>
#define COLUMN 8

int main()
{
    int c, i, nc;
    nc = 0;

    while ((c = getchar()) != EOF)
    {
        if (c != '\t' && c != '\n')
            nc = (nc + 1) % COLUMN;

        if (c == '\n')
            nc = 0;

        if (c == '\t') {
            for (i=1; i<=(COLUMN - nc); ++i) {
                putchar('-');
            }
            nc = 0;
        }
        else
            putchar(c);
    }

return(0);
}
\$\endgroup\$

migrated from stackoverflow.com Feb 13 '15 at 11:46

This question came from our site for professional and enthusiast programmers.

  • 1
    \$\begingroup\$ I think K&R style would put the { on the same line as the while. Also, K&R doesn't put parentheses around a return value. And return should have four spaces in front of it, like the rest of your main function. \$\endgroup\$ – S. Morgenstern Feb 12 '15 at 22:59
  • 1
    \$\begingroup\$ AFAIR they dropped parantheses for return statement in second edition. There is really no need for them. \$\endgroup\$ – Grzegorz Szpetkowski Feb 12 '15 at 23:02
  • \$\begingroup\$ K&R would also do i = 1; i <= (..., rather than without spaces like you wrote it. All of this only applies if you want to write K&R style, rather than something else. \$\endgroup\$ – S. Morgenstern Feb 12 '15 at 23:05
1
\$\begingroup\$

Here is an alternate algorithm:

while ((c = getchar()) != EOF) {
    switch (c) {/* switch instead of if-else... */
    case '\n':
        nc = 0;
        putchar(c);
        break;
    case '\t':
        for (i = COLUMN - nc % COLUMN, nc += i; i > 0; --i) {
            putchar('-');
        }
        break;
    default:
        ++nc; /* increment is faster than increment plus divide */
        putchar(c);
        break;
    }
}

nc keeps track of the current column position within the line.

\$\endgroup\$
  • \$\begingroup\$ this line: 'for (i = COLUMN - nc % COLUMN, nc += i; i > 0; --i) {' might be a problem, as there is no guarantee in C on the order of evaluation and this line uses a side effect, the result of nc could windup being incorrect. It is not a good idea to depend on presidence when performing a calculation (use parens) \$\endgroup\$ – user3629249 Feb 12 '15 at 23:40
  • \$\begingroup\$ @Mahé when the loop starts, i is assigned the number of spaced to add. And because the same value needs to be added to nc, it is done right there (after comma). Setting nc to 0 would also work, but I've decided not to break semantics when nc is a position inside the line, not tab offset counter. \$\endgroup\$ – Valeri Atamaniouk Feb 12 '15 at 23:42
  • \$\begingroup\$ @user3629249 I believe you confuse comma operator and function parameter list evaluation. \$\endgroup\$ – Valeri Atamaniouk Feb 12 '15 at 23:46
  • \$\begingroup\$ @ValeriAtamaniouk ok thanks, sorry I delete my question because I thought it was stupid, but visibly not, your answer help me! \$\endgroup\$ – Mahé Feb 12 '15 at 23:47
  • \$\begingroup\$ @ValeriAtamaniouk Indeed the if-else is not here very practice because I have to write a third case like : else if (c != '\t' && c != '\n'). But I should not know the "switch" structure yet! :) Thanks for your feedback and for (i = COLUMN - nc % COLUMN, nc += i; i > 0; --i) line \$\endgroup\$ – Mahé Feb 13 '15 at 0:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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