2

In chapter 6.3 of K&R the function getword() is defined like this:

int getword(char *word, int lim)
{
    int c, getch(void);
    void ungetch(int);
    char *w = words;

    while(isspace(c=getch()))
        ;
        if(c!= EOF)
            *w++; = c;
        if(isalpha(c)) {
            *w = '\0';
            return c;
        }

        for(;--lim > 0; w++)
            if(!isalnum(*w)getch()){
                ungetch(*w);
                break;
            }
        *w = '\0';
        return word[0];
}

I don't understand the syntax of the line

int c, getch(void);

it is the first time I'm seeing this. Why is it declaring a function as int? Shouldn't be enough to insert prototypes of functions before calling them?

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • The original code from K&R is complete trash, one does not write modern C programs like this. Nothing to learn here except bad habits. I'd strongly recommend getting a better book. – Lundin Oct 14 '19 at 10:49
  • @Lundin Can you please recommend some modern C books for beginner and Advanced level. – EsmaeelE Oct 14 '19 at 10:54
  • 2
    Neither the K&R book nor the code fragment in question is "complete trash". @Lundin has an unreasonable bias here. – Steve Summit Oct 14 '19 at 11:15
  • @EsmaeelE Stack Overflow has a [book list](https://stackoverflow.com/questions/562303/the-definitive-c-book-guide-and-list). – Steve Summit Oct 14 '19 at 11:17
  • @SteveSummit 1)There is never a reason to declare prototypes inside functions, 2) particularly not on the same line as variables. 3) Assignment inside control statements are bad practice. 4) Mixing ++ together with assignment is bad practice. 5) Multiple return or break jumping here and there is unreadable. 6) There is no reason to use `lim` as iterator instead of `(i=0; i – Lundin Oct 14 '19 at 11:55
  • @Lundin Not gonna get into a back-and-forth here, and some of your points are fair, but if by(3) you mean putting `c = getch()` inside the controlling expression of a `while()`, and if by (4) you mean `*w++ = c`, both of those are absolutely idiomatic C, and they have significant benefits beyond parsimony, so they're definitely not problems; anyone who has problems with them either needs to learn the idioms and understand their benefits, or abandon C. – Steve Summit Oct 14 '19 at 13:10
  • @SteveSummit Definitely not gonna debate "Yoda conditions". Beating the dead horse. But feel free to point out a mainstream compiler which doesn't warn against assignment inside conditions. – Lundin Oct 14 '19 at 13:17
  • @Lundin I know of no mainstream compiler that will warn about `while(isspace(c=getch()))`, or the more conventional `while((c = getchar()) != EOF)`. – Steve Summit Oct 14 '19 at 13:23

1 Answers1

4

Think of the line

int c, getch(void);

as being equivalent to

int c;
int getch(void);

That is, it's a declaration of an int variable named c, followed by a prototype for a function named getch taking no arguments and returning int.

As this example shows, there's no hard line between "declarations" and "function prototypes" in C. A function prototype is merely a declaration, that declares a function type, that includes the types of its arguments.

It's mildly unusual, but not at all wrong, to declare a function prototype with local scope like this. Normally, a function prototype is declared "at the top" of a source file, with global scope, outside of any function. (In fact, normally, function prototypes are declared in header files.)

Why is it declaring a function as int?

Well, because the getch function does return int.

Shouldn't be enough to insert prototypes of functions before calling them?

Yes, and that's exactly what this like is doing -- this line does contain a function prototype, which declares the getch function before calling it.

The bottom line is that every function declaration in C is "external", whether it appears inside or outside a function, whether it contains the storage-class specifier extern or not.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103