5
\$\begingroup\$

I'm currently reading the infamous K&R C book and trying to solve Exercise 1-20. My solution looks kind of too simple, but it works. I've searched the web for different solutions, but they all are much longer, although I didn't see any improvement compared to my code. Do you see anything which might compromise my approach? The exercise is as follows:

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?

And here's my solution:

#include <stdio.h>
#define COLS 8

int main (void)
{
    int ch;
    int charCounter = 0;

    while ((ch = getchar()) != EOF) {
        if (ch != '\t'){
            putchar(ch);
            charCounter++;
        }

        if (ch == '\t'){
            for (int i = 0; i < (COLS - (charCounter % COLS)); ++i) {
                putchar(' ');
            }
            charCounter = 0;
        }

        if (ch == '\n'){
            charCounter = 0;
        }
    }
}
\$\endgroup\$
4
\$\begingroup\$

Do you see anything which might compromise my approach?

  1. Good use of int ch; as the type returned by fgetc() is int and not char - avoided a rookie mistake.

  2. The if() layout looks weak. Suggest using else

    // current
    if (condition) {
    }
    if (!condition) {
    }
    
    // Suggest
    if (condition) {
    }
    else {
    }
    
  3. It is easier for people to understand == rather than !=. This is important for writing the correct code and maintaining it. So, when practical, avoid negation. Don't you think it is not a bit mis-understandable to negate the inverse of a sentence, No?

    if (ch == '\t') {
      for (int i = 0; i < (COLS - (charCounter % COLS)); ++i) {
        putchar(' ');
      }
      charCounter = 0;
    } else {
      putchar(ch);
      charCounter++;
    }
    
  4. The if (ch == '\n') is only possible when ch != '\t'. But this is minor. In a more complex code having this if() stand alone may be preferable.

    ...
    } else {
      putchar(ch);
      charCounter++;
      if (ch == '\n') {
        charCounter = 0;
      }
    }
    
  5. Then there is the missing return _something_;. With main(), lack of a return in the end will inject a return 0;. Should you do this or not is a coding style. One side says, no. Minimal code. The other side says - yes. Be explicit, it is poor practice to omit. The larger point here is that some "do/don't do" axioms are driven by your group's coding style. Following a consistent style is more important than being "right". If your group lacks a coding style, create one. This applies to all sorts of indentation, brackets or not, ++i or i++ issues.

  6. Pedantic code would avoid integer overflow from pathological long lines. Example:

     // charCounter++;
     charCounter = (charCounter + 1)%COLS;
    
     // i < (COLS - (charCounter % COLS)_;
     i < (COLS - charCounter);
    
  7. Clerical: Since the design document is "K&R C, Exercise 1-20.", that information should have been in code. Name and date is nice. It is your work, proudly sign it,

    /* K&R C,  Exercise 1-20. */
    /* Saalim  2016 Apr 5 */
    
    #include <stdio.h>
    ...
    

Should n be a variable or a symbolic parameter?

A more advance code would code some means to pass in a variable rather than a fixed tab stop of 8.

Very good initial post.

\$\endgroup\$

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.