0

I'm trying to write a program that takes from the standard input stream a sentence, and based on the definition that a word is everything that is between "spaces"; "spaces" being the space character, tab character or newline character, so, for example, if the input stream is hey there this is some test, the output should be

hey
there
this
is
some
test

Here is my try:

#include <stdio.h>

#define TRUE 1
#define FALSE 0

#define IS_SPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')

int main() {

    for(int c, inWord = FALSE; (c = getchar()) != EOF;)
        if(!IS_SPACE(c)) {
            putchar(c);
            inWord = TRUE;
        }
        else if(inWord) {
            putchar('\n');
            inWord = FALSE;
        }

    return 0;
}

But I don't like this approach because I am manually entering TRUE and FALSE to inWord when it can be automatically be done by inWord = !IS_SPACE(c), but I don't know how to modify the code to make just one call to IS_SPACE without creating another temporal variable.

Garmekain
  • 664
  • 5
  • 18
  • why don't just use [`isspace`](https://en.cppreference.com/w/c/string/byte/isspace)? – phuclv Jul 15 '18 at 15:42
  • @phuclv I'm actually doing the examples of Ritchie and Kernighan's book and I want to use only the things that they introduce until that point, so that I master the basics. That's why I don't want libraries. – Garmekain Jul 15 '18 at 15:48
  • 1
    You cannot do this without at least 1bit of *state*; to decide on the new state, the program needs to remember the previous state. (but: you could cheat by using recursion) – wildplasser Jul 15 '18 at 15:56
  • ... but actually the state *bit* is only needed to decide what needs to be output. – wildplasser Jul 15 '18 at 16:11
  • 1
    K&R is so old that occasionally you'll find some odds [like this](https://stackoverflow.com/q/32652213/995714). Probably it's better to use a modern C book – phuclv Jul 16 '18 at 02:00
  • @phuclv Any good modern C book? – Garmekain Jul 16 '18 at 11:26

2 Answers2

1
int  my_spaces[256] = { 0 };
my_spaces[' '] = my_spaces['\t'] = my_spaces['\n'] = 1;
#define MY_SPACE(c) (my_sapces[c])

This is the core of how isspace() and friends are often implemented but with bits for isspace(), isprint(), ....

Old answer before your edit: Look at strtok, though strtok_r is now my function of choice. Being built into C you can expect it to be optimized for the current implementation.

Gilbert
  • 3,740
  • 17
  • 19
1

The bug is that it doesn't print the last '\n' if the text ends with nonspace. Or maybe it is a feature? I did not fix it.

As to your question, you may do

for(int c, inWord=FALSE; (c = getchar()) != EOF;) {
    if(!IS_SPACE(c))
        putchar(c);
    else if(inWord)
        putchar('\n');
    inword = !IS_SPACE(c);
}

or even

for(int c, bPrevInWord = FALSE; (c = getchar()) != EOF;) {
    int bInWord = !IS_SPACE(c);
    if(bInWord)
        putchar(c);
    else if(bPrevInWord)
        putchar('\n');
    bPrevInWord = bInWord;
}
user31264
  • 6,557
  • 3
  • 26
  • 40
  • Not to be rude, but, your first example calls two times IS_SPACE, and your second one uses two temporal variables, which I explicitly excluded these. – Garmekain Jul 15 '18 at 16:00
  • 2
    Your action depends on whether `c` is nonspace AND whether the previous character is nonspace. So you need either two temporal variables or two calls to IS_SPACE, you probably cannot avoid this. (But, regarding two IS_SPACE calls, don't worry about efficiency, any compiler will optimize them away.) – user31264 Jul 15 '18 at 16:08
  • That's exactly what I've thought, but maybe anyone of you had a different point of view. Apparently not. Thanks. – Garmekain Jul 15 '18 at 16:13
  • 1
    Actually I tried the 3 versions(mine and the two yours) and the compiler does not optimize yours, in total my code takes 32 lines of asm, and yours 43 and 37 respectively. https://godbolt.org/g/c55JR8 – Garmekain Jul 30 '18 at 14:55