Variables and Data Types
Variables and Data Types
A variable in C is a named box in memory. Two things about that box are fixed the moment you declare it: how many bytes it occupies and how those bytes are interpreted. The second part is what a data type really is. The same eight bytes can be a number, two numbers, or eight characters, depending purely on the type you attached to them.
This is why C insists you announce a type before using a variable. It is not paperwork. It is the only way the compiler knows how much space to reserve and which machine instructions to emit.
The basic types
| Type | Typical size | Holds | Format specifier |
|---|---|---|---|
char |
1 byte | One character, or a small integer | %c |
int |
4 bytes | Whole numbers | %d |
float |
4 bytes | Real numbers, about 6-7 digits precise | %f |
double |
8 bytes | Real numbers, about 15-16 digits precise | %lf |
long |
8 bytes on most Linux systems | Larger whole numbers | %ld |
The word "typical" matters. The C standard does not fix these sizes. It guarantees only minimums and relationships, such as int being at least 2 bytes and double being at least as large as float. On the machines you will use, int is almost always 4 bytes, but writing code that assumes it is a portability bug.
Checking sizes yourself with sizeof
sizeof is an operator, not a function, and it is answered by the compiler rather than at run time. Run this on your own machine instead of memorising a table.
#include <stdio.h>
int main(void)
{
printf("char : %zu bytes\n", sizeof(char));
printf("int : %zu bytes\n", sizeof(int));
printf("float : %zu bytes\n", sizeof(float));
printf("double : %zu bytes\n", sizeof(double));
printf("long : %zu bytes\n", sizeof(long));
return 0;
}
%zu is the correct specifier for the type sizeof produces. Many textbooks use %d, which usually works by accident and is technically wrong.
Size is what limits range. A 4-byte int holds 32 bits, so it can represent about 4.29 billion distinct values. Because it is signed, that range is split roughly in half around zero: about -2,147,483,648 to 2,147,483,647. Push past the top and the value wraps around to the bottom. This is integer overflow, and C will not warn you at run time.
Declaration versus initialisation
These are two different events, and confusing them causes some of the strangest beginner bugs.
- Declaration reserves the space:
int count; - Initialisation puts a known value in it:
int count = 0;
A declared but uninitialised local variable does not contain zero. It contains whatever bytes were already lying in that memory location, left over from previous work. Reading it gives you an unpredictable value, and the program may appear correct on your laptop and wrong in the lab.
int sum; followed by sum = sum + 5; is a real bug even though it compiles cleanly. The starting value of sum is garbage. Initialise every variable at the point you declare it, unless you assign to it immediately afterwards. int sum = 0; costs nothing.
A program that shows the types working
#include <stdio.h>
int main(void)
{
int rollNo = 42;
char section = 'B';
float cgpa = 8.75f;
double pi = 3.14159265358979;
printf("Roll number : %d\n", rollNo);
printf("Section : %c\n", section);
printf("CGPA : %.2f\n", cgpa);
printf("Pi : %.10lf\n", pi);
printf("Section as a number: %d\n", section);
return 0;
}
Two details are worth stopping on.
The character constant uses single quotes: 'B' is one character. "B" with double quotes is a string, which is a different thing entirely and will not fit in a char.
The last line prints 66. A char really is a small integer; 'B' is stored as its ASCII code. This is not a trick, it is the definition, and it is why 'a' + 1 gives you 'b'.
%.2f means "print two digits after the decimal point". The default for %f is six.
Integer division, the classic surprise
#include <stdio.h>
int main(void)
{
int obtained = 7;
int total = 2;
printf("Integer division : %d\n", obtained / total);
printf("Float division : %.2f\n", (float) obtained / total);
printf("Remainder : %d\n", obtained % total);
return 0;
}
7 / 2 gives 3, not 3.5. When both operands are integers, C performs integer division and throws away the fractional part. It does not round; it truncates. To get 3.5 you must make at least one side a floating-point value, which is what the cast (float) does.
The % operator gives the remainder and works only on integers. 7 % 2 is 1.
Constants
Some values should never change after you set them. C gives you two ways to say so.
#include <stdio.h>
#define MAX_STUDENTS 60
int main(void)
{
const float PI = 3.14159f;
float radius = 2.0f;
printf("Seats available : %d\n", MAX_STUDENTS);
printf("Circle area : %.4f\n", PI * radius * radius);
return 0;
}
#define is handled by the preprocessor, which simply replaces every occurrence of the name with the text before compilation. It has no type and takes no memory. Note there is no semicolon and no equals sign.
const creates a genuine typed variable that the compiler refuses to let you modify. If you write PI = 3.0f; later, compilation fails. Prefer const in new code, because the compiler can type-check it. You will meet #define constantly in existing code and in your textbooks, so you need to recognise both.
Naming rules
Names may contain letters, digits and underscores, and may not start with a digit. 2ndYear is invalid; year2 is fine. Keywords such as int, for and return cannot be reused as names. Case matters: Total and total are two different variables, and mixing them up produces confusing errors.
Common mistakes
- Mismatching the format specifier and the type. Printing a
floatwith%d, or adoublewith%finscanf, produces garbage rather than an error. The specifier must match the type exactly. - Assuming
intdivision rounds.5 / 2is 2, andavg = sum / count;with integer variables silently loses the fraction. Cast one operand first. - Using an uninitialised variable. Compiles fine, behaves randomly. Initialise on declaration.
- Double quotes for a character.
char grade = "A";is wrong. Usechar grade = 'A'; - Expecting exact decimals from
float. Binary floating point cannot represent 0.1 exactly, so0.1 + 0.2is not precisely 0.3. Never compare floats with==; check whether the difference is smaller than a small tolerance.
Types are the foundation everything else in C sits on. Once you are comfortable predicting what a declaration reserves and what a specifier prints, the rest of the language gets noticeably easier. Test yourself on the Practice page.