4

I'm working through K & R to learn programming. Going well so far, but I'm unclear about the role of a line of code from section 1.8 (functions).

In section 1.8, the authors show you how to create a function to raise one integer to the power of another integer.

I've pasted the code below, as it was written in the book. Everything outputs fine. But I don't know why they've included this line at the top:

int power(int m, int n);

The book doesn't mention it, apart from saying that the program will raise integer m to the power n. If I remove the line from the code, the program still outputs as it should.

If I understand this correctly, the line

int power(int base, int n)

creates the function, and the braces underneath define the function. Then the braces under main call the function to output the chart.

So all that seems to make sense. But I don't see what the very top line does.

It could be extraneous, but it seems far more likely that I'm missing something. Can anyone enlighten me as to why that line is there?

#include <stdio.h>

int power(int m, int n);

/* test power function */
main()
{
int i;

    for (i = 0; i < 10; ++i)
        printf("%d %d %d\n", i, power(2,i), power(-3, i));
    return 0;
}

/* power: raise base to n-th power; n >= 0 */

int power(int base, int n)
{
    int i, p;

    p = 1;
    for (i = 1; i <= n; ++i)
        p = p * base;
    return p;
}
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
Graeme
  • 1,107
  • 2
  • 10
  • 11

6 Answers6

9

The first line is the declaration of the function. The block of code at the bottom is the definition of the function.

Starting with the 1999 version of the ISO C standard, it's illegal (a constraint violation) to call a function without a visible declaration; the declaration must precede the call.

For a simple program like this one, you could just write the full definition of power() before the definition of main() (since a definition also provides a declaration), but for more complex cases (such as recursive calls) you often need to provide a separate declaration.

For larger programs, it's common to collect all the function declarations in a header file (foo.h, for example), and the corresponding definitions in a source file (foo.c, for example). A #include "foo.h" directive is used to make the declarations visible in other files. You'll see that kind of thing later in the book.

(In the 1990 and earlier versions of C, which is what K&R2 covers, there are cases where you can call a function without a visible declaration -- but it's still a very good idea to provide explicit declarations anyway.)

Incidentally, the declaration of the main program should really be int main(void) rather than just main().

Terminology: a "prototype" is a function declaration that specifies the types of the parameters.

int power(int base, int n);    /* a declaration that's also a prototype */
int power(int, int);           /* likewise */
int power();                   /* a declaration but not a prototype */

(Parameter names are required in a definition, but optional in a standalone declaration.)

As a special case, a prototype for a function with no parameters uses (void), since empty parentheses already mean a non-prototype declaration. So int main(void) is a prototype, but int main() isn't.

Non-prototype declarations are "obsolescent", meaning that they could in theory be removed from a future language standard. But they've been obsolescent since 1989, and even in the new 2011 ISO C standard the committee hasn't seen fit to remove them.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Note: leaving the return type off `main` works probably for the same reason that leaving off the declaration works for OP, in olden times, C had the 'implicit int' rule, if no type was specified, it was implicitly assumed to be `int`. So the implicit type of `power` matches its real type, thus it worked (still works on many if not most compilers due to backwards compatibility). – Daniel Fischer Jan 11 '12 at 22:16
  • @DanielFischer: That's true in C90 and earlier (I deliberately glossed over that); the "implicit int" rule was dropped in C99. It's still not a good idea to take advantage of it. – Keith Thompson Jan 11 '12 at 22:17
  • Yeah, that's why I said "in olden times". – Daniel Fischer Jan 11 '12 at 22:19
  • That makes sense. Thanks. So the program still ran because the compiler found the definition, took it as a declaration, and everything worked out because power() was used as an int? But, this only worked because my compiler was backwards compatible? Also, thanks for the tip on main(void). I was following what they wrote in the book; perhaps that convention didn't exist when it was published. – Graeme Jan 11 '12 at 22:27
  • The program as it appears in your question ran because you have an explicit declaration for `power()` -- and it's compatible with the definition that appears later. But if you delete the declaration, it still works as long as the compiler doesn't strictly enforce the new rules imposed by the 1999 ISO C standard. (BTW, there's an even newer 2011 ISO C standard, but there are no implementations of it yet.) – Keith Thompson Jan 11 '12 at 22:45
  • Non-prototype declarations actually have some modern uses. For instance: `extern const int foo_arg_cnt, foo(); if (foo_arg_cnt==2) return foo(bar, bah); else if (foo_arg_cnt==1) return foo(bar); else abort();` This code is valid in a translation unit that has no way of knowing internally which prototype is correct for `foo`. – R.. GitHub STOP HELPING ICE Jan 12 '12 at 01:29
  • @R..: Perhaps. Personally, I don't think they're worth the cost (other that for backwards compatibility, and that can be handled by compilers continuing to suppport older standards). C++ gets along fine without non-prototype declarations. – Keith Thompson Jan 12 '12 at 01:31
  • @Keith: Note that a similar effect can be obtained with function pointers and casting to and from a prototype-mismatched function pointer type, so I agree this use is not really a justification for keeping them. – R.. GitHub STOP HELPING ICE Jan 12 '12 at 03:39
2
int power(int m, int n);

is a declaration of the power function in its prototype form. A function declaration informs the compiler of the number of parameters the function has, the type of the function parameters and the type of the function return value.

In C you cannot use a function identifier before it has been declared.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • "It is declared because you cannot call a function in C before it has been declared" - not true. There are peculiarities calling such functions, but it is legal (that's why OP's example works without the prototype as well). – jpalecek Jan 11 '12 at 21:58
  • @jpalecek could you expand, please? Since C99, implicit function declarations are no longer allowed and a definition of a function is a declaration of the function that includes the function body. – ouah Jan 11 '12 at 22:00
  • @jpalecek "OP's example works without the prototype as well". Well, without the function prototype the OP's program would be no longer valid. – ouah Jan 11 '12 at 22:02
  • Yes, but kn K&R, it was allowed. I guess the OP isn't using a c99 compiler. – jpalecek Jan 11 '12 at 22:05
  • He wrote: "If I remove the line from the code, the program still outputs as it should." – jpalecek Jan 11 '12 at 22:06
  • If you're trying to call a function that isn't declared, doesn't the compiler assume it's a function returning `int` taking any number of arguments? Edit: Never mind, read about C99 – tangrs Jan 11 '12 at 22:06
2

It's a forward declaration which makes the function interface public as the function is used before it is actually implemented below main().

Header files, which you #include provide a similar functionality of making the callable API public---but the code is then commonly supplied in a library rather than via the same compilation unit as it is here in this single-file example of the K&R Intro chapter.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
1

If you don't include that line at the top, when the program reaches power(2,i) in main power has not been declared yet. Programs are read from top to bottom, and by putting the declaration at the top, the compiler knows that "a definition is coming".

Jesse Good
  • 50,901
  • 14
  • 124
  • 166
1

That line is just the function prototype. It's a forward declaration that allows code to be able to use some function with that signature that will exist when everything is linked together. Without it, the main() function will attempt to use the power() function but the compiler is not aware of it yet since it isn't actually defined later in the source file.

Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
0

That line at the top that you are referring to is a function prototype. The ONLY thing it is there for is so that the compiler can check your work, that is, to make sure you are using the function correctly by passing the right types and number of arguments. That's all it is for. That is why you can remove it and the code still compiles - all you are doing by removing it is removing the compiler's reference so it can't check your work. And if you do remove it, then there is the possibility that you could pass the wrong type of argument(s) and cause a hard to find run time error or program crash. But leaving it in allows the compiler to flag such an error at compile time saving you some grief. And saving someone some grief is a good thing.

Later, with the C99 standard, they decided to make it mandatory to provide a function prototype (or else define the function first) in order for the code to compile, thus forcing you to let the compiler check your work.