Menu

C Syntax: The Structure of a C Program Explained

Every C program has the same skeleton: includes, a main function, statements ending in semicolons, and blocks in braces. Here is what each part does and the rules the compiler actually enforces.

This page includes runnable editors - edit, run, and see output instantly.

C has very little syntax to learn - about 32 keywords and a handful of punctuation rules. Almost every program you will ever write has the same outer shape, so it is worth taking that shape apart once and carefully.

The Smallest Complete Program

This compiles, runs, and does nothing:

No includes, no output, no boilerplate class or module. main is the entry point: when the operating system starts your program, it calls main. When main returns, the program ends, and the value it returns is the exit status.

Add output and you need one include:

Preprocessor Directives

Lines beginning with # are handled before compilation proper, by the preprocessor. They are not C statements, and they take no semicolon.

#include <stdio.h>    /* standard library header - angle brackets */
#include "myutils.h"  /* your own header - quotes, searched locally first */
#define MAX 100       /* a macro - MAX is replaced by 100 everywhere below */

#include is a literal text paste: the entire contents of the named file are dropped in at that point. stdio.h contains the declaration of printf, which is how the compiler knows what arguments printf takes. Leave the include out and you get implicit declaration of function 'printf'.

The angle-bracket versus quote distinction is about where the compiler searches: <...> means the system include directories, "..." means look next to this file first.

The main Function

int main(void) {
    return 0;
}

Four parts, each meaningful:

  • int - main's return type. The value goes to the operating system as the exit status, where 0 means success.
  • main - the reserved name the runtime calls. Every hosted C program has exactly one.
  • (void) - the parameter list. void here means "takes no arguments." Writing main() instead is legal but weaker: empty parentheses in C mean "unspecified parameters," which disables argument checking.
  • { ... } - the function body.

The other standard form takes command-line arguments:

int main(int argc, char *argv[]) { ... }

Use int main(void) until you need them.

Statements and Semicolons

A statement is a single instruction, and it ends with a semicolon.

Four statements, four semicolons. The semicolon is a terminator, not a separator - the last statement in a block needs one too.

What does not take a semicolon:

#include <stdio.h>        /* preprocessor line - no semicolon */

int add(int a, int b) {   /* function definition header - no semicolon */
    return a + b;
}                         /* closing brace of a function - no semicolon */

if (x > 0) {
    ...
}                         /* closing brace of a control block - no semicolon */

The one case that bites everyone is a semicolon where a body should be:

if (score > 90);              /* BUG: this ; is the entire if body */
    printf("Excellent!\n");   /* always runs, whatever score is */

That is perfectly legal C. The if controls an empty statement, and the printf is just the next line in sequence. -Wall warns about it; the compiler will not stop you.

Blocks and Braces

Curly braces group statements into a block, which counts as one statement wherever a statement is expected.

Braces are optional when the body is a single statement, but omitting them is how the famous bugs happen - add a second line later and it silently leaves the if. Use braces always.

Blocks also create scope: a variable declared inside { ... } stops existing at the closing brace.

Case Sensitivity and Whitespace

C is case sensitive everywhere. total, Total, and TOTAL are three separate names. Every keyword is lowercase, so Int, Return, and Printf are all errors - and the error message for Printf is confusing, because the compiler assumes you meant some function it has never heard of.

Whitespace, by contrast, is almost entirely free. The compiler treats any run of spaces, tabs, and newlines as one separator. This is valid:

int    main ( void )
{
    printf
    ( "Hello\n" ) ;
    return 0 ;
}

So is this:

int main(void){printf("Hello\n");return 0;}

Both compile identically. Since the compiler does not care, formatting is entirely for humans - and the conventional layout (one statement per line, four spaces or one tab per nesting level, opening brace on the same line) is worth following because every C codebase you read will use something close to it.

Two places whitespace does matter: you cannot split a keyword or identifier (in t is not int), and you cannot put a newline inside a normal string literal.

Identifiers: Naming Rules

An identifier is any name you choose - variables, functions, types. The rules:

  • Made of letters, digits, and underscores.
  • Must not start with a digit. total2 is fine, 2total is not.
  • Cannot be a keyword: no variable called int, for, or return.
  • Case matters.
  • Names starting with an underscore, and anything with two underscores in a row, are reserved for the implementation - do not invent them.
int score;        /* good */
int total_items;  /* good - snake_case is the C convention */
int _hidden;      /* legal but reserved - avoid */
int 2fast;        /* error */
int float;        /* error - keyword */

A Fully Annotated Program

Everything above, in one place:

Reading order matters here: with_tax is defined before main uses it. C reads the file from top to bottom, so a function must be declared before it is called. Define it earlier, or write a function prototype at the top and define it later.

Frequently Asked Questions

What is the basic structure of a C program?

Preprocessor directives first (#include <stdio.h>), then function definitions, one of which must be main. Inside a function, statements end with semicolons and blocks are wrapped in curly braces. A minimal program is #include <stdio.h> plus int main(void) { return 0; }.

Why is it int main(void) and not just main()?

int is main's return type - the exit status the program hands back to the operating system. (void) says explicitly that main takes no arguments. Writing main() with empty parentheses is an older style that tells the compiler nothing about the parameters, so it does less checking.

Do all C statements need a semicolon?

Every statement does, but not every line. Preprocessor directives (#include, #define), function definitions, and the closing brace of a block or if/for/while do not take one. A stray semicolon after if (x) is legal C and silently makes the body run unconditionally.

Is C case sensitive?

Yes, completely. count, Count, and COUNT are three different identifiers, and Int is not the keyword int. Every C keyword is lowercase, so a capital letter in Return or Printf produces an error.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED