types and variables in C printf scanf Python comparison IC2 guide

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.

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.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *