01 · variables, data types & IO
Chapter 1 — how C stores a value, names it, measures it, and moves it in and out. Format specifiers, sizeof, scanf, and the byte underneath.
chapter 1 — variables, data types & IO
← back to C index · V:\KNOWLEDGE\NOTES\C
How C stores a value, names it, measures it, and moves it in and out of a program. The big idea of the whole chapter: a format specifier is a window onto a byte — change the window, not the byte. The memory never moves; only the interpretation does.
core concepts
variables
Containers that store a value. Declaration reserves memory; initialization writes a value into it. They are two separate events — a declared-but-uninitialized variable holds whatever garbage was already in that memory.
int age; // declaration — memory reserved, value undefined
age = 25; // initialization — value written
int year = 2026; // both at once
constants
Entities whose value does not change once set.
data types
A classification that tells the compiler what kind of value a variable holds and how much memory to allocate for it.
| type | stores | note |
|---|---|---|
int | whole numbers | no decimals |
float | numbers with decimals | floating point |
char | a single character | wrap the value in 'single quotes', never " |
comments
Notes for humans, ignored by the compiler: // single line or /* block */.
format specifiers
Placeholders inside printf/scanf that say how to read or display a value.
| specifier | type |
|---|---|
%d | whole number (int) |
%f | floating point (float) |
%c | single character (char) |
%zu | size (size_t, from sizeof) |
escape sequences
Special characters inside a string: \n newline, \t tab, \" / \' literal
quote. They are valid char values — storable and injectable like any other.
sizeof
A unary operator that returns the exact memory size in bytes of a type, variable, or expression. Resolved at compile time, never at runtime.
- Around a type, parentheses are required:
sizeof(int). - Around a variable, they are optional but recommended.
- Returns a
size_t— print it with%zu.
The same variable can be printed two ways in one printf: %c shows the
character, %d shows its ASCII integer. Both read the same byte — only the
display instruction changes. Every % consumes one argument, left to right, so
two specifiers need two arguments even when it's the same variable.
user input — scanf() and &
scanf pauses, waits for input, and writes it into a variable's memory address.
The & (address-of) operator hands scanf the destination address.
&, scanf has nowhere to write&age does not pass the value of age — it passes its address, telling
scanf where in memory to store the data. Omit it and you get undefined
behavior or a crash. This is the foundation of pointers.
code logs
code 03 — format specifiers & data types
Objective: the format specifier controls how a value is displayed, not the value itself. Same byte in memory, different display.
#include <stdio.h>
int main() {
int a = 1;
float b = 1.40;
char c = 'b';
char x = 'a';
printf("valor de a es %d \n", a);
printf("valor de b es %f \n", b);
printf("valor de c es %c \n", c);
printf("valor de x es %d \n", x);
return 0;
}
Output:
valor de a es 1
valor de b es 1.400000
valor de c es b
valor de x es 97
Walkthrough:
int a = 1→%ddisplays1.float b = 1.40→%fdisplays1.400000(six decimals by default).char c = 'b'→%cdisplaysb.char x = 'a'→%ddisplays97, the ASCII value ofa.
char is an integer internally. %c and %d are two instructions for
displaying the same byte. The memory never changes; only the interpretation does.
code 04 — sizeof(), memory size & multiple representations
Objective: variables have a value and a memory size. Both can be printed in one statement. The same variable can appear multiple times to show different representations.
#include <stdio.h>
int main() {
int a = 10;
float b = 3.14;
char c = 'z';
printf("Variable a has value %d and takes %zu bytes\n", a, sizeof(int));
printf("Variable b has value %f and takes %zu bytes\n", b, sizeof(float));
printf("Variable c has value %c as character but %d as number and takes %zu bytes\n",
c, c, sizeof(char));
return 0;
}
Output:
Variable a has value 10 and takes 4 bytes
Variable b has value 3.140000 and takes 4 bytes
Variable c has value z as character but 122 as number and takes 1 bytes
Walkthrough:
int a = 10→ 4 bytes.intis 32-bit; the compiler reserves 4 bytes on the stack for whole numbers.float b = 3.14→ 4 bytes. Floating-point precision:3.14has no exact binary form, so the machine stores the closest representable value. GDB reveals3.140001;printfrounds it to3.140000for display.char c = 'z'→ 1 byte. ASCII fits in 256 combinations; 8 bits suffice. GDB shows122 'z'— the integer value ofz.
Multiple representations in one call:
printf("...%c as character but %d as number...", c, c, sizeof(char));
Each specifier consumes one argument left to right. Two specifiers, two arguments — even when the variable repeats.
Resolved at compile time, never at runtime — the compiler knows every type's
size before execution. Returns a size_t; format with %zu.
code 06 — user input with scanf()
Objective: read three datatypes from the user, store each via the address-of operator, and print each value with its size.
#include <stdio.h>
int main() {
char ini;
int age;
float height;
scanf("%c", &ini);
scanf("%d", &age);
scanf("%f", &height);
printf("Name Initial: %c and value %d and %zu bytes\n", ini, ini, sizeof(char));
printf("Age: %d and %zu bytes\n", age, sizeof(int));
printf("Height: %f %zu bytes \n", height, sizeof(float));
printf("Me llaman el mas piola \n");
return 0;
}
Input:
J
25
1.75
Output:
Name Initial: J and value 74 and 1 bytes
Age: 25 and 4 bytes
Height: 1.750000 4 bytes
Me llaman el mas piola
Walkthrough:
- Variables declared without initialization. GDB shows garbage: memory is reserved, but nothing has been written yet.
- Each
scanfpauses execution, waits for input, and writes the value to the variable's memory address.
The & operator: &ini, &age, &height give scanf the destination address.
Without &, scanf has nowhere to write — undefined behavior or a crash. This is
the address-of operator: the foundation of pointers.
GDB confirms type sizes through address differences:
&ageat0x7fffffffe2a4,&heightat0x7fffffffe2a0→ 4 bytes apart.&iniat0x7fffffffe2ab→ 1 byte from the next variable.
The 0x... notation is hexadecimal — skip it for now. What matters: addresses
are real, and their differences expose type sizes directly.
code 07 — \n as a stored value, char as an injectable variable
Objective: \n lives in a char variable and gets injected into printf like
any other argument — no hardcoding required. A user-input char then prints as
character, ASCII integer, and memory size in a single statement.
#include <stdio.h>
int main() {
char separator = '\n';
char init = 'J';
char apu;
scanf("%c", &apu);
printf("Hello, my name starts with %c %c Nice to meet you %c %c "
"But people also call me %c OR %d OR %zu byte %c THANKS YOU",
init, separator, init, separator, apu, apu, sizeof(char), separator);
return 0;
}
Input:
Z
Output:
Hello, my name starts with J
Nice to meet you J
But people also call me Z OR 90 OR 1 byte
THANKS YOU
Walkthrough:
char separator = '\n'→ stores ASCII 10 (newline).char init = 'J'→ storesJ.char apu→ declared, uninitialized. Garbage in GDB untilscanfwrites.scanf("%c", &apu)→ user supplies a character;scanfwrites it toapu's address.
printf, applied:
- One datatype, one variable, one format specifier per occurrence.
separatorinjects the newline without hardcoding\nin the string — operationally identical, just controlled through a variable.apuappears three times:%cshowsZ,%dshows90,%zushows1. Three views of the same byte.
Every % consumes one argument, left to right. Two specifiers, two arguments.
No exceptions.
concepts covered
| concept | key point |
|---|---|
| declaration vs init | Declaration reserves memory. Initialization writes a value. |
| int, float, char | Different sizes, different valid operations. |
| format specifiers | Control display, not the value. Same byte, different window. |
| sizeof() | Compile-time operator. Returns size_t. Format with %zu. |
| floating point | Binary can't represent all decimals. Closest value is stored. |
| ASCII | char is an integer internally. %c and %d show the same byte. |
| scanf() and & | & passes a memory address. Without it, scanf has no target. |
| memory addresses | Variables live at addresses. Diffs reveal type sizes. |
\n as a value | Escape sequences are valid char values. Storable and injectable. |