getword that properly handles undersores, string constants, comments, or preprocessor control lines
I don't didn't immediately see a bug in it and you're doing a lot of things well; so some minor comments.



while(isspace((c = getch())))
    ;


This will often cause a compiler warning "possible missing or empty statement". If you use a compound statement instead that may suppress that warning:

while(isspace((c = getch()))) { }




int ordinaryKeyWord = 0;
int comment         = 0;
int stringConstant  = 0;


These are mutually exclusive, so a 3-valued enum might be better.



for(; --lim; w++)


I don't think your lim testing is strict enough: for example if lim is 8 then /*this*/ would overrun (write past the end of) the input buffer; even an ordinaryKeyWord will write its last '\0' past the end of the buffer.



return *--w;


That's a bit tricky. It would be clearer to return word[0]; everywhere consistently.



    if(ordinaryKeyWord &amp;&amp; (!isValidKeyWord(*w))) {
        ungetch(*w);
        break;
    }


That's compact (few lines) but could be expanded to make the logic clearer for a tired reviewer:

    if(ordinaryKeyWord) {
        if (isValidKeyWord(*w)) {
            continue;
        }
        ungetch(*w);
        break;
    }
    if (stringConstant) {
        ... break or continue ...




else if(c == '/') {
    *w++ = c;
    c = getch();
    if(c == '*') {
        *w++ = c;
        comment = 1;
    }
    else {
        *w = '\0';
        return *--w;
    }


You're missing ungetch in the else case.



Is there any way to show end-of-input: pressing &lt;Ctrl&gt;-D for EOF for example? If so, how does getword signal that?



I don't know an easy way to automate code which reads from the keyboard using getch and ungetch.

That's a pity because I'd like to see the automated unit tests which define how well your code works.

For example, this question includes its unit tests: 6 different tests of the function being coded. I was able to identify one or two bugs in the function, not by reading the function but by reviewing the set of unit tests, to find a condition (a set of input data) that wasn't being tested.

My boss wasn't a programmer but used to user-acceptance-test the software before shipping it: he said, not 'you get what you expect' but "You get what you INspect".

Especially when you're beginning you should learn to do unit testing, and take pride in constructing a good/complete set of test cases, which is able to detect bugs in the earlier versions of your software.