Is this an elegant way to initialize a variable for the first iteration of a loop?

118 views Asked by At

This is a C program that copies its input to its output, replacing each string of one or more blanks by a single blank. I don't know what is the best way to proceed when the program starts and there isn't a previous value yet.

I have come up with the following:

#include <stdio.h>

void main() {

        int actual, previous = -1;

        while((actual = getchar()) != EOF) {
                if(!(previous == ' ' && actual == ' ')) {
                        putchar(actual);
                        previous = actual;
                }
        }
}

This works, however I was taught that you should not initialize a variable to a random value. Another option would be to use a do-while loop, but then if the program gets an empty file it will go through the if statement for nothing.

3

There are 3 answers

2
Chris On

I would just set a boolean flag that can be checked and if we're not on the first iteration and the actual and previous character are both spaces we can skip printing the character and updating the previous char and setting the first_char flag to false.

This way previous is never used before being initialized.

#include <stdio.h>
#include <stdbool.h>

int main(void) {
    bool first_char = true;
    int actual, previous;

    while ((actual = getchar()) != EOF) {
        if (!first_char && previous == ' ' && actual == ' ') {
            continue;
        } 
        
        putchar(actual);
        previous = actual;
        first_char = false;
    }  

    return 0;
}
1
ad absurdum On

You can use an in_spaces variable to keep track of whether you are reading input while in a section of spaces or not. in_spaces is initialized to 0, or false, since you don't start out reading from a group of spaces.

If you are in a group of spaces and a space is read, just continue and read the next character. Otherwise you always want to print the character. If that character is a space, you are in a group of spaces so in_spaces should be set to 1, or true. Otherwise that character is not a space so you are not in a group of spaces and in_space should be set to 0.

#include <stdio.h>

int main(void) {
    int in_spaces = 0;
    int c;
    while ((c = getchar()) != EOF) {
        if (in_spaces && c == ' ') continue;
        putchar(c);
        if (c == ' '){
            in_spaces = 1;
        } else {
            in_spaces = 0;
        }
    }
}
2
Fe2O3 On

As already noted, void main() is ill advised...

If your concern is repeated spaces (0x20), then -1 is arbitrary. Equally arbitrary, but less jarring would be 0. (In fact, you could use any value except 0x20!)...

Collapsing your code into a for() loop reduces the amount of code. A helpful comment is always helpful. The testing code supplies several strings testing leading, trailing and mid-string runs of repeated SP's.

#include <stdio.h>

void test( char *str ) {
    putchar( '"' );
    for( int ch, prvCh = ~' '; (ch = *str++) != '\0'; prvCh = ch )
        if( prvCh != ' ' || ch != ' ' ) // suppress successive SP's as single.
            putchar( ch );
    putchar( '"' );
    putchar( '\n' );
}

int main(void) {
    test( "abc     def" ); // test middle SPSPSP
    test( " abc    def " ); // test single leading & trailing SP
    test( "   abc  def   " ); // test multiple leading & trailing SPs
    return 0;
}

Output:

"abc def"
" abc def "
" abc def "

Note the initialisation of prvCh as ~' '... Uncommon notation that expresses "a value that is not an SP".

The changes to use getchar() and EOF should be obvious and easy.