A variable is a named piece of memory that holds a value your program can read and change. In C you always say up front what kind of value it holds, and that choice is permanent for the life of the variable.
Declaring a Variable
The form is type, name, semicolon:
int age;
double price;
char grade;
Each line reserves enough memory for that data type and attaches a name to it. Nothing has been stored yet - the space exists, but its contents are whatever was left there by whatever ran before.
You can give a value at the same moment, which is called initialization:
Note the format specifiers: %d for int, %f for double, %c for char. printf does not inspect the values it is given - it trusts your format string, so a mismatch prints nonsense rather than an error.
Assignment After Declaration
Once a variable exists you change it with =:
= in C is assignment, not equality. score = score + 10 reads as "take what is in score, add 10, put the result back in score." The comparison operator is ==, and mixing them up is such a common bug that it has its own section on the booleans page.
The shorthand score += 10 does the same thing in fewer characters; the compound assignment operators cover all the arithmetic.
The Uninitialized Variable Trap
This is the single most common beginner bug in C, and it does not produce an error:
Run it. You may see 15, which is the right answer. You may see a huge random number. You may see something different on a second run or on a different machine. All of those are "correct" behavior, because reading an uninitialized local variable is undefined behavior - the C standard places no requirement on what happens.
Unlike many languages, C does not zero your locals. A local variable is a slice of the stack, and the stack is full of leftovers from earlier function calls. Sometimes those leftovers happen to be zero, which is what makes this bug so dangerous: it often works in testing and fails in production.
The fix is one character:
Make it a habit: initialize every variable at the point of declaration. If you genuinely have no sensible value yet, 0 or NULL is better than garbage. And compile with -Wall, which catches most cases:
warning: 'total' is used uninitialized in this function
Global and static variables are the exception - they are zero-initialized automatically. Relying on that is fine, but writing = 0 anyway documents your intent.
Declaring Several at Once
Variables of the same type can share a declaration, with or without initializers:
This is legal and common for tightly related values like x, y, z. It is also where a classic misreading lives:
int a = 0, b = 0, c = 0; /* all three are 0 */
int d, e, f = 0; /* only f is 0 - d and e are garbage */
The initializer attaches to one name, not to the line. When the values differ in meaning, give each its own line - it reads better and diffs better.
Declaring pointers on one line has the same trap in sharper form:
int *p, q; /* p is a pointer to int; q is a plain int */
The * binds to the name, not the type. Declare pointers one per line.
Naming Rules and Conventions
The compiler's rules:
- Letters, digits, and underscores only.
- Cannot begin with a digit:
total2is fine,2totalis not. - Cannot be a C keyword: no variable named
int,return,for,double. - Case sensitive:
count,Count, andCOUNTare three separate variables. - Names starting with an underscore, or containing a double underscore, are reserved for the implementation. Do not create them.
int itemCount; /* legal */
int item_count; /* legal - the usual C style */
int _count; /* legal but reserved - avoid */
int item-count; /* error: '-' is the minus operator */
int 3rd_place; /* error: starts with a digit */
int float; /* error: keyword */
The conventions that most C code follows: snake_case for variables and functions, UPPER_CASE for macro constants, and names that say what the value means rather than what type it is. elapsed_ms beats t; customer_count beats n2.
Short names are still fine where the scope is tiny - i as a loop counter is universally understood, and nobody wants for (int loop_iteration_index = 0; ...).
Where a Variable Lives
Where you declare a variable determines who can see it and how long it lasts. This is scope, and the short version is:
A variable is visible from its declaration to the closing brace of the block containing it. Globals live for the whole program and are visible everywhere, which sounds convenient and is why they cause trouble: any function can change one, so tracking down who did becomes a search through the whole file. Prefer locals and pass values to functions as parameters.
Declaring Anywhere (C99 and Later)
In original C89, every declaration had to come before any statement in a block:
int main(void) {
int i, sum = 0; /* all declarations first */
printf("Starting\n");
for (i = 0; i < 10; i++) { sum += i; }
return 0;
}
Since C99 you can declare where you first need the value, including in the for header:
This is better style: the declaration sits next to its first use, and i cannot leak into the rest of the function. Compile with -std=c17 (or any C99+ setting) and it works everywhere.
Frequently Asked Questions
How do you declare a variable in C?
Write the type, then the name, then a semicolon: int age;. You can give it a value at the same time - int age = 30; - which is called initialization and is almost always what you want.
What is the difference between declaring and initializing a variable?
Declaring reserves the space and names it (int count;). Initializing puts a value in it at the moment it is created (int count = 0;). A declared-but-uninitialized local variable contains whatever bytes were already at that address - reading it is undefined behavior.
What are the rules for variable names in C?
Letters, digits, and underscores only; it cannot start with a digit; it cannot be a keyword like int or for; and it is case sensitive, so total and Total are different variables. Names beginning with an underscore are reserved - avoid them.
Can you declare variables anywhere in a C function?
Since C99, yes - declare each variable right where you first need it. In the original C89 standard every declaration had to appear at the top of a block, which is why older code has a wall of declarations before any real work.