Types and variables in C — what changes from Python and what doesn’t
Types and variables in C are the first real shock when you move from Python to C in IC2. In Python you wrote x = 5 and Python figured everything out. In C you have to declare the type, the size and the format specifier for every variable, and if you get any of them wrong the compiler either refuses to compile or produces incorrect results silently.
This article explains every difference clearly, with direct comparisons to Python so nothing is left without context.
Table of Contents
The fundamental difference — static vs dynamic typing
In Python variables have no fixed type. You can write:
x = 5 # int x = "hello" # now str — Python doesn't complain x = 3.14 # now float — still fine
In C every variable has a type that is declared at creation and never changes:
int x = 5; x = "hello"; // compile error — x is int, not a string x = 3.14; // compile error — 3.14 is double, not int
This is called static typing, the type is fixed at compile time and checked before the program runs. This is both stricter and faster than Python’s dynamic typing.
Why C requires type declarations
C runs directly on hardware — there’s no interpreter between your code and the processor. When you declare int x, C reserves exactly 4 bytes of memory for x and knows it will always contain a 32-bit integer. The processor can then access and operate on that memory as efficiently as possible.
Python’s flexibility comes at a cost — every Python object carries metadata about its type at runtime, which takes extra memory and processing time. C skips all that overhead by knowing the types at compile time.
The basic types in C
int x = 5; // integer — 4 bytes, -2,147,483,648 to 2,147,483,647 float f = 3.14f; // decimal, single precision — 4 bytes double d = 3.14159; // decimal, double precision — 8 bytes (more precise) char c = 'A'; // single character — 1 byte
Note the semicolons, every statement in C ends with ;. Forgetting it is the most common compile error for Python programmers.
Comparing type systems
Python C Size ───────────────────────────────────────── int int 4 bytes float double 8 bytes str char[] varies bool int (0 or 1) 4 bytes (no equivalent) char 1 byte (no equivalent) float 4 bytes
Integers — int and its variants
The basic integer type is int. C also has smaller and larger variants:
char c = 65; // 1 byte: -128 to 127 short s = 30000; // 2 bytes: -32,768 to 32,767 int i = 1000000; // 4 bytes: -2,147,483,648 to 2,147,483,647 long l = 9000000000L; // 8 bytes: very large numbers
In IC2 you’ll use int for almost everything. Use long when a number might exceed ~2 billion. The L suffix tells C the literal is a long.
You can also declare unsigned integers that can’t be negative but can store larger positive values:
unsigned int ui = 4000000000U; // 0 to 4,294,967,295 unsigned char uc = 200; // 0 to 255
Decimal numbers — float vs double
float f = 3.14f; // ~7 decimal digits of precision double d = 3.14159265; // ~15 decimal digits of precision
Use double by default in IC2, it has more precision and printf/scanf use it by default. Use float only when memory is a concern (which it won’t be in IC2).
The f suffix on a float literal is important:
float f = 3.14; // warning: implicit conversion from double to float float f = 3.14f; // correct — f suffix makes it a float literal
Characters — char and ASCII
char stores a single character as its ASCII numeric value:
char c = 'A'; // stores 65 (ASCII code for 'A') char c = 65; // same thing — stores 65, displays as 'A'
Single quotes for char, always. In Python single and double quotes were interchangeable for strings. In C single quotes are strictly for single characters:
char c = 'A'; // correct — single character char c = "A"; // wrong — "A" is a string, not a char
You can do arithmetic with chars because they’re just numbers:
char c = 'A';
printf("%c\n", c + 1); // → B (65 + 1 = 66 = 'B')
printf("%d\n", c); // → 65 (the ASCII code)
Declaring variables in C
In C variables must be declared before they can be used. In older C standards (C89/C90) all declarations had to come before any other statements at the top of a function block. In modern C (C99 and later, which IC2 uses) you can declare variables anywhere:
#include <stdio.h>
int main() {
int a = 5;
int b = 3;
int result; // declared without a value
result = a + b; // assigned later
printf("%d\n", result);
return 0;
}
You can declare multiple variables of the same type in one line:
int x = 1, y = 2, z = 3; double a, b, c; // declared without values
printf — formatted output in C
In Python you used print() and f-strings. In C you use printf() with format specifiers, placeholders that tell C what type to print and how to format it:
# Python
name = "Sergio"
age = 20
grade = 7.5
print(f"Name: {name}, Age: {age}, Grade: {grade:.2f}")
// C
char name[] = "Sergio";
int age = 20;
double grade = 7.5;
printf("Name: %s, Age: %d, Grade: %.2f\n", name, age, grade);
Format specifiers
%d → int %f → float or double (6 decimal places by default) %.2f → float/double with exactly 2 decimal places %e → scientific notation (1.234567e+02) %c → char (character) %s → string (char array) %ld → long int %lf → double (in scanf — see below) %u → unsigned int %x → hexadecimal %o → octal %% → literal % sign
int i = 42;
double d = 3.14159;
char c = 'A';
printf("%d\n", i); // → 42
printf("%.2f\n", d); // → 3.14
printf("%c is %d\n", c, c); // → A is 65
printf("%10d\n", i); // → " 42" (right-aligned, 10 wide)
printf("%-10d|\n", i); // → "42 |" (left-aligned)
printf("%05d\n", i); // → "00042" (zero-padded)
Escape sequences in printf
\n → newline \t → tab \\ → backslash \" → double quote \0 → null character (string terminator)
scanf — reading input in C
scanf is the C equivalent of input(), but it works very differently:
# Python
name = input("Name: ")
age = int(input("Age: "))
grade = float(input("Grade: "))
// C
char name[50];
int age;
double grade;
printf("Name: ");
scanf("%s", name); // reads a word (stops at space)
printf("Age: ");
scanf("%d", &age); // & is required for non-array types
printf("Grade: ");
scanf("%lf", &grade); // %lf for double in scanf (not %f)
The & in scanf — why it’s required
This is the most confusing part of scanf for beginners. The & before a variable name gives scanf the memory address of that variable so it can store the value there:
int age;
scanf("%d", &age); // & gives scanf the address of age
// scanf writes the value directly into that memory location
Without & you’d be passing the current (undefined) value of age to scanf instead of its address, undefined behaviour, usually a crash.
The exception: arrays (including strings) don’t need & because the array name itself is already an address:
char name[50];
scanf("%s", name); // no & needed — name is already an address
scanf format specifiers — the differences from printf
// IMPORTANT: scanf uses %lf for double, printf uses %f
double d;
scanf("%lf", &d); // scanf: %lf for double
printf("%f\n", d); // printf: %f for double (or %.2f, etc.)
// int
int i;
scanf("%d", &i);
// char
char c;
scanf(" %c", &c); // note the space before %c — skips whitespace
Reading a full line with spaces
scanf("%s") stops at the first space. To read a full line including spaces:
char full_name[100];
scanf(" %[^\n]", full_name); // reads until newline
Or use fgets:
char full_name[100]; fgets(full_name, 100, stdin); // safer — limits to 100 characters
Operators in C — same as Python with small differences
Arithmetic operators are the same as Python:
int a = 10, b = 3; int sum = a + b; // 13 int diff = a - b; // 7 int prod = a * b; // 30 int div = a / b; // 3 ← integer division! (not 3.333...) int mod = a % b; // 1 ← remainder
The integer division trap
# Python 10 / 3 # → 3.333... (always float) 10 // 3 # → 3 (floor division)
// C int a = 10, b = 3; int result = a / b; // → 3 (integer division — decimal part dropped) double result = 10.0 / 3; // → 3.333... (at least one operand must be double) double result = (double)a / b; // → 3.333... (cast a to double first)
In C, dividing two integers always gives an integer result. To get decimals you need at least one operand to be a double, either use a literal like 10.0 or cast with (double).
Increment and decrement operators
int x = 5; x++; // x is now 6 (post-increment) x--; // x is now 5 (post-decrement) ++x; // x is now 6 (pre-increment) --x; // x is now 5 (pre-decrement) x += 3; // x = x + 3 x -= 2; // x = x - 2 x *= 4; // x = x * 4 x /= 2; // x = x / 2 x %= 3; // x = x % 3
Type casting in C
To convert between types explicitly:
int i = 7; double d = (double)i; // int to double → 7.0 int truncated = (int)3.99; // double to int → 3 (truncates, doesn't round) char c = (char)65; // int to char → 'A' int ascii = (int)'A'; // char to int → 65
Constants in C
Use const for values that shouldn’t change, equivalent to Python’s convention of UPPERCASE names:
# Python (convention only, not enforced) PI = 3.14159
// C (enforced by compiler) const double PI = 3.14159; const int MAX_SIZE = 100; PI = 4.0; // compile error: assignment of read-only variable 'PI'
The #define preprocessor directive is another way to define constants:
#define PI 3.14159 #define MAX_SIZE 100
#define doesn’t have a type and is replaced by a text substitution before compilation. const is preferred in modern C because the compiler can type-check it.
A complete example — putting it all together
#include <stdio.h>
int main() {
// Variable declarations
char name[50];
int age;
double height;
char initial;
// Reading input
printf("Enter your name: ");
scanf("%s", name);
printf("Enter your age: ");
scanf("%d", &age);
printf("Enter your height in metres: ");
scanf("%lf", &height);
// Calculate some values
double height_cm = height * 100;
int birth_year = 2025 - age;
int is_adult = age >= 18; // 1 (true) or 0 (false)
initial = name[0]; // first character of name
// Display results
printf("\n--- Profile ---\n");
printf("Name: %s\n", name);
printf("Initial: %c\n", initial);
printf("Age: %d years\n", age);
printf("Height: %.2f m (%.1f cm)\n", height, height_cm);
printf("Born: %d\n", birth_year);
printf("Adult?: %s\n", is_adult ? "Yes" : "No");
return 0;
}
Compile and run:
gcc profile.c -o profile -Wall ./profile
Output:
Enter your name: Sergio Enter your age: 20 Enter your height in metres: 1.78 --- Profile --- Name: Sergio Initial: S Age: 20 years Height: 1.78 m (178.0 cm) Born: 2005 Adult?: Yes
Python vs C — complete comparison table
CONCEPT PYTHON C
─────────────────────────────────────────────────────────────
Variable x = 5 int x = 5;
Integer x = 5 int x = 5;
Decimal x = 3.14 double x = 3.14;
Character c = "A" char c = 'A';
String s = "hello" char s[] = "hello";
Constant PI = 3.14 (conv.) const double PI = 3.14;
Print int print(x) printf("%d\n", x);
Print decimal print(f"{x:.2f}") printf("%.2f\n", x);
Print string print(s) printf("%s\n", s);
Read int int(input("Age: ")) scanf("%d", &age);
Read decimal float(input(...)) scanf("%lf", &d);
Read string input("Name: ") scanf("%s", name);
Integer division 10 // 3 → 3 10 / 3 → 3 (automatic)
Float division 10 / 3 → 3.333 (double)10 / 3 → 3.333
Increment x += 1 x++ or ++x
Modulo x % y x % y (same)
Quick summary
// TYPES
int i = 5; // integer
double d = 3.14; // decimal (use this, not float)
char c = 'A'; // single character (single quotes)
float f = 3.14f; // less precise decimal (avoid unless needed)
long l = 9000000L; // large integer
// DECLARATIONS
int x; // declared without value — garbage value inside
int x = 5; // declared with value
int x, y, z; // multiple declarations
const int N = 10; // constant — cannot change
// PRINTF FORMAT SPECIFIERS
%d → int %f → float/double
%.2f → 2 decimals %c → char
%s → string %ld → long
%e → scientific %% → literal %
// SCANF — note the & and %lf
scanf("%d", &i); // int — & required
scanf("%lf", &d); // double — %lf not %f
scanf("%c", &c); // char — & required
scanf("%s", str); // string — no & needed
// INTEGER DIVISION TRAP
int a = 7, b = 2;
a / b // → 3 (drops decimal)
(double)a / b // → 3.5 (cast to double first)
// CASTING
(int)3.99 // → 3 (truncates)
(double)7 // → 7.0
(char)65 // → 'A'
// OPERATORS
++x x++ --x x-- // increment/decrement
+= -= *= /= %= // compound assignment
// COMMON ERRORS
// 1. Missing ; at end of statement → syntax error
// 2. Missing & in scanf (except strings) → crash
// 3. %f instead of %lf in scanf for double → wrong value
// 4. Integer division when you expected decimal
// 5. Single quotes for char, double quotes for strings
In the next article we practice C types and variables with real programs compiled and run in your Fedora terminal.
