C Notes
Complete guide to C data types — primary types (int, char, float, double), derived types (arrays, pointers, structures), type modifiers (short, long, signed, unsigned), sizeof operator, type conversion, and memory representation with examples.
In C, every variable must have a declared type. The type tells the compiler three things: (1) how much memory to allocate, (2) how to interpret the bits stored in that memory, and (3) what operations are valid on that data.
Unlike Python where x = 5 just works and the type is figured out automatically, in C you must explicitly say int x = 5; — telling the compiler "allocate 4 bytes, interpret them as a signed integer."
Why Data Types Matter in C
#include <stdio.h>
int main() {
// Same 4 bytes of memory, interpreted differently:
int asInt = 1065353216;
float asFloat = *(float *)&asInt; // Reinterpret same bits as float
printf("Same bits as int: %d\n", asInt);
printf("Same bits as float: %f\n", asFloat);
// The point: the TYPE determines how bits are interpreted
// 01000000 00000000 00000000 00000000
// As int: 1065353216
// As float: 1.000000
return 0;
}Same bits as int: 1065353216 Same bits as float: 1.000000
Classification of C Data Types
Primary (Fundamental) Data Types
int — Integer Numbers
The most commonly used type. Stores whole numbers without decimal points.
#include <stdio.h>
#include <limits.h>
int main() {
int age = 25;
int population = 1400000000;
int temperature = -15;
int hexValue = 0xFF; // Hexadecimal (255)
int octalValue = 077; // Octal (63)
int binaryValue = 0b1010; // Binary (10) — C23
printf("age = %d\n", age);
printf("population = %d\n", population);
printf("temperature = %d\n", temperature);
printf("hex 0xFF = %d\n", hexValue);
printf("octal 077 = %d\n", octalValue);
// Size and range
printf("\nint size: %lu bytes\n", sizeof(int));
printf("int range: %d to %d\n", INT_MIN, INT_MAX);
return 0;
}age = 25 population = 1400000000 temperature = -15 hex 0xFF = 255 octal 077 = 63 int size: 4 bytes int range: -2147483648 to 2147483647
char — Characters
Stores a single character (technically a small integer, 1 byte):
#include <stdio.h>
int main() {
char letter = 'A';
char digit = '7';
char newline = '\n';
char tab = '\t';
char nullChar = '\0';
// char is actually a number (ASCII value)
printf("'A' = %c (ASCII: %d)\n", letter, letter);
printf("'7' = %c (ASCII: %d)\n", digit, digit);
printf("'a' = %c (ASCII: %d)\n", 'a', 'a');
printf("'Z' = %c (ASCII: %d)\n", 'Z', 'Z');
// You can do arithmetic with chars!
char uppercase = 'a' - 32; // Convert lowercase to uppercase
printf("\n'a' - 32 = '%c' (ASCII math!)\n", uppercase);
// Check if character is uppercase
char ch = 'G';
if (ch >= 'A' && ch <= 'Z') {
printf("'%c' is uppercase\n", ch);
}
printf("\nchar size: %lu byte\n", sizeof(char));
printf("char range: %d to %d\n", -128, 127);
return 0;
}'A' = A (ASCII: 65) '7' = 7 (ASCII: 55) 'a' = a (ASCII: 97) 'Z' = Z (ASCII: 90) 'a' - 32 = 'A' (ASCII math!) 'G' is uppercase char size: 1 byte char range: -128 to 127
float — Single-Precision Floating Point
Stores decimal numbers with ~6-7 digits of precision:
#include <stdio.h>
#include <float.h>
int main() {
float pi = 3.14159f; // 'f' suffix for float literal
float gravity = 9.81f;
float price = 99.99f;
float scientific = 6.022e23f; // Scientific notation
printf("pi = %.5f\n", pi);
printf("gravity = %.2f\n", gravity);
printf("price = %.2f\n", price);
printf("Avogadro = %e\n", scientific);
// Precision limitation!
float bigFloat = 123456789.0f;
printf("\n123456789 stored as float: %.0f\n", bigFloat);
printf("(Notice: precision lost after ~7 digits!)\n");
printf("\nfloat size: %lu bytes\n", sizeof(float));
printf("float precision: %d significant digits\n", FLT_DIG);
printf("float range: %e to %e\n", FLT_MIN, FLT_MAX);
return 0;
}pi = 3.14159 gravity = 9.81 price = 99.99 Avogadro = 6.022000e+23 123456789 stored as float: 123456792 (Notice: precision lost after ~7 digits!) float size: 4 bytes float precision: 6 significant digits float range: 1.175494e-38 to 3.402823e+38
double — Double-Precision Floating Point
Twice the precision of float (~15-16 significant digits). Use this as your default for decimals:
#include <stdio.h>
#include <float.h>
#include <math.h>
int main() {
double pi = 3.141592653589793;
double electronMass = 9.10938e-31; // kg
double lightSpeed = 299792458.0; // m/s
printf("pi = %.15f\n", pi);
printf("Electron mass = %.5e kg\n", electronMass);
printf("Speed of light = %.0f m/s\n", lightSpeed);
// Mathematical operations with precision
double result = sqrt(2.0);
printf("\nsqrt(2) = %.15f\n", result);
// double vs float precision comparison
float fResult = 1.0f / 3.0f;
double dResult = 1.0 / 3.0;
printf("\n1/3 as float: %.20f\n", fResult);
printf("1/3 as double: %.20f\n", dResult);
printf("\ndouble size: %lu bytes\n", sizeof(double));
printf("double precision: %d significant digits\n", DBL_DIG);
return 0;
}pi = 3.141592653589793 Electron mass = 9.10938e-31 kg Speed of light = 299792458 m/s sqrt(2) = 1.414213562373095 1/3 as float: 0.33333334326744080000 1/3 as double: 0.33333333333333331000 double size: 8 bytes double precision: 15 significant digits
void — No Type
void means "nothing" or "no type." It's used in three contexts:
Hello, Developer! Random: 42 Generic pointer demo: 42 3.14 A
Type Modifiers
Modifiers change the size or sign behavior of base types:
short and long — Size Modifiers
Type Size Value ────────────────────────────────────── short 2 bytes 32000 int 4 bytes 2000000000 long 8 bytes 2000000000 long long 8 bytes 9000000000000000000 Ranges: short: -32768 to 32767 int: -2147483648 to 2147483647 long: -9223372036854775808 to 9223372036854775807 long long: -9223372036854775808 to 9223372036854775807
signed and unsigned — Sign Modifiers
#include <stdio.h>
#include <limits.h>
int main() {
// signed (default) — can hold negative values
signed int temperature = -15;
// unsigned — only positive values, but DOUBLE the positive range
unsigned int fileSize = 4294967295U; // Max value for unsigned int
unsigned int age = 25;
unsigned int count = 0;
printf("signed int range: %d to %d\n", INT_MIN, INT_MAX);
printf("unsigned int range: 0 to %u\n", UINT_MAX);
printf("\ntemperature: %d\n", temperature);
printf("fileSize: %u\n", fileSize);
// Practical use cases for unsigned:
// - File sizes (can't be negative)
// - Array indices (can't be negative)
// - Bit manipulation (cleaner behavior)
// - Network protocols (byte values 0-255)
unsigned char byte = 255; // Full byte range: 0-255
printf("\nunsigned char: 0 to %d\n", 255);
printf("signed char: %d to %d\n", -128, 127);
// WARNING: unsigned underflow!
unsigned int x = 0;
x = x - 1; // Wraps around to maximum value!
printf("\nDanger! 0u - 1 = %u (wraparound!)\n", x);
return 0;
}signed int range: -2147483648 to 2147483647 unsigned int range: 0 to 4294967295 temperature: -15 fileSize: 4294967295 unsigned char: 0 to 255 signed char: -128 to 127 Danger! 0u - 1 = 4294967295 (wraparound!)
The sizeof Operator
sizeof returns the number of bytes a type or variable occupies:
=== Size of All Types === Fundamental types: char: 1 byte short: 2 bytes int: 4 bytes long: 8 bytes long long: 8 bytes float: 4 bytes double: 8 bytes long double: 16 bytes Pointers (all same size on a given platform): int*: 8 bytes char*: 8 bytes double*: 8 bytes void*: 8 bytes Arrays: int[10]: 40 bytes (10 × 4) Structures: Student: 60 bytes (may include padding for alignment)
Type Conversion (Casting)
Implicit Conversion (Automatic)
C automatically converts smaller types to larger types in expressions:
#include <stdio.h>
int main() {
// Implicit widening: char → int → long → float → double
char c = 'A';
int i = c; // char → int (automatic)
float f = i; // int → float (automatic)
double d = f; // float → double (automatic)
printf("char 'A' = %d (as int)\n", i);
printf("int 65 = %.1f (as float)\n", f);
printf("float 65.0 = %.1f (as double)\n", d);
// In mixed expressions, smaller type promotes to larger
int x = 10;
double y = 3.0;
double result = x + y; // x is promoted to double before addition
printf("\n10 + 3.0 = %.1f (int promoted to double)\n", result);
// Integer division TRAP!
int a = 7, b = 2;
printf("\n7 / 2 = %d (integer division — truncated!)\n", a / b);
printf("7 / 2.0 = %.1f (one operand is double → result is double)\n", a / 2.0);
return 0;
}char 'A' = 65 (as int) int 65 = 65.0 (as float) float 65.0 = 65.0 (as double) 10 + 3.0 = 13.0 (int promoted to double) 7 / 2 = 3 (integer division — truncated!) 7 / 2.0 = 3.5 (one operand is double → result is double)
Explicit Conversion (Type Casting)
When you need to force a conversion:
17 / 5 = 3.40 (int)99.99 = 99 (truncated) (char)72 = 'H' int 0x41424344 as bytes: 'D' 'C' 'B' 'A'
Complete Size Reference Table
| Type | Size (typical) | Range | Format Specifier |
|---|---|---|---|
char | 1 byte | -128 to 127 | %c (char), %d (int) |
unsigned char | 1 byte | 0 to 255 | %u |
short | 2 bytes | -32,768 to 32,767 | %hd |
unsigned short | 2 bytes | 0 to 65,535 | %hu |
int | 4 bytes | -2.1B to 2.1B | %d |
unsigned int | 4 bytes | 0 to 4.2B | %u |
long | 4/8 bytes | Platform dependent | %ld |
unsigned long | 4/8 bytes | Platform dependent | %lu |
long long | 8 bytes | -9.2×10¹⁸ to 9.2×10¹⁸ | %lld |
float | 4 bytes | ±3.4×10³⁸ (6-7 digits) | %f, %e |
double | 8 bytes | ±1.7×10³⁰⁸ (15-16 digits) | %lf, %e |
long double | 12/16 bytes | Extended precision | %Lf |
Interview Questions
Q1: What are the primary data types in C?
Answer: C has five primary (fundamental) data types: int (integers, 4 bytes), char (characters, 1 byte), float (single-precision decimals, 4 bytes), double (double-precision decimals, 8 bytes), and void (no type — used for functions returning nothing and generic pointers).
Q2: What is the difference between float and double?
Answer: float is 4 bytes with ~6-7 digits of precision. double is 8 bytes with ~15-16 digits of precision. double is the default for decimal literals in C (writing 3.14 creates a double, not float). Use double for most calculations to avoid precision loss; use float only when memory is constrained (embedded systems, large arrays).
Q3: What happens when you assign a float value to an int variable?
Answer: The decimal part is truncated (not rounded). For example, int x = 9.99; stores 9, and int y = -3.7; stores -3. This is called implicit narrowing conversion. The compiler may issue a warning about potential data loss.
Q4: Explain the difference between signed and unsigned integers.
Answer: signed integers (default) use one bit for the sign, allowing negative values. Range: -2³¹ to 2³¹-1. unsigned integers use all bits for magnitude, only allowing positive values. Range: 0 to 2³²-1. Use unsigned for values that are never negative (file sizes, counts, flags) to get double the positive range.
Q5: What does sizeof return and when would you use it?
Answer: sizeof returns the number of bytes occupied by a type or variable, as a size_t value (compile-time constant for types, runtime for VLAs). Use it for: (1) dynamic memory allocation (malloc(n * sizeof(int))), (2) calculating array lengths (sizeof(arr)/sizeof(arr[0])), (3) writing portable code that doesn't assume type sizes, (4) determining struct sizes including padding.
Summary
C's type system is the foundation of everything you write. The primary types (int, char, float, double, void) cover basic data needs. Modifiers (short, long, signed, unsigned) let you fine-tune range and memory usage. The sizeof operator tells you exactly how much memory each type uses on your system. Understanding type conversion (both implicit and explicit) prevents subtle bugs that arise from mixing types in expressions. Always choose the smallest type that safely holds your data — especially in embedded systems where memory is precious.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Data Types in C.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this C Programming topic.
Search Terms
c-programming, c programming, programming, basics, data, types, data types in c
Related C Programming Topics