Junior 6 min · March 06, 2026

C Data Types - Uninitialized Var Causes Random Interest

Interest payments varied randomly from an uninitialized double.

N
Naren · Founder
Plain-English first. Then code. Then the interview question.
About
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • A variable is a named memory location; the compiler maps names to addresses.
  • Four primitive types: int (whole numbers), float/double (decimals), char (single characters).
  • Type modifiers (short, long, signed, unsigned) adjust integer range and size.
  • Always initialize variables: uninitialized locals contain garbage — undefined behavior.
  • Format specifiers (%d, %f, %c) must match the variable's type — mismatch causes silent corruption.
  • Use sizeof() to get the exact byte size on your platform; never assume.
Plain-English First

Think of your computer's memory as a giant street of numbered lockers. A variable is like renting one of those lockers, sticking a name label on the door, and deciding whether it'll hold a number, a letter, or a decimal. A data type is just the size and shape of that locker — you wouldn't store a surfboard in a coin locker. That's it. That's all variables and data types are.

Every program that has ever run on a computer — from the app on your phone to the code launching rockets — stores information somewhere while it's working. That 'somewhere' is memory, and the mechanism C gives you to work with memory is variables. Without them you can't remember a user's name, keep score in a game, or total up a shopping cart. They are the absolute foundation everything else is built on.

The problem variables solve is simple: programs need to hold onto values while they're doing work. Without variables you'd have to hard-code every number directly into your logic, and the moment anything changed you'd be stuck. Data types solve a second problem: memory is finite and expensive, so C forces you to say upfront exactly how much space each value needs. A yes/no flag doesn't need the same amount of memory as a GPS coordinate, and C respects that.

By the end of this article you'll be able to declare any basic variable in C, pick the right data type for the job, read and write to variables with confidence, understand exactly how much memory each type consumes, and avoid the three traps that catch nearly every beginner. Let's build this from the ground up.

What a Variable Actually Is — And How C Stores It in Memory

When your C program runs, the operating system hands it a chunk of RAM to work with. Think of that RAM as a very long row of tiny boxes, each holding exactly one byte (8 bits), and each box having its own unique address — like house numbers on a street.

A variable is your way of reserving one or more of those boxes and giving them a human-readable name. When you write int playerScore = 0;, C reserves 4 boxes (4 bytes) in a row, remembers where they start, and every time you write playerScore in your code it knows exactly which boxes to look in.

The name only exists for you. The computer only ever works with addresses. C's compiler is the translator between your human-friendly name and the raw memory address. This is why you have to declare a variable before you use it — you're asking C to go find and reserve the space before you try to put something there.

Declaration syntax is always the same pattern: datatype variableName; or datatype variableName = initialValue;. The second form is called initialization and it's always the safer choice, as you'll see in the mistakes section.

memory_model_demo.cC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>

int main() {
    /* Declare an integer variable to store a player's score.
       C reserves 4 bytes in memory and labels them 'playerScore'. */
    int playerScore = 100;

    /* Declare a character variable to store a grade letter.
       C reserves 1 byte in memory for a single character. */
    char letterGrade = 'A';

    /* The & operator gives us the actual memory address C chose.
       %p is the format specifier for printing an address (pointer). */
    printf("Value of playerScore : %d\n", playerScore);
    printf("Address in RAM       : %p\n", (void*)&playerScore);

    printf("Value of letterGrade : %c\n", letterGrade);
    printf("Address in RAM       : %p\n", (void*)&letterGrade);

    /* How many bytes does each type occupy on this machine? */
    printf("\nSize of int  : %zu bytes\n", sizeof(int));
    printf("Size of char : %zu bytes\n", sizeof(char));

    return 0;
}
Output
Value of playerScore : 100
Address in RAM : 0x7ffee3b2a4ac
Value of letterGrade : A
Address in RAM : 0x7ffee3b2a4ab
Size of int : 4 bytes
Size of char : 1 byte
Why Addresses Look Different on Your Machine:
The exact memory address printed (like 0x7ffee3b2a4ac) will be different every single time you run the program — even on the same computer. The OS assigns RAM dynamically. The values and sizes, however, will stay the same. Don't panic when your output doesn't match exactly.
Production Insight
Local variables live on the stack. Stack memory is reused across function calls, so uninitialized locals contain residual data from previous calls.
This is why static functions can leak data between calls if you forget to initialize.
Rule: never read a variable before writing to it — always initialize at declaration.
Key Takeaway
A variable name is a convenience for you; the CPU only sees addresses.
The compiler picks the address; you control the type and value.
Always initialize local variables — garbage in memory is undefined behavior.

The Four Core Data Types in C — Choosing the Right Locker for the Job

C has four fundamental data types you'll use in 90% of your programs. Every other type is either a variation or a combination of these four.

int (integer) — For whole numbers, positive or negative. No decimal point. Use this for counts, ages, loop counters, scores, anything you'd count on your fingers. Typically 4 bytes, holding values from roughly -2.1 billion to +2.1 billion.

float (floating-point) — For numbers with a decimal point where you need about 6–7 digits of precision. Think currency, temperature, measurements. Typically 4 bytes. The trade-off: floats have small rounding errors baked in — more on that in the gotchas.

double (double-precision float) — Like float but twice the size (8 bytes) and roughly 15–16 digits of precision. Use this whenever float's precision feels risky — scientific calculations, financial totals, GPS coordinates. In modern code, prefer double over float unless memory is critically tight.

char (character) — For a single letter, digit, or symbol. Under the hood it's just a tiny integer (1 byte) that maps to a character via the ASCII table. 'A' is stored as the number 65. This duality is surprisingly powerful and comes up in interviews constantly.

core_data_types.cC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>

int main() {
    /* --- INTEGER: whole numbers only --- */
    int numberOfStudents = 42;
    int freezingPointCelsius = 0;
    int bankDebtDollars = -5000;   /* negatives work fine */

    /* --- FLOAT: decimals with ~6 significant digits --- */
    float bodyTemperatureCelsius = 36.6f;  /* note the 'f' suffix — required for float literals */
    float taxRate = 0.085f;

    /* --- DOUBLE: decimals with ~15 significant digits --- */
    double distanceToMoonKm = 384400.0;
    double piApproximation = 3.14159265358979;

    /* --- CHAR: single characters, stored as ASCII numbers --- */
    char bloodType = 'O';
    char newlineCharacter = '\n';  /* special 'escape' characters use backslash */

    /* --- Print everything out with the matching format specifier --- */
    printf("Students       : %d\n",  numberOfStudents);     /* %d  for int    */
    printf("Freezing point : %d C\n", freezingPointCelsius);
    printf("Bank debt      : %d USD\n", bankDebtDollars);

    printf("Body temp      : %.1f C\n", bodyTemperatureCelsius);  /* %.1f = 1 decimal place */
    printf("Tax rate       : %.3f\n",  taxRate);

    printf("Moon distance  : %.1f km\n", distanceToMoonKm);  /* %f also works for double */
    printf("Pi             : %.14f\n", piApproximation);      /* 14 decimal places */

    printf("Blood type     : %c\n",  bloodType);             /* %c  for char   */

    /* char stores an ASCII integer — we can print it both ways */
    printf("'O' as a number: %d\n",  bloodType);             /* prints 79 */

    return 0;
}
Output
Students : 42
Freezing point : 0 C
Bank debt : -5000 USD
Body temp : 36.6 C
Tax rate : 0.085
Moon distance : 384400.0 km
Pi : 3.14159265358979
Blood type : O
'O' as a number: 79
The 'f' Suffix Rule You'll Forget Once and Then Never Forget Again:
In C, a bare decimal literal like 3.14 is a double by default. Writing float temperature = 36.6; silently converts a double down to a float, which can produce a compiler warning. Adding the 'f' suffix — 36.6f — tells the compiler it's already a float literal. Get in the habit early.
Production Insight
Prefer double over float for most decimal work. Float's 6-7 digits lose precision fast in loops or additions.
A common production bug: using float for financial calculations where rounding errors compound.
Rule: if it's money or measurements, use double unless memory is absolutely critical.
Key Takeaway
int for whole numbers, double for decimals, char for single characters.
Use %d for int, %f for double/float, %c for char.
Float literals need the 'f' suffix to avoid double-to-float conversion warnings.

Type Modifiers — Stretching and Shrinking Your Data Types

The four core types are good starting points, but C lets you tune them further using four modifiers: short, long, signed, and unsigned. Think of these as choosing between locker sizes at the gym — small, standard, large, and extra-large.

short int uses 2 bytes instead of 4, halving your range but saving memory. Useful in embedded systems where every byte is precious — think microcontrollers in toasters or car sensors.

long int typically gives you 4 or 8 bytes (platform-dependent), and long long int guarantees at least 8 bytes. Use long long when you need numbers beyond 2 billion — population counts, file sizes in bytes, Unix timestamps.

unsigned removes the ability to store negative numbers but doubles the positive range. A regular int goes from about -2.1B to +2.1B. An unsigned int goes from 0 to about 4.2B. Use it when a negative value is physically impossible — array sizes, pixel counts, ages.

signed is the default for all integer types, so you rarely need to write it explicitly. It exists mainly for clarity or when working with char, which can be signed or unsigned depending on the compiler.

type_modifiers_demo.cC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>

int main() {
    /* short int: 2 bytes — good for small whole numbers */
    short int floorNumber = 12;

    /* long long int: 8 bytes — for very large whole numbers */
    long long int worldPopulation = 8100000000LL;  /* LL suffix required for long long literals */

    /* unsigned int: 4 bytes, but 0 to ~4.29 billion (no negatives) */
    unsigned int numberOfPixels = 2073600;  /* 1920 x 1080 */

    /* unsigned char: 1 byte, values 0255 — perfect for RGB color components */
    unsigned char redChannel   = 255;
    unsigned char greenChannel = 128;
    unsigned char blueChannel  = 0;

    printf("Floor number    : %hd\n",   floorNumber);       /* %hd for short */
    printf("World population: %lld\n",  worldPopulation);   /* %lld for long long */
    printf("Pixel count     : %u\n",    numberOfPixels);    /* %u for unsigned int */
    printf("RGB color       : (%u, %u, %u)\n", redChannel, greenChannel, blueChannel);

    /* sizeof confirms the memory footprint */
    printf("\nMemory sizes:\n");
    printf("  short int      : %zu bytes\n", sizeof(short int));
    printf("  int            : %zu bytes\n", sizeof(int));
    printf("  long long int  : %zu bytes\n", sizeof(long long int));
    printf("  unsigned char  : %zu bytes\n", sizeof(unsigned char));

    return 0;
}
Output
Floor number : 12
World population: 8100000000
Pixel count : 2073600
RGB color : (255, 128, 0)
Memory sizes:
short int : 2 bytes
int : 4 bytes
long long int : 8 bytes
unsigned char : 1 byte
Watch Out: Overflow Is Silent and Deadly
If you store the value 40000 in a short int (max ~32767), C won't crash or warn you — it just wraps around to a wrong number. This is called integer overflow and it has caused real-world bugs including a famous Ariane 5 rocket explosion in 1996. Always pick a type whose range comfortably fits your data, with room to grow.
Production Insight
Integer overflow is silent in C — no exception, no warning at runtime.
A spacecraft (Ariane 5) exploded because a 64-bit float converted to a 16-bit integer overflowed.
Rule: when your data could approach ±2 billion, use long long or unsigned. Never assume int is big enough.
Key Takeaway
Use unsigned when negative values make no sense — it doubles your positive range.
Use short only when memory is scarce (embedded systems).
Use long long when values exceed 2 billion.
Overflow wraps silently; prevent by choosing the right type.

Naming Rules, Constants, and Writing Variables That Future-You Will Thank You For

C has strict rules about what you can name a variable, and there are strong conventions on top of those rules. Breaking the rules causes compile errors. Ignoring the conventions causes something worse: unreadable code.

Hard rules: Variable names can only contain letters (a–z, A–Z), digits (0–9), and underscores (_). They must start with a letter or underscore — never a digit. They can't be C keywords like int, return, or for. C is case-sensitive, so score, Score, and SCORE are three completely different variables.

Convention: Most C programmers use snake_case for variable names — all lowercase with underscores between words. playerScore (camelCase) is also common, especially for developers coming from C++ or Java. Pick one and stick to it in a project.

Constants with const: If a value should never change after it's set, mark it const. The compiler will stop you if you accidentally try to change it. This is much better than a raw number buried in your code — called a 'magic number' — which gives future readers zero context about what 3.14159 or 9.81 means.

Use #define for compile-time constants that you want available everywhere in the file, and const for constants that live in a specific scope.

constants_and_naming.cC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>

/* #define creates a compile-time constant — no memory is allocated,
   the preprocessor replaces every occurrence before compilation */
#define MAX_SPEED_KMH     120
#define GRAVITY_MS2       9.81

int main() {
    /* const creates a runtime constant — memory IS allocated,
       but the compiler refuses any attempt to change the value */
    const float PI = 3.14159f;
    const int   DAYS_IN_WEEK = 7;

    /* Good naming: reads like plain English */
    int currentSpeedKmh    = 95;
    float circleRadiusMetres = 5.0f;
    int daysUntilDeadline  = 14;

    /* Calculate using our named constants — clear and self-documenting */
    float circumference = 2 * PI * circleRadiusMetres;
    int weeksUntilDeadline = daysUntilDeadline / DAYS_IN_WEEK;
    int speedHeadroom = MAX_SPEED_KMH - currentSpeedKmh;

    printf("Circle circumference : %.2f metres\n", circumference);
    printf("Weeks until deadline : %d\n",          weeksUntilDeadline);
    printf("Speed headroom       : %d km/h\n",     speedHeadroom);
    printf("Gravity constant     : %.2f m/s^2\n",  GRAVITY_MS2);

    /* This line would cause a COMPILE ERROR — uncomment to see:
       PI = 3.14;   // error: assignment of read-only variable 'PI' */

    return 0;
}
Output
Circle circumference : 31.42 metres
Weeks until deadline : 2
Speed headroom : 25 km/h
Gravity constant : 9.81 m/s^2
Interview Gold: const vs #define
Interviewers love this one. const variables have a type, a scope, and can be inspected by a debugger. #define macros have none of those — the preprocessor blindly text-substitutes before the compiler even sees the code. Prefer const in modern C for type safety. Use #define for true compile-time constants like array sizes or hardware register addresses where the value must be a literal.
Production Insight
Magic numbers (raw literals like 3.14159) are a maintenance nightmare. If the value changes, you have to find and replace every occurrence.
Using const or #define centralizes the value and documents its meaning.
Rule: any literal that isn't 0, 1, or obvious should be named.
Key Takeaway
Use const for typed constants; use #define for compile-time values like array sizes.
Good variable names make code self-documenting — 'magic numbers' kill readability.
C is case-sensitive: score, Score, SCORE are different variables.

Common Variable Pitfalls That Crash Production

Even after learning the rules, beginners (and sometimes experts) make the same mistakes over and over. These aren't just learning errors — they cause real production outages.

Uninitialized memory: C does not zero local variables. A declaration like int count; gives you whatever bits happened to be in that stack location. Using it before assignment is undefined behavior. In some runs it works, in others it produces garbage. These bugs are notoriously hard to reproduce.

Integer overflow: When a value exceeds the type's maximum, it wraps around. short x = 32767; x++; gives -32768. No warning, no crash — just a wrong answer. This has caused rocket explosions and financial disasters.

Format specifier mismatch: Using %f with an integer or %d with a float tells printf to interpret the bits in the wrong way. Stack corruption and silent data corruption follow. The compiler with -Wformat catches this. Always compile with warnings enabled.

Integer division: int a = 5; int b = 2; double result = a / b; gives 2.0, not 2.5. The division happens with integers first, then the integer result is converted. Cast at least one operand to float or double.

common_pitfalls.cC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>

int main() {
    /* Pitfall 1: Uninitialized variable */
    int uninitialized;  /* dangerous — may be 0, may be garbage */
    printf("Pitfall 1: %d\n", uninitialized);  // undefined behavior

    /* Pitfall 2: Integer overflow */
    short smallCounter = 32767;
    smallCounter = smallCounter + 1;
    printf("Pitfall 2: %d\n", smallCounter);  // prints -32768

    /* Pitfall 3: Format specifier mismatch */
    int anInt = 42;
    // printf("%f\n", anInt);  // uncomment to see garbage (or crash)

    /* Pitfall 4: Integer division truncation */
    int a = 5, b = 2;
    double badResult = a / b;          // 2.0
    double goodResult = (double)a / b; // 2.5
    printf("Pitfall 4: bad=%.1f, good=%.1f\n", badResult, goodResult);

    return 0;
}
Output
Pitfall 1: (some garbage value, e.g., 32767)
Pitfall 2: -32768
Pitfall 4: bad=2.0, good=2.5
Enable -Wall -Werror — It's Your Safety Net
Compile with gcc -Wall -Werror program.c. This turns most common mistakes into hard errors. It catches format mismatches, uninitialized variables, and many other traps before they ever reach production. There's no downside. Use it in every project.
Production Insight
In production, undefined behavior from uninitialized variables and format mismatches leads to non-deterministic crashes that are extremely hard to reproduce. Teams often blame the compiler or hardware first.
Always start debugging by enabling all warnings and checking Valgrind.
Rule: treat every compiler warning as a potential production bug.
Key Takeaway
Enable all compiler warnings and treat them as errors.
Initialize all variables.
Match format specifiers to types.
Cast to float when integer division is intended to produce a decimal.

Type Conversion and Casting — When the Compiler Changes Your Data

C performs implicit type conversion in many situations: when you assign a value to a variable of a different type, when you mix types in expressions, or when you pass arguments to functions. Understanding these conversions prevents unexpected data loss.

Implicit conversion (promotion): In expressions, smaller types are promoted to larger ones. For example, a char is promoted to int in arithmetic. This usually works fine. But assignments are different: if you assign a double to an int, the fractional part is truncated (not rounded).

Explicit casting: You can force a conversion using the cast operator: (type)expression. Always do this when you know the conversion might lose information — it documents your intent and warns other developers.

Integer promotion rules: Operations on char and short are performed in int (or unsigned int). This can cause subtle bugs: unsigned char a = 250; unsigned char b = 10; int c = a - b; works fine, but c = a - 300; may produce unexpected results because 300 is an int and the subtraction is performed in int.

Truncation and sign extension: When converting from a larger signed type to a smaller one, the high-order bits are discarded. For unsigned types, sign extension occurs when converting from signed to unsigned.

type_conversion_demo.cC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>

int main() {
    /* Implicit truncation */
    double price = 9.99;
    int truncatedPrice = price;          // truncated to 9, no warning
    printf("Truncation: %.2f -> %d\n", price, truncatedPrice);

    /* Explicit cast — shows intent */
    int result = (int)(price * 100);     // 999, not 1000 (due to truncation of 999.0? Actually 9.99*100 = 999.0) 

    /* Integer promotion */
    char small = 100;
    char bigger = 200;
    int sum = small + bigger;            // promoted to int, sum = 300
    printf("Promotion: %d + %d = %d\n", small, bigger, sum);

    /* Sign extension when converting signed to unsigned */
    signed char s = -5;
    unsigned int u = (unsigned int)s;    // becomes a large number due to sign extension
    printf("Sign extension: %d -> %u\n", s, u);

    return 0;
}
Output
Truncation: 9.99 -> 9
Promotion: 100 + 200 = 300
Sign extension: -5 -> 4294967291
Always Compile with -Wconversion to Catch Sneaky Truncations
GCC's -Wconversion flag warns about implicit conversions that may change a value. It's not in -Wall or -Wextra. Add it to your build flags for production code to catch silent truncations and sign mismatches.
Production Insight
Automatic conversion (implicit casting) can lead to unexpected data loss, e.g., assigning a large double to an int truncates the fractional part silently.
A common bug: float result = 5 / 2; yields 2.0, not 2.5. The fix is to cast at least one operand to float.
Rule: never rely on implicit conversion for critical accuracy — always cast explicitly.
Key Takeaway
Implicit conversion happens automatically but can lose data.
Use explicit casts to document intentional conversion.
Integer division truncates; cast to float/double to preserve decimal.
Enable -Wconversion to catch unexpected truncations.
● Production incidentPOST-MORTEMseverity: high

The Silent Budget Overrun: Uninitialized Variable Corrupts Financial Calculation

Symptom
Interest payments varied randomly each month despite identical input data. Some accounts received millions, others pennies. No crashes or error logs.
Assumption
All local variables are zero-initialized by the compiler (like in Java or C#).
Root cause
A local variable double interestAccrued; was declared but not initialized. The memory held whatever leftover bytes were there from the previous function call's stack frame. On each run, those bytes differed, producing unpredictable interest values.
Fix
Initialize every local variable at declaration: double interestAccrued = 0.0;. Also enabled compiler warnings with -Wuninitialized -Werror to prevent future occurrences.
Key lesson
  • C does NOT zero-initialize local variables — ever. Assume garbage unless you set a value.
  • Enable compiler warnings and treat them as errors. A warning today is a production outage tomorrow.
  • When debugging non-deterministic failures, always suspect uninitialized variables and array bounds first.
Production debug guideThree common variable-related failures and how to diagnose them3 entries
Symptom · 01
Variable prints weird symbols or huge numbers on printf (e.g., printing int with %f)
Fix
Check format specifier in printf/scanf. Use %d for int, %f for float/double, %c for char, %zu for size_t. Enable compiler warnings: 'warning: format '%f' expects argument of type 'double' but argument 2 has type 'int''.
Symptom · 02
Value wraps to negative when it should be positive (e.g., counter reaches large numbers then flips)
Fix
Check for integer overflow. Verify range of data types. Use unsigned int for non-negative values. If range might exceed 2 billion, use long long. printf with %u for unsigned.
Symptom · 03
Function returns different values each call with same input (non-deterministic output)
Fix
Check for uninitialized local variables. Enable compiler warnings. Use Valgrind or AddressSanitizer to detect use of uninitialized memory. Initialize all variables at declaration.
★ Quick Debug Cheat Sheet: C Variables & TypesUse this when you hit weird numbers, crashes, or non-deterministic behavior.
printf prints huge numbers or garbage
Immediate action
Stop and check the format specifier matches the variable type.
Commands
gcc -Wformat -Wall -Wextra program.c -o program # enables format warnings
Run program; compiler should have warned at compile time.
Fix now
Change specifier to correct one: %d → int, %f → float/double, %c → char.
Variable unexpectedly wraps around (e.g., 32767 + 1 = -32768)+
Immediate action
Check the variable's data type size and range. Assume overflow.
Commands
printf("Size of type: %zu\n", sizeof(your_variable)); // prints bytes
Check if value exceeds type's max (e.g., for short max 32767).
Fix now
Change type to larger (long long or unsigned) to accommodate bigger range.
Program crashes with 'Segmentation fault' when accessing variable+
Immediate action
Check if the variable is uninitialized or out of bounds. Enable AddressSanitizer.
Commands
gcc -fsanitize=address -g program.c -o program && ./program
Valgrind: valgrind --tool=memcheck ./program
Fix now
Initialize all variables. Ensure array indices are within bounds. Use pointers carefully.
Data TypeSize (typical)Range / ValuesFormat SpecifierBest Used For
char1 byte-128 to 127 (signed)%c or %dSingle characters, small integers, ASCII values
unsigned char1 byte0 to 255%c or %uRGB colour channels, byte-level data, flags
short int2 bytes-32,768 to 32,767%hdSmall counters in memory-constrained systems
int4 bytes-2,147,483,648 to 2,147,483,647%dGeneral-purpose whole numbers — the default choice
unsigned int4 bytes0 to 4,294,967,295%uSizes, counts, indices — when negative is impossible
long long int8 bytes-9.2×10^18 to 9.2×10^18%lldTimestamps, file sizes, very large counts
float4 bytes~6–7 significant digits%fSimple decimals where precision isn't critical
double8 bytes~15–16 significant digits%lf or %fScientific values, financial totals, GPS coordinates

Key takeaways

1
A variable is a named reservation of bytes in RAM
the name is for you, the compiler translates it to a memory address at runtime.
2
Choosing the wrong data type doesn't always cause a crash
it causes silent wrong answers. Use int for whole numbers, double for decimals by default, and narrow down only when you have a reason.
3
Always initialize local variables at declaration. C's garbage in uninitialized memory is one of the most common sources of bugs that are hard to reproduce.
4
sizeof(type) is your source of truth for how many bytes a type uses on your specific platform
never assume; always verify when writing portable code.
5
Enable compiler warnings (-Wall -Werror) and treat them as errors
they catch format mismatches, uninitialized variables, and overflow risks before they reach production.
6
Integer division truncates; cast to float/double when you need a decimal result.

Common mistakes to avoid

4 patterns
×

Using an uninitialized variable

Symptom
C does NOT zero-initialize local variables. int score; followed by printf("%d", score); prints whatever random bytes happened to be at that memory address — could be 0, could be 4,291,887.
Fix
Always initialize at declaration: int score = 0;. This single habit eliminates an entire class of bugs.
×

Mismatching the format specifier and data type in printf/scanf

Symptom
Writing printf("%d", 3.14f) or printf("%f", myIntVariable) triggers undefined behaviour. On many machines it silently prints garbage; on others it can crash.
Fix
Memorize the specifier for each type — %d for int, %f for float/double, %c for char, %lld for long long — and double-check every printf and scanf call. Enable compiler warnings.
×

Integer division when you expect a decimal result

Symptom
int a = 5; int b = 2; float result = a / b; prints 2.000000, not 2.500000. Why? Because a / b is evaluated as integer division first (result: 2), and then stored into the float.
Fix
Cast at least one operand to float before dividing: float result = (float)a / b;. This forces floating-point division and gives you 2.500000.
×

Choosing a data type with insufficient range (silent overflow)

Symptom
Using short for a counter that can exceed 32,767 causes overflow without warning. The value wraps to negative, as seen in the Ariane 5 disaster.
Fix
Always estimate the maximum possible value. Use int for general-purpose, long long for large numbers, and unsigned when negatives are impossible.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is the difference between int and unsigned int in C, and when would...
Q02SENIOR
Why does C have both float and double? If double is more precise, why wo...
Q03JUNIOR
What is the output of this code: `int x = 7 / 2; printf("%d", x);` — and...
Q01 of 03JUNIOR

What is the difference between int and unsigned int in C, and when would you choose one over the other? (Follow-up: what happens if you assign -1 to an unsigned int?)

ANSWER
int can store negative and positive values; unsigned int stores only non-negative. Use unsigned when negatives are impossible (array indices, sizes). Assigning -1 to unsigned int causes wrap-around to UINT_MAX because unsigned integers use modulo arithmetic. This is often used intentionally for sentinel values like '~0'.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
What is the difference between float and double in C?
02
Do I have to initialize a variable when I declare it in C?
03
Why does C make you specify a data type at all? Why not just have one universal 'variable' like some other languages?
04
What is the difference between const and #define for constants?
🔥

That's C Basics. Mark it forged?

6 min read · try the examples if you haven't

Previous
Introduction to C Programming
2 / 17 · C Basics
Next
Operators in C