C / GETTING STARTED
Comments, formatting, and naming identifiers
Comment, format and name C code deliberately: why /* */ cannot nest, why indentation never changes behaviour, and which identifiers are reserved.
What you will learn
- Treat each comment as one space: it separates tokens, it never joins them.
- Disable code with #if 0 ... #endif, since /* */ stops at the first */ and cannot nest.
- Brace every if/for/while body so indentation can never contradict what runs.
- Skip identifiers that start with _ or reuse library prefixes like str, mem, is, to.
Understanding Comments, formatting, and naming identifiers
Before C code is analysed at all, the source text is split into tokens: each comment is replaced by a single space, and runs of spaces, tabs and newlines collapse into nothing more than token separators. That is why `int main(void){return 0;}` on one line and the same code spread over six lines produce byte-identical machine code. Structure comes from braces, parentheses and semicolons, never from columns, so your indentation is a claim about the code that the compiler will not check. The one exception is that preprocessing directives such as #include and #define are line-oriented, which is why they end at the newline unless you continue them with a backslash.
A `/* */` comment scans forward for the first `*/` and stops there, with no nesting and no awareness of what is between. So a block comment cannot be used to wrap code that already contains one, and `#if 0` / `#endif` is the tool for switching regions of code off. A `//` comment runs to the end of the line, but backslash-newline splicing happens before comments are recognised, so a `//` line ending in a backslash quietly swallows the next line too. Comment markers inside string literals and character constants are just characters, because the literal is recognised as a single token first. Given that the code already states what happens, comments earn their space by recording why: the unit a number is in, the invariant a function assumes, the reason the obvious approach was rejected.
An identifier is letters, digits and underscores, not starting with a digit, and case matters, so `count` and `Count` are two different variables. Several spellings belong to the implementation rather than to you: anything starting with an underscore followed by an uppercase letter or a second underscore is reserved everywhere, a single leading underscore is reserved at file scope, and the library owns prefixes such as str, mem, is and to. C also has no modules, so every non-static function and variable at file scope is visible to the entire program at link time, which makes descriptive names and `static` your only collision defence. Let scope drive length: `i` is fine for a loop three lines long, while a name read fifty lines away or from another file needs to say what it holds.
C keeps names in separate name spaces, so a struct tag, a label, a struct member and an ordinary variable can all be spelled the same without conflict.
<stdio.h>
/* Money is kept in whole cents. Repeatedly adding a double like 19.99
accumulates rounding error, and a total must come out exact. */
static int line_total_cents(int unit_price_cents, int quantity)
{
return unit_price_cents * quantity;
}
int main(void)
{
int unit_price_cents = 1999; /* 19.99 */
int quantity = 3;
int total_cents = line_total_cents(unit_price_cents, quantity);
// %02d pads the remainder, so 5 cents prints as 05 and not as 5.
printf("%d x %d cents = %d.%02d\n",
quantity, unit_price_cents, total_cents / 100, total_cents % 100);
return 0;
}
Comments and layout are reduced to whitespace before the compiler sees any structure, so they exist for readers only, while C's token rules decide the few places where that whitespace still changes meaning.
Worked examples
A comment is exactly one space
Shows that comments act as token separators and that comment markers inside a string literal are ordinary characters.
<stdio.h>
int main(void)
{
int x/**/=/**/5;
printf("%d\n", x);
printf("visit http://example.com\n");
return 0;
}
Example explained
Line 1`int x/**/=/**/5;` compiles because each comment becomes one space, leaving the tokens int, x, =, 5 and ;.
Line 2For the same reason `a/**/b` is two identifiers rather than `ab`; comments can never glue tokens together.
Line 3The `//` in the second string is inside a string literal, which the scanner takes as one token, so nothing after it is commented out.
The space in y / *p is load-bearing
Demonstrates the one common case where deleting whitespace changes a C program's meaning.
<stdio.h>
int main(void)
{
int divisor = 5;
int *p = &divisor;
int quotient = 100 / *p; /* space required between the slash and *p */
printf("100 / *p = %d\n", quotient);
return 0;
}
Example explained
Line 1`100 / *p` divides by the int that `p` points at, so the result is 20.
Line 2Remove the space and the scanner reads the two characters as a comment opener, then consumes the rest of the file hunting for `*/` and reports an unterminated comment.
Line 3The scanner always takes the longest thing it can recognise at each position, so the comment opener wins over the division operator whenever the characters are adjacent.
Tags and variables live in different name spaces
Shows that a struct tag and an ordinary variable may share a spelling in C, and why that is still a bad idea.
<stdio.h>
struct point { int x; int y; };
int main(void)
{
struct point point = { 3, 4 };
printf("%d %d\n", point.x, point.y);
return 0;
}
Example explained
Line 1`struct point` introduces a tag, and tags are looked up separately from ordinary identifiers, so the variable may also be called `point`.
Line 2Member names sit in yet another name space, one per struct type, so `x` here can never collide with a variable named `x`.
Line 3The program is legal but every later reader has to work out which `point` is meant, which is why real code names the type and the object differently.
Important notes
Start your own names with a letter. A leading underscore followed by an uppercase letter or a second underscore is reserved to the implementation in every context, and a single leading underscore is reserved at file scope, so such names can clash with anything a header defines.
`//` comments are standard only from C99 onward; under `gcc -std=c89 -pedantic` they draw a diagnostic, which is why older code uses `/* */` throughout.
Common mistakes
Wrapping a block of code in /* */ when that block already contains a comment: the inner */ closes your comment early, the rest of the block stays live, and the final */ becomes a stray token that gcc reports on a line you did not touch.
Ending a // comment with a backslash, often while lining up a trailing comment: splicing happens before comments are found, so the following line joins the comment and silently disappears from the program with no error at all.
Adding a second statement under an unbraced if and trusting the indentation: only the first statement is guarded and the second runs unconditionally, because layout has no effect on which statement the if controls.
Try it yourself
Change, predict, then run
Write a main() that prints two lines and contains one /* */ comment between them, then try to disable the whole body with a single /* */ pair and read the exact error gcc gives. Replace that attempt with #if 0 and #endif and confirm it compiles cleanly.
Open the C workspaceCheck your understanding
Which of these edits to a working C file can change what the program does?
- Re-indenting the body of a for loop so it lines up with the loop header
- Adding a blank line between two statements
- Deleting the space in `int x = y / *p;`
- Renaming a local variable, and every use of it, to another unused name
Show answer
Whitespace matters only where it changes how the source splits into tokens: with the space gone, the scanner reads the slash and star as a comment opener and everything up to the next */ vanishes from the program. Re-indenting looks like the tempting answer to anyone coming from Python, but braces and semicolons define structure in C, so the compiler cannot see indentation at all.