C Syntax & Structure
Master the fundamental syntax rules of C programming. Learn about statements, blocks, comments, identifiers, keywords, and the building blocks that form every C program.
Basic Program Structure
Every C program follows a consistent structure that the compiler expects. At minimum, you need preprocessor directives to include necessary headers, the main() function where execution begins, and statements that perform actual work. This structure isn't arbitrary - it reflects how C programs are compiled and executed at the system level.
C is a case-sensitive language, meaning Main, main, and MAIN are three different identifiers. The entry point must be exactly main (lowercase). Similarly, printf is not the same as Printf or PRINTF. This strictness helps prevent subtle bugs but requires careful attention to capitalization.
/* Basic C program structure */
#include <stdio.h> // Preprocessor directive (no semicolon)
int main(void) { // Function declaration
// Statements go here
printf("Hello!\n"); // Statement (ends with semicolon)
return 0; // Return statement (ends with semicolon)
} // Closing brace (no semicolon)
/* Multiple functions */
#include <stdio.h>
void greet(void) { // Helper function
printf("Welcome!\n");
}
int main(void) {
greet(); // Call helper function
return 0;
}Statements and Semicolons
In C, a statement is a complete instruction that performs an action. Most statements end with a semicolon, which acts as a statement terminator (not separator). The semicolon tells the compiler "this instruction is complete." Forgetting semicolons is one of the most common beginner errors, resulting in confusing compiler messages.
Not everything needs a semicolon. Preprocessor directives (#include, #define) don't use semicolons because they're not C statements - they're instructions to the preprocessor. Function definitions, struct/union/enum declarations, and control flow blocks (if, while, for) use braces instead of semicolons to mark their boundaries.
/* Statements requiring semicolons */
int x = 5; // Variable declaration
printf("Hello\n"); // Function call
x = x + 1; // Assignment
return 0; // Return statement
/* Things that DON'T use semicolons */
#include <stdio.h> // Preprocessor directive
#define MAX 100 // Macro definition
int main(void) { // Function header
if (x > 0) { // Control flow
printf("Positive\n"); // Statement inside DOES have semicolon
} // Closing brace - no semicolon
} // Closing brace - no semicolon
/* Common semicolon mistakes */
if (x > 0); // WRONG: semicolon here means empty statement
{
printf("This always runs!\n"); // Not part of if!
}
for (int i = 0; i < 10; i++); // WRONG: semicolon makes loop body empty
printf("Only prints once!\n"); // Not part of loop!Blocks and Braces
Curly braces { } create code blocks - groups of statements treated as a single unit. Blocks define scope: variables declared inside a block only exist within that block. They're also used to group multiple statements where C syntax expects a single statement, like in if conditions or loops.
Indentation helps humans read code but means nothing to the compiler. The braces determine structure, not indentation. However, proper indentation is crucial for readability - misindented code can make you think the structure is different from reality, leading to bugs.
/* Block defining scope */
{
int x = 10; // x exists only in this block
printf("%d\n", x); // OK: x is visible
}
// printf("%d\n", x); // ERROR: x doesn't exist here
/* Nested blocks */
{
int x = 10; // Outer x
{
int x = 20; // Inner x (shadows outer)
printf("%d\n", x); // Prints 20
}
printf("%d\n", x); // Prints 10 (outer x)
}
/* Blocks in control structures */
if (x > 0) {
printf("Positive\n");
printf("Value: %d\n", x);
x = 0;
} // Multiple statements need braces
if (x > 0)
printf("Single statement - braces optional\n");
// But always use braces for clarity and safety:
if (x > 0) {
printf("Always better with braces\n");
}Comments
Comments document your code for other programmers (including future you). The compiler ignores comments completely - they exist only for humans. C supports two comment styles: traditional multi-line comments (/* */) from the original C, and single-line comments (//) adopted from C++ in the C99 standard.
Good comments explain WHY code does something, not WHAT it does. The code itself shows what it does; comments should provide context, rationale, or warnings about non-obvious behavior. Over-commenting obvious code creates noise, while under-commenting complex logic leaves future maintainers confused.
/* Multi-line comment style
Can span multiple lines
Used since original C */
// Single-line comment (C99 and later)
// Each line needs its own //
/* Good comments - explain WHY */
// Calculate factorial iteratively to avoid stack overflow
int factorial(int n) {
int result = 1;
// Using iteration instead of recursion for large n
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
/* Bad comments - state the obvious */
i = i + 1; // Add 1 to i (obvious from code)
int x; // Declare x (obvious from code)
/* Useful comments */
// FIXME: Handle negative input
// TODO: Optimize for large arrays
// HACK: Temporary workaround for bug #1234
// WARNING: This function is not thread-safe
// NOTE: Must be called after initialize()
/* Comments can't be nested */
/*
/* This is an error */
Trying to nest comments doesn't work
*/
// But single-line comments can appear anywhere
int x = 5; // Inline comment
// Multiple // lines
// are fineIdentifiers and Keywords
Identifiers are names you give to variables, functions, and other entities in your program. They must start with a letter (A-Z, a-z) or underscore (_), followed by letters, digits (0-9), or underscores. C is case-sensitive, so myVariable, MyVariable, and myvariable are all different.
Keywords are reserved words with special meaning in C. You cannot use them as identifiers. C has 32 keywords in the original standard, with a few more added in C99 and C11. These keywords form the core language syntax and are recognized by all C compilers.
/* Valid identifiers */
int count;
int my_variable;
int myVariable; // camelCase
int MyVariable; // PascalCase
int _private;
int variable123;
/* Invalid identifiers */
int 123variable; // Can't start with digit
int my-variable; // Hyphens not allowed
int my variable; // Spaces not allowed
int int; // 'int' is a keyword
/* C keywords (cannot be used as identifiers) */
// Data types:
int, char, float, double, void, short, long, signed, unsigned
// Control flow:
if, else, switch, case, default, for, while, do, break, continue, return, goto
// Storage classes:
auto, register, static, extern
// Other:
struct, union, enum, typedef
sizeof, const, volatile
// C99 added: inline, restrict, _Bool, _Complex, _Imaginary
// C11 added: _Alignas, _Alignof, _Atomic, _Static_assert, etc.
/* Identifier naming conventions */
// Functions and variables: lowercase with underscores
int calculate_total(void);
int user_count;
// Constants: UPPERCASE with underscores
#define MAX_SIZE 100
#define PI 3.14159
// Type names: Often use typedef with _t suffix or PascalCase
typedef struct {
int x, y;
} point_t;Whitespace
C ignores whitespace (spaces, tabs, newlines) outside of strings and character constants. You can use whitespace freely to format code for readability. However, whitespace is required between tokens that would otherwise be ambiguous, like "int x" (whitespace required) vs "intx" (identifier).
/* These are all equivalent */
int main(void){return 0;}
int main(void) { return 0; }
int main(void)
{
return 0;
}
int main ( void )
{
return 0 ;
}
/* But this is an ERROR - missing required space */
intmain(void){return 0;} // "intmain" not recognized
/* Good formatting */
int x = 5;
int y = 10;
int result = x + y;
/* Legal but unreadable */
int x=5;int y=10;int result=x+y;Expression vs Statement
An expression produces a value: 2 + 3 is an expression that evaluates to 5. A statement performs an action and typically ends with a semicolon. Many expressions can become statements by adding a semicolon (expression statement). Understanding this distinction helps you reason about C code.
/* Expressions (produce values) */
5 // Literal
x // Variable
x + 5 // Arithmetic
x > 0 // Comparison
func() // Function call
x = 5 // Assignment (returns the assigned value!)
/* Statements (perform actions) */
int x; // Declaration statement
x = 5; // Expression statement
printf("Hi\n"); // Expression statement
return 0; // Return statement
if (x > 0) {"{ }"} // Compound statement
/* Expression used as statement */
x + 5; // Valid but useless - result discarded
printf("Test\n"); // Useful - side effect (prints)
/* Assignment is an expression in C */
x = y = z = 5; // Right-to-left: z=5, y=5, x=5
if (x = 5) {"{ }"} // OOPS: assignment instead of comparison!
if ((x = getValue()) != 0) {"{ }"} // Assign AND testSummary & What's Next
Key Takeaways:
- ✅ C is case-sensitive (main ≠Main)
- ✅ Statements end with semicolons
- ✅ Braces { } create code blocks and define scope
- ✅ Comments use /* */ or // (C99+)
- ✅ Identifiers start with letter or underscore
- ✅ Keywords are reserved and cannot be used as identifiers
- ✅ Whitespace is ignored (except between tokens)
- ✅ Expressions produce values; statements perform actions