Function Prototypes

The compiler reads your program from top to bottom, the way you read a book. When it gets to a function call, it must already know the function: its name, what it takes and what it returns. That is why we have been defining functions above main. This program has the function below main:

#include <stdio.h>

int main(void) {
    greet();
    return 0;
}

void greet(void) {
    printf("Hello!\n");
}

It doesn't compile:

main.c:4:5: error: call to undeclared function 'greet'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
    4 |     greet();
      |     ^
main.c:8:6: error: conflicting types for 'greet'
    8 | void greet(void) {
      |      ^
main.c:4:5: note: previous implicit declaration is here
    4 |     greet();
      |     ^
2 errors generated.

Start with the first error. On line 4, main calls the function greet, which hasn't been declared yet: nothing above line 4 has told the compiler that such a function exists. The rest of the line says that since C99, the version of C from 1999, the language doesn't allow implicit function declarations. Very old compilers used to guess what an unknown function looks like, and they often guessed wrong. The second error, conflicting types, only follows from the first one: the compiler made its own guess on line 4 (the note says so), and the real function on line 8 doesn't match it. When you fix the first error, the second one goes away too.

There are two ways to fix it. The first one you know: move the whole function above main. The second one is a function prototype above main: the first line of the function, with a semicolon at the end instead of the body:

#include <stdio.h>

void greet(void);

int main(void) {
    greet();
    return 0;
}

void greet(void) {
    printf("Hello!\n");
}

This program prints:

Hello!

The prototype void greet(void); is a declaration of the function. It tells the compiler: there is a function greet, it takes nothing and returns nothing, and its definition comes later. That is enough for the compiler to check the call. The prototype must match the definition: the same return type, name and parentheses. And the definition must really be there: with a prototype and no definition, the program doesn't run, and the error message ends with undefined symbol: greet, which means that the body of greet is missing.

Why write prototypes? In a long program, the prototypes at the top work like the table of contents of a book: you see all the functions at a glance, and main can come right after them. And you have been using prototypes since the first lesson without knowing it. The file stdio.h is a header file: it holds the prototypes of printf and other functions of the library, the collection of ready-made functions that comes with C. #include <stdio.h> inserts its contents into your program, so the compiler knows printf before you call it. In the same way, string.h declares strlen, and ctype.h declares toupper.

In this course, we will mostly write whole functions above main, because it's simpler. But when you see a prototype in a program, you will know what it is.

Instructions

The program doesn't compile, because main calls print_title, which is defined below it. Don't move the function. Instead, add its prototype above main. The program then prints the title and Press Start to play.

Below the function print_title, write a function void print_goodbye(void) that prints Thanks for playing!, and add its prototype above main, below the first one.

At the end of main, before return 0;, call print_goodbye. The program prints:

SPACE RACE
==========
Press Start to play.
Thanks for playing!

Start programming for free

By signing up, you agree to the Terms of Service and Privacy Policy.

Or sign up with:

3/12