1

I'm doing some exercises from "C Programming Language" and can't figure out what is going on to give me certain output. Not really a roadblock because I got the output I wanted, but I don't understand why changing a certain piece of my code actually gave me the output I wanted. Was just looking for an explanation.

Here is the code that works the way I want it to. The part I am not understanding is the s[++i] = ' '; in the 'k' for loop. Before I used s[++i], I used:

s[i] = ' ';

++i;

Which would only put 1 space in the array, no matter how many times that k loop ran.

Then, just for testing, I placed ++i; above s[i] = ' '; and not a single space was included in my output.

#include <stdio.h>
#define MAXLINE 1000
#define TABSTOP 5

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


int main() {

  char c;
  int i, j;
  int modTabStop, numTabs, k;
  char s[MAXLINE];

  i = 0;
  while((c = getchar()) != EOF) {
    if(c == '\t') {
      modTabStop = i % TABSTOP;
      numTabs = TABSTOP - modTabStop;
      for(k = 0;k <= numTabs; ++k)
        s[++i] = ' ';
    }
    else if(c == '\n') {
      ;
    }
    else {
      s[i] = c;
      ++i;
    }
  }

  for(j = 0;j <= i;++j)
    printf("%c", s[j]);

  return 0;
}

I'm just wondering why s[++i] worked and none of the others did. My expected output is defined in the comment above the main function. But just for clarification, I was using the test string "the(tab)dog". When it works correctly, only 2 spaces should be placed in place of the tab in between "the" and "dog" because my tab stop is 5 and "the" is three letters long ("the(space)(space)dog"). If I put ++i; after s[i] = ' ', then I get a single space in between ("the(space)dog"). And if I place it before, I get no spaces ("thedog").

I just want to make sure I understand all this fully before moving on. Thanks guys!

klutt
  • 30,332
  • 17
  • 55
  • 95

3 Answers3

4

For starters this loop

  for(k = 0;k <= numTabs; ++k)
              ^^^

is incorrect. It should look like

  for(k = 0;k < numTabs; ++k)
              ^^^

In this case exactly numTabs spaces will be inserted in the array,

This assignment

    s[++i] = ' ';

is also incorrect because the character at the position i is not changed. The position is skipped due to the pre-increment operator ++i.

You should write instead

    s[i++] = ' ';

So finally the loop will look like

  for(k = 0;k < numTabs; ++k)
    s[i++] = ' ';

Pay attention to that this loop

while((c = getchar()) != EOF) {

is incorrect.

You should write instead

while( i < MAXLINE && ( c = getchar() ) != EOF && c != '\n' ) {

or at least like

while( i < MAXLINE && ( c = getchar() ) != EOF ) {

In the last case you should write within the loop

else if(c == '\n') {
  s[i++] = ' ';
}

Otherwise if you are entering several statements they will not be separated.

In the first case this if statement shall be removed.

And instead of the declaration

char c;

you should use the declaration

int c;

because the type char can behave as the type unsigned char (depending on the compiler options). And in this case the comparison c != EOF will be always true.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Vlad, thanks for all the help man. I’m going to copy all of that info into my notes and make those changes. Really appreciate you taking the time – ubernoob1010 Nov 01 '19 at 13:02
3

There's a major difference between

s[i]
i++;

and

s[++i]

Before explaining, let me simplify the first form into s[i++] so you have

s[i++]

and

s[++i]

which I believe makes things more clear, this is the difference between pre-increment and post-increment.

The difference is that pre-increment s[++i] increments the value of i before injecting it into the expression which is the array access operator in our case. While post-increment injects the value of i first into the array access operator, then increments it later on just like what you originally did in the expanded two lines form.

mohkamfer
  • 435
  • 3
  • 12
  • Thanks for the super quick reply! Ok the pre and post increment makes sense. But is there any reason why the two line form wouldn't work and the single line form would? That is what is most confusing to me. Like the ```s[++i]``` works in my code, but the two line form gives me the wrong/different output (1 space vs 2 spaces) – ubernoob1010 Oct 31 '19 at 13:21
  • Well if you want to use the two line form WHILE pre-incrementing, you have to do `i = i + 1` first then access the array with it – mohkamfer Oct 31 '19 at 13:23
  • 2
    @ubernoob1010 — did you include braces for the loop body when you tried the two statement form? Also, you assign to a different element of the array when you use the two statement form – Jonathan Leffler Oct 31 '19 at 13:26
  • Jonathan, no I totally forgot the braces and feel really dumb right now for posting this. I was messing with it for so long I guess I completely glossed over something so simple. Thanks for your help and sorry for wasting your time! – ubernoob1010 Nov 01 '19 at 13:00
1

Consider the code:

for(k = 0;k <= numTabs; ++k)
    s[i] = ' ';
    ++i;

this is equivalent to

for(k = 0;k <= numTabs; ++k){
    s[i] = ' ';
}
++i;

as only the first statement is in the for loop when using no braces.

This then means: write space to s[i] for numTabs-times, then increment i. Effectively writing one space.

Similar:

for(k = 0;k <= numTabs; ++k)
    ++i;
    s[i] = ' ';

would increment i for numTabs times and then write a space. This leaves numTabs characters of gibberish in the array and probably a terminating NULL.

The solution is simple: Use braces

Burdui
  • 1,242
  • 2
  • 10
  • 24
  • Yeah I'm suspecting this is what the OP did too, so the question is not about i++ vs ++i. – Lundin Oct 31 '19 at 13:40
  • Burdui, thanks for the answer. Sorry to waste your time with something so simple. Coming from a Python background so I completely forget the braces sometimes as I’m just starting to pick up C. That was definitely the issue. I just assumed there was a difference in s[++i] and the looping method. I appreciate all the help – ubernoob1010 Nov 01 '19 at 12:59