Unlock C Basic Data Types with deep yet simple insights. Start as a beginner, uncover hidden coding secrets, and master the fundamentals with confidence!
RAM: The Short-Term Memory of Your Computer
RAM (Random Access Memory) is a type of memory that helps your computer work quickly by storing information it needs at the moment. It acts as a temporary workspace for the computer, allowing it to access and manage data rapidly.
When you turn on the computer, RAM starts empty. The system immediately loads essential programs into RAM to make the computer functional. These programs are critical because, without them, the computer wouldn’t be able to manage or store any new information in RAM.
Once the essential programs are in place, RAM is ready to store other information you need. For example, if you create a number like int x = 5;
, the value 5
is temporarily stored in RAM while your program runs. This allows the computer to process and retrieve the value quickly.
When you close a program, the memory it was using gets cleared. But the memory being used by other programs stays the same. For example, if you have several programs open, closing one will free up the space it was using, but the other programs will keep their memory. Only the memory for the program that’s finished will be cleared, not all the memory in your computer.
However, RAM only holds data as long as the computer is on. When you turn off the computer, all the information in RAM disappears. The next time you power it on, RAM starts fresh again, loading the essential programs to prepare for new tasks.
To sum it up, when you shut down your computer, everything in RAM gets wiped out because RAM is temporary memory that resets once the power is off. But when a program finishes running, only the memory used by that program gets cleared. The rest of the data in RAM stays intact. So, shutting down your computer clears all of RAM, while closing a program only removes the data that program was using.
Since RAM is temporary, any unsaved data is lost when the program stops or the computer shuts down. When a program ends, the data it used in RAM is erased. Similarly, when you turn off your computer, everything in RAM is cleared. To avoid losing important information, always save it to permanent storage, like a hard drive or SSD, before the program finishes or the computer is turned off.
CPU: The Brain of the Computer
The CPU, or the computer’s brain, doesn’t do all the work itself. Instead, it’s like the boss who makes sure everything runs smoothly by telling other parts of the computer what to do.
Now, when it comes to the actual work—like adding numbers—that’s handled by parts inside the CPU, like the ALU (Arithmetic Logic Unit). The CPU gives instructions to the components inside it, as well as those outside of it, to get things done.
The CPU also takes charge of other parts of the computer, like memory (RAM). It tells RAM how to manage and store data temporarily while the computer is running.
So, even though the CPU is in control, it doesn’t do everything directly. It counts on other components to do their own specialized tasks.
Who Handles the Movement of Data into RAM?
The CPU decides what data is needed and stores it in RAM while the computer is on. But here’s the catch—the CPU doesn’t move the data into RAM itself. That job goes to the memory controller.
The memory controller is the one who actually transfers the data into RAM, so the CPU can use it.
The process starts when the compiler converts the program into machine code. Once that’s done, the memory controller puts the data into RAM on its own.
After the code is in RAM, the CPU can start giving instructions to the rest of the computer, including the memory controller. It tells them what to do—whether it’s calculating something, storing more data, or other tasks.
When Does the CPU Start Working?
The CPU only starts working once the data is already in RAM. Once it’s in there, the CPU reads the instructions and begins executing them. It then passes on instructions to other parts of the computer to carry out specific tasks—like performing calculations, managing memory, or interacting with storage.
1. Getting Data into RAM:
- When you run a program, the CPU doesn’t immediately tell the memory controller what to do. Instead, the compiler translates the code into machine code first.
- The memory controller is responsible for transferring the data to RAM, so everything the CPU needs can be stored and ready.
2. The CPU Starts Executing:
- Once the data is in RAM, the CPU starts reading those instructions. It looks through the machine code and begins executing one step at a time.
3. CPU Controls Memory Access:
- Now that the data is in RAM, the CPU can give instructions to the memory controller. It tells the controller to retrieve or manage specific data as needed for its tasks.
4. Performing Tasks:
- Finally, the CPU works with other parts of the computer, like the arithmetic unit for calculations or storage devices, to get things done. It sends out commands to make sure everything happens smoothly and efficiently.
Imagine the CPU as a worker who’s got a set of tasks to complete. But before the worker can start, they need all the materials (the data) ready and waiting in their workspace (RAM). The CPU doesn’t give the orders to bring the materials in yet. Instead, the compiler steps in first. It’s like a translator that takes the program’s code and turns it into something the worker (CPU) can understand.
Once the code is all translated into machine language, the memory controller takes over. Think of it like a helpful assistant who gathers up the materials and moves them into the workspace (RAM). The memory controller does this on its own, without needing any instructions from the CPU. It just makes sure everything’s ready and waiting in RAM for when the CPU is ready to start working.
Now, with everything in RAM, the CPU can get to work. It starts reading through the instructions, following them one by one. At this point, the CPU can start telling the memory controller what to do—like grabbing more materials from RAM when needed or organizing things to make the job easier.
As the worker (CPU) moves through tasks, they might need some extra tools—like a calculator for complex math. The CPU sends out instructions to other parts of the computer to handle those jobs, making sure everything gets done efficiently.
Compilers: Translating Human Code into Machine Language
When you write a program in C, the computer can’t understand it because it’s meant for humans. To make it work, we use a tool called a compiler. The compiler translates your program into machine code—just a bunch of 0s and 1s—that the computer can understand.
This process happens in steps. First, in Preprocessing, things like comments are removed and any shortcuts you used are taken care of. Then, Compilation checks the code for errors and turns it into a form called assembly language.
Next, in the Assembly step, the code is turned into machine code. Finally, during Linking, everything is put together into one final file that the computer can run.
Binary: The Language of Computers
In everyday life, we use the decimal system, which is based on 10 digits (from 0 to 9). We start counting from 0 and go up to 9, and then we move on to numbers like 10, 11, 12, and so on. These numbers are just different combinations of the digits 0 to 9, and we can create any number by arranging them in various ways.
Computers, however, work a bit differently. They use the binary system, which only has 2 digits: 0 and 1. Despite having just these two digits, the computer can still represent many numbers and perform complex tasks by combining them in different ways.
There are other number systems, like octal (base 8) and hexadecimal (base 16), but binary and decimal are the most commonly used.
Computers use 0 and 1 because their circuits can only be on or off. This makes binary a simple way to store and work with information. By combining these two numbers, computers can represent all kinds of things, like numbers, text, and even pictures, and perform tasks easily.
Memory is divided into small units called bytes. A byte is the smallest piece of memory and is made up of 8 bits (which are just 0s or 1s). Each byte can store one piece of data, like a number, letter, or part of a larger value.
01000111 is a byte, made up of 8 bits.
Each 0 or 1 is a bit, and a byte is 8 bits.
0 can be 1, and 1 can be 0; we just write it this way.
CQuestions on Binary? I Won’t Answer Them Here
For now, we just need a simple idea of binary to understand how data types are stored in memory. We won’t go deep into how binary works, just enough to know that data is stored this way. This will help us understand how things like numbers and characters are represented in C, without getting too technical.
Understanding Data Types and How They Affect Memory
In programming, data types are like different kinds of containers that help the computer understand how to store and work with different kinds of information. Depending on what you need to store, the size and shape of the container (or memory space) will change.
For example, an int
is a type of container used to store whole numbers, and it usually takes up 4 bytes. This means it can hold numbers like 10, -200, or even a million. If you need to store decimal numbers, like 3.14 or -0.001, you’d use a float
, which also uses 4 bytes but can handle decimals. For even more precision, you’d use a double
, which takes 8 bytes of memory.
Most of the time, the computer will assume a type like int
is signed by default. That means it can handle both positive and negative numbers. For example, int a = 10;
lets a
hold positive numbers like 10 or negative ones like -10.
But sometimes, you might only need to store positive numbers. This is where unsigned types come in, like unsigned int
. By using unsigned
, you’re telling the computer, “I only want positive numbers.” Because of this, the computer can store larger positive numbers, since it doesn’t need to use any memory to store negative values.
It’s also really important to remember that not all types are always signed by default. In some situations, you should decide yourself whether a type should be signed or unsigned because the default behavior can change depending on your system or compiler. To make sure everything works as expected, it’s a good idea to always specify whether you want a type to be signed or unsigned.
The difference between signed and unsigned types comes down to how the computer uses memory. For signed types, one bit is used to keep track of whether the number is positive or negative, leaving fewer bits for the actual number itself. For unsigned types, every bit is used for the number, so unsigned types can hold larger positive values.
In the end, data types are like a map for the computer, telling it how much memory to use for each piece of data—whether it’s a number or a decimal. By choosing the right type, you help the computer handle data efficiently and store things in the right way.
How do 1 byte, 4 bytes, and 8 bytes look in binary?
1 Byte (8 bits):
10000000 (128)
// This stores a 'char' or character
//(typically one byte in size)
C4 Bytes (32 bits):
10000000 00000000 00000000 00000000 (2147483648)
// This stores an integer (whole number)
// or a float (decimal number)
C8 Bytes (64 bits):
10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 (9223372036854775808)
// This stores a double
CHow to Read Binary Numbers: Understanding the Value of 0s and 1s
Position (Pos) | 2^7 | 2^6 | 2^5 | 2^4 | 2^3 | 2^2 | 2^1 | 2^0 |
Value (Val) | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
Each bit of one byte | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
Binary numbers are how computers store and process information. They only use two digits: 0 and 1. These digits are called “bits,” and each bit has a value based on where it is in the sequence.
The value of each bit depends on its position. Starting from the rightmost bit, the first one represents 2^0 = 1. The second bit represents 2^1 = 2, the third bit represents 2^2 = 4, then 2^3 = 8, 2^4 = 16, and so on. Each position doubles the value of the one before it.
To figure out what a binary number means, look at the bits that are 1. Each 1 adds the value of its position. If a bit is 0, you skip it because it doesn’t contribute anything to the total.
Take 10110000 as an example. The first 1 is in the 2^7 position, which is worth 128. The next 1 is in the 2^5 position, worth 32. The third 1 is in the 2^4 position, worth 16.
The bits with 0s, such as 2^6 = 64, 2^3 = 8, 2^2 = 4, and 2^1 = 2, are ignored. When you add up the values of the 1s, you get 128 + 32 + 16 = 176.
This is the basic idea of how binary works. You simply add up the values where there’s a 1. Once you understand how each bit’s position represents a power of 2, it becomes easy to convert between binary and decimal. It’s just a matter of adding the right numbers together!
Byte 1: 10000000 -> Value = 128 // Highest value (2^7)
Byte 2: 01000000 -> Value = 64 // Next highest value (2^6)
Byte 3: 00100000 -> Value = 32 // (2^5)
Byte 4: 00010000 -> Value = 16 // (2^4)
Byte 5: 00001000 -> Value = 8 // (2^3)
Byte 6: 00000100 -> Value = 4 // (2^2)
Byte 7: 00000010 -> Value = 2 // (2^1)
Byte 8: 00000001 -> Value = 1 // Lowest value (2^0)
CBinary | Decimal | Character |
01000001 | 65 | ‘A’ |
01100001 | 97 | ‘a’ |
A byte is made up of 8 bits. Each bit represents a number: 1, 2, 4, 8, 16, 32, 64, and 128. These numbers follow a pattern that doubles each time as you move to the left.
To understand a binary number, you add the values of the bits that are 1. For example, take the binary number 01000001. The second bit from the right is 1, and it represents 64. The last bit is also 1, and it represents 1. Adding 64 and 1 gives you 65.
This same binary number, 01000001, also stands for the letter A in ASCII, a system used to store characters as numbers.
In a computer, data is stored using bits. A bit can either be 0 or 1. When you group 8 bits together, you get a byte. Each bit in a byte represents a power of 2. This is how computers organize and store all kinds of data, whether it’s numbers or letters.
In programming, data types tell the computer how much memory to use for different kinds of data. For example, a char (character) usually takes 1 byte, while an int (integer) typically uses 4 bytes.
The compiler is responsible for translating the program’s code into machine code. This machine code is then loaded into the computer’s RAM by the memory controller. The CPU doesn’t give instructions to the memory controller during this process—it just waits for the data to be ready in memory.
Once the data is in RAM, the CPU can start working. It reads the instructions and sends them to its ALU (Arithmetic Logic Unit) to perform calculations and other tasks. As the program continues, the CPU sends commands to the memory controller to retrieve or update data in RAM.
ASCII TABLE
ASCII is a system that helps computers understand text because computers only work with numbers, not letters or symbols.
Each letter or symbol is given a number. For example, the letter ‘A’ is given the number 65.
The computer turns that number into 1s and 0s, which the CPU (the brain of the computer) can understand.
The CPU sees 65, not ‘A’. So, when the computer processes ‘A’, it stores the number 65, not the letter ‘A’.
When you use 65, the computer sees it as just a number. It stores it like any other number.
But when you use ‘A’, the computer still stores 65. The difference comes in how it interprets the value.
If you use %c, the computer knows to look at the ASCII table and show A, because A is represented by 65 there.
But if you use %d, the computer just shows 65. It’s like saying, “Just give me the number.”
So, %c means, “Show me the character for this number,” while %d means, “Show me the number itself.”
That’s why %c will show A for ‘A’, but %d will show 65 for ‘A’.
It’s all about telling the computer how you want to see the value. That’s how ASCII works—numbers become characters when you tell the computer to treat them that way.
All computers are made to use the same ASCII system or table. This ensures they “speak the same language,” so they can understand each other. By following the same ASCII rules, different computers can share text and data correctly, even if they are made by different manufacturers or run different programs.
The computer stores the binary data in RAM, which is its memory.
This system ensures that all computers can read and share text the same way.
When one computer sends the number 65, the other computer knows it means the letter ‘A’ because both use the same ASCII system.
However, if you send 65 as a number (not a letter), the computer will treat it as the number 65, not ‘A’.
ASCII uses numbers from 0 to 127 to represent characters.
Each number in this range has a clear meaning. For example, 65 is ‘A’, and 97 is ‘a’.
When you use %c, the computer looks at the ASCII table and shows the correct character.
But what if you use a number bigger than 127 or below 0?
Things can get messy. The computer might show random symbols, or it might not work the same way on different systems.
This happens because ASCII stops at 127, and anything beyond that depends on the system.
It’s like speaking a different language—some computers might understand it, but others won’t.
To make sure everyone sees the same characters, it’s best to stay between 0 and 127.
Go Look at the ASCII Table!
Look at the ASCII table: the decimal (dec) value 65 corresponds to the character (char) ‘A’. You don’t need to memorize it, just refer to the table whenever you need to know which character a number represents.
You can easily find the ASCII codes in C through a quick search on Google. Just use the keyword “ASCII table C” and look at the photos to see the ASCII codes for characters.
What Are Variable Declaration and Initialization?
When you write int age = 10;
in C, you’re creating a variable called age
to store a whole number. The int
part tells the computer that this variable will hold an integer, like the number 10.
In most cases, an int
takes up 4 bytes of memory, which is enough space to store a number. So, when you declare the variable, the computer sets aside this amount of memory to hold the value.
The = 10;
part sets the initial value of age
to 10. The number 10 gets stored in the computer’s memory as binary data. For example, in a 32-bit system, the binary code for 10 looks like this: 00000000 00000000 00000000 00001010
.
Even if you later change the value of age
, it still takes up the same 4 bytes of memory. So, if you write age = 25;
, the computer will store the number 25 in those 4 bytes, but the space reserved for age
doesn’t change.
What’s important to remember is that no matter what value you assign to age
, it will always use 4 bytes of memory. The size of the space stays the same, regardless of the number.
Variable Declaration: What It Is
When you declare a variable, you’re telling the computer that you want to set aside some space to store information. For example, when you write int age;
, you’re asking the computer to reserve 4 bytes of memory for a variable called age
, which will store an integer.
The int
type needs 4 bytes (32 bits) to hold an integer. But at this point, the computer is only setting up the space for age
—it’s not storing any actual value yet. The CPU knows where in memory age
will be, but it’s empty until you assign a value to it.
In simple terms, declaring a variable is like making a label for a storage space. The space is there, but you haven’t put anything in it yet.
int age;
// Declaration:
// Here, we are just saying
// "I will use a variable called 'age' to store a number."
// But we haven’t given it a value yet.
// The name 'age' can be anything you choose.
// It's just a label to hold a number later.
CVariable Initialization: What It Is
When you write int age = 10;
in C, you’re doing two things: you’re declaring and initializing a variable.
First, the declaration happens. The int
tells the computer that the variable age
will store an integer, and it sets aside 4 bytes of memory to hold that value.
Then comes initialization. This is where you assign a value to the variable. In this case, age = 10;
means you’re setting age
to hold the value 10. The number 10 is stored in the 4 bytes of memory that were reserved earlier.
The data is stored in RAM (Random Access Memory), which is like the computer’s short-term memory. While the program is running, the CPU makes sure the value is correctly stored in RAM.
However, once the program finishes, the data in RAM is cleared. So, the value of age
is lost when the program ends. This is because RAM is temporary memory that only holds data as long as the program is running.
To sum it up, declaration creates the variable and reserves memory for it, and initialization gives it a value. That value stays in RAM while the program runs, but once the program ends, it’s cleared.
int age = 10;
// Initialization:
// The variable 'age' is of type 'int' and is given the value 10.
// The name 'age' can be anything you want,
// as long as it follows naming rules.
// The value can also be anything valid for an 'int',
// like 5, -3, or 1000.
CYou can’t initialize a variable without declaring it, but you can declare it without initializing it.
Declaration tells the computer to prepare space for a variable in memory, and initialization places a value into that space. The CPU manages this process by directing the computer where to put the variable and how to access it, but it doesn’t store the actual data. The data is stored in the computer’s RAM.
Memory Size and Value Ranges of Common Data Types
When you’re working in C, the size of types like int
, char
, float
, and double
can change depending on the system architecture you’re using.
On older system architectures (16-bit), an int
usually takes up 2 bytes. But on newer system architectures (32-bit or 64-bit), it typically takes 4 bytes.
A char
is used to store a single character, like a letter or symbol, and it always takes 1 byte, no matter the system architecture.
For decimal numbers, a float
usually uses 4 bytes, and a double
uses 8 bytes for more precise or larger decimal numbers.
These days, most system architectures are 32-bit or 64-bit, so you’re typically working with ints
that are 4 bytes and doubles
that are 8 bytes. This helps make sure your code works the same across different computers.
By default, types like int
, float
, double
, and char
are signed, meaning they can store both positive and negative numbers. So, when you write int
, it’s like writing signed int
. If you only want positive numbers, you can use unsigned int
or unsigned char
.
The range of signed types depends on how many bytes they use. For example, a signed 4-byte int
can store numbers from -2,147,483,648
to 2,147,483,647
, and a signed 1-byte char
can store numbers from -128
to 127
.
In signed numbers, one bit is used to decide if the number is positive or negative. This bit is called the sign bit. If the sign bit is 0, the number is positive, and if it’s 1, the number is negative.
Data Type | Size | Minimum Value | Maximum Value |
int | 4 bytes | -2,147,483,648 | 2,147,483,647 |
float | 4 bytes | -3.4 billion | 3.4 billion |
char | 1 byte | -128 | 127 |
double | 8 bytes | -1.7 * 10^308 | 1.7 * 10^308 |
Unsigned data types are used to store positive numbers and zero only. They don’t handle negative numbers like signed types do.
The big difference is that unsigned types don’t need a bit for the sign (positive or negative). In signed types, one bit is reserved to show if the number is positive or negative.
Since unsigned types don’t use a bit for the sign, they can use that bit to store more numbers. This means they can hold larger positive values.
For example, an unsigned int
uses 4 bytes and can store values from 0 up to 4,294,967,295
. An unsigned char
, which uses 1 byte, can store values from 0 to 255.
Just remember, unsigned isn’t the default. You need to write unsigned
before the type, like unsigned int
or unsigned char
.
In short, unsigned types are great for storing only positive numbers. They allow you to store more numbers because they don’t use any bits for the sign.
Data Type | Size (Bytes) | Minimum Value | Maximum Value |
unsigned int | 4 | 0 | 4,294,967,295 |
unsigned float | 4 | 0 | 3.4E+38 |
unsigned char | 1 | 0 | 255 |
unsigned double | 8 | 0 | 1.7E+308 |
How Overflow and Underflow Affect Data Type Values
Overflow happens when a number becomes too large for the data type. For example, with a signed int
, if the number exceeds the maximum value it can store, it will wrap around to the minimum value, causing errors or weird results.
In an unsigned int
, the same thing happens. If the number gets larger than the maximum value, it wraps around to zero. The difference is that unsigned types only deal with positive numbers, so you don’t get negative values like in signed types.
Underflow occurs when a number is too small. For a signed type, if the value is smaller than the minimum value it can handle, it wraps around to the maximum value. This can cause unexpected behavior or mistakes in your program.
With unsigned types, there’s no true underflow. If you subtract 1 from 0, for example, it will wrap around to the maximum value, like 255 for an unsigned char
. There’s no negative value to worry about, so it behaves differently.
The main difference between signed and unsigned types is how they handle negative numbers. Signed types can represent both positive and negative numbers, so they have a range that includes both extremes. Unsigned types only deal with positive numbers, so they don’t have the same kind of underflow.
With signed types, overflow happens when a number goes over the maximum value or falls below the minimum. In unsigned types, overflow occurs when the number exceeds the maximum value, but there’s no underflow because they can’t represent negative numbers.
It’s important to understand how overflow and underflow work to avoid mistakes. Always make sure the values you’re working with stay within the allowed range — between the minimum and maximum values for that data type.
To avoid these issues, it’s a good idea to check that your numbers are within the valid range before using them in calculations.
Now that we’ve covered overflow and underflow, let’s look at some examples with the int
data type to see how it works in practice.
Exploring the int
Data Type in C
In C, an integer is a variable used to store whole numbers. These numbers can be positive, negative, or zero, but they don’t have decimal points. For example, 5
, -3
, and 0
are all integers.
The way integers are stored in memory depends on the system architecture. On most 32-bit and 64-bit systems, an integer typically takes up 4 bytes, or 32 bits.
Each bit is like a tiny switch. It can either be on (1
) or off (0
). The collection of these bits, when put together, represents the value of the integer.
Integers can be of two types: signed and unsigned. A signed integer can store both positive and negative numbers. A signed integer typically holds values from about -2,147,483,648
to 2,147,483,647
. An unsigned integer, however, can only store positive numbers and zero. It can store values from 0
to 4,294,967,295
.
The Two’s Complement system is used for representing negative integers. It reserves the leftmost bit (most significant bit) for the sign of the number. If this bit is 0
, the number is positive. If it’s 1
, the number is negative.
In C, we use the keyword int
to define an integer variable. For example, int num = 5;
creates an integer variable named num
and assigns it the value 5
.
To print an integer, we use the printf
function with the format specifiers %i
or %d
. Both are used to print integers, and in most cases, they will produce the same output. The main difference is that %i
can handle numbers in formats like hexadecimal or octal.
When you perform calculations with integers, such as adding 5
and 3
, the CPU’s ALU (Arithmetic Logic Unit) does the math. It adds the two numbers and stores the result in memory.
This result will stay in memory while the program is running. When the program ends, the result is cleared from memory. The integer’s value is no longer available after that.
Printing Integers in C: Using %d
and %i
#include <stdio.h> // Lets us use printf to print things.
int main() {
int num = 10; // Create an integer variable and set it to 10.
// Print the value of num using %d (for integers).
printf("Using %%d: %d\n", num);
// Print the value of num using %i (also for integers).
printf("Using %%i: %i\n", num);
return 0;
}
CTo print a percent sign (%
) in C, you need to use %%
because %
is a special character in the printf
function. When you want to print the value of an integer variable, you use %i
or %d
. For example, printf("%d", num);
prints the value stored in the variable num
. Both %i
and %d
work the same way for printing integers. But when you want to display a literal percent sign (%
), you write %%
.
Output:
Using %d: 10
Using %i: 10
CWhat Happens When an int
Overflows or Underflows in C?
The int
data type is used to store whole numbers.
However, there’s a limit to how large or small an int
can be.
On most systems, a 32-bit int
can hold values from -2,147,483,648 to 2,147,483,647.
If you try to store a number outside this range, something unusual happens.
Let’s first look at what happens when a number gets too large for the int
to store.
For example, if you try to add 1 to the largest possible value of an int
, you’ll see an overflow:
#include <stdio.h>
int main() {
int x = 2147483647; // This is the biggest number
// an int can hold on most systems
printf("Before overflow: %d\n", x);// Print the current value of x
x = x + 1; // Try to add 1 to x, this will cause an overflow
printf("After overflow: %d\n", x);
// The value of x now becomes negative, because it overflows!
return 0;
}
C- We start with
x
as the largest possibleint
, which is 2,147,483,647. - When we add 1, the value “wraps around” and turns into the smallest negative number, -2,147,483,648.
Why does this happen?
The int
data type can only hold numbers between -2,147,483,648 and 2,147,483,647. If you try to go beyond this range, it simply “wraps around” like the numbers on a clock.
For example, if you go past 12 on a clock, it starts over from 1.
Next, let’s look at what happens when a number gets too small for the int
to store.
#include <stdio.h>
int main() {
int x = -2147483648; // This is the smallest value
// an int can hold (most systems)
printf("Before underflow: %d\n", x);// Print the current value of x
x = x - 1; // Try subtracting 1 from x, this causes an underflow
printf("After underflow: %d\n", x);
// The value of x becomes positive because it wrapped around
return 0;
}
C- We start with
x
as the smallest possibleint
, which is -2,147,483,648. - When we subtract 1 from it, the value “wraps around” to 2,147,483,647, the largest possible positive number.
This behavior is similar to overflow, but in the opposite direction.
When the int
goes below its minimum value, it wraps around and jumps to the maximum value.
It’s really important to understand overflow and underflow in C because they can cause your program to act in strange ways. If you don’t pay attention to numbers that are too big or too small for a data type, things might go wrong without you realizing it.
For example, if you add or subtract too much, pushing the number past its limit, it can “wrap around.” This means it goes from the maximum to the minimum, or vice versa, which results in a number that doesn’t make sense in the context of your program. This could lead to errors, unexpected behavior, or even crashes, which can be hard to track down.
Take int
as an example: if the number exceeds 2,147,483,647 or goes below -2,147,483,648, it will wrap around and give you incorrect values, like going from a large positive number to a negative one, or vice versa. This is overflow or underflow in action.
That’s why it’s so important to be cautious when working with large or small numbers in C. Knowing how overflow and underflow work helps you avoid these kinds of bugs and keeps your program running smoothly. Always double-check your calculations and inputs to make sure you’re not accidentally pushing numbers beyond what a data type can handle.
Exploring the char
Data Type in C
In C, the char
data type is used to store individual characters. These characters can be letters, numbers, or symbols. For example, 'a'
, 'B'
, '1'
, and '#'
are all valid characters.
Anything inside single quotes ('
) is a char
. It can be a letter like 'A'
, a number like '5'
, or even a symbol like '@'
. When you put a number in single quotes, it’s treated as a character, not a number. For example, '5'
is the character for the digit 5, not the number 5. Always use single quotes for char
, and remember, characters are stored as their ASCII values in memory.
A char
takes up 1 byte of memory, which consists of 8 bits. Each bit can either be a 0 or a 1, meaning that with 8 bits, the char
data type can represent values in the range of 0 to 255 for an unsigned char
, or -128 to 127 for a signed char
. This range is enough to store a variety of characters.
The values stored in a char
variable are mapped to specific characters using something called the ASCII table. The ASCII table assigns each number between 0 and 255 to a character. For example, the number 65 corresponds to the character 'A'
, and the number 97 corresponds to 'a'
.
To assign a character to a char
variable in C, we use single quotes. For example, writing 'a'
means the character 'a'
will be stored in the char
variable.
However, it’s important to understand that a char
can only store one character. So, writing code like char letter = "A";
is incorrect because "A"
is a string, not a single character. The compiler would give an error because char
expects a single character, not a string. Instead, you should write char letter = 'A';
where 'A'
is a single character.
Similarly, writing char letter = A;
without quotes would also lead to an error, because A
would be treated as a variable or identifier, not as a character. You must always use single quotes to represent a character, like this: char letter = 'A';
.
'A'
is a single character, and it’s the correct way to assign a character to achar
variable."A"
is a string, and it can’t be assigned directly to achar
.- If you try
char letter = A;
without quotes, the compiler will treatA
as a variable, not a character, leading to an error. Always use single quotes for characters and double quotes for strings.
#include <stdio.h>
int main() {
char letter = 'A'; // We are storing the character 'A'
// in the variable 'letter'
// Now, we want to print the character we stored in 'letter'
// The %c tells printf to print the character, not the number
printf("%c\n", letter); // This will print 'A'
return 0; // The program ends here and returns 0
// to indicate success
}
Cwhen you use a char
to store a character, you’re not really storing the character itself. You’re actually storing a number that the computer understands. For example, when you write 'A'
, the computer doesn’t store the letter 'A'
, it stores the number 65.
Why does it do this? Well, the computer can only understand numbers. Characters like 'A'
, 'B'
, and '1'
are just human-friendly labels for numbers. The number 65 represents 'A'
in something called the ASCII table, which is a system that maps numbers to characters.
The character 'A'
is just a symbolic representation, and what is actually stored in memory is the number 65 (its value in the ASCII table). In other words:
When you define a variable like this:
char w = 'A';
CWhat is actually stored in memory is the number 65.
When the program prints the character 'A'
using %c
, it looks up the ASCII table and finds the character that corresponds to the stored number (65).
If you ask it to print using %d
, the program directly prints the number 65, without trying to interpret it as a character.
#include <stdio.h>
int main() {
// We store the character 'A' in the variable 'letter'.
// But what the computer really stores
// is the number 65 (the ASCII value of 'A').
char letter = 'A';
// Printing the character stored in 'letter'.
// We use %c to print the actual character 'A'
// that corresponds to the number 65.
printf("%c\n", letter); // This will print 'A'
// Printing the number stored in 'letter'.
// We use %d to print the number 65 directly
//, which is what the computer actually stores.
printf("%d\n", letter); // This will print 65
return 0;
}
C- Here, we are assigning the character
'A'
to the variableletter
. - The character
'A'
is represented by the number 65 in the ASCII table. So, the computer stores 65 in memory, not the letter'A'
itself.
- The
%c
format specifier is used to print a character. - Even though
letter
contains the number 65 in memory, when you print it with%c
, the program looks up the number 65 in the ASCII table and prints the corresponding character, which is'A'
.
- The
%d
format specifier is used to print a decimal number (an integer). - When you use
%d
, the program prints the actual number stored inletter
, which is 65. This is the ASCII value of'A'
.
%c
: Prints the character that corresponds to the stored number (65 →'A'
).%d
: Prints the actual number stored (65), which is the ASCII value of'A'
.
#include <stdio.h>
int main() {
// We're storing the number 65 in 'letter'.
// In the ASCII table, 65 corresponds to the character 'A'.
char letter = 65;
// Use %c to print the character
// that corresponds to the stored number (65).
// The ASCII value 65 maps to 'A', so it will print 'A'.
printf("%c\n", letter); // This prints 'A'
// Use %d to print the number (65) stored in 'letter'.
// This will print the numeric value 65,
// which is the actual number in memory.
printf("%d\n", letter); // This prints 65
return 0;
}
Cletter = 65;
: We’re actually storing the number 65, which corresponds to'A'
in the ASCII table.%c
: This will print the character'A'
, since 65 maps to'A'
in ASCII.%d
: This will print the number 65, which is the value stored inletter
.
We can write either 65 or ‘A’ in a char
variable like char letter = 65;
or char letter = 'A';
because both represent the same thing. The number 65 is the ASCII value for the character 'A'
, so whether we write 65 directly or use 'A'
, the computer stores the same value (65) in memory. It’s just that when we use 65, we are directly using the numeric value, and when we use ‘A’, we are using the character that corresponds to that number. Both ways will result in the same memory value being stored, which is 65.
The main point to understand is that a char
in C is essentially just a number, representing an ASCII value. If we want to print the character that corresponds to that number, we use %c
to display the character. For example, if the number 65 is stored in a char
, using %c
will print 'A'
, because 65 represents the letter ‘A’ in the ASCII table. On the other hand, if we use %d
, it will print the number itself (65), showing the actual value stored in the memory instead of the character.
The computer doesn’t actually understand letters or characters like we do. It only understands numbers. So, when we write 'A'
in our code, the computer doesn’t store the letter itself. Instead, it stores the number 65, because 65 is the number that represents 'A'
in the ASCII table. The ASCII table is like a map that links numbers to characters. When we see 'A'
, we’re just using a shortcut to represent the number 65, and the computer uses that number to know what character to show. So, in the end, it’s all about numbers, and the ASCII table helps the computer know which number means which letter.
Decimal | Character |
65 | A |
66 | B |
97 | a |
98 | b |
48 | 0 |
49 | 1 |
Each number matches a specific character. The computer uses these numbers to store letters, digits, and symbols. The ASCII table helps the computer translate numbers into characters we can understand. You don’t need to memorize it, but go ahead and look at the ASCII table on Google whenever you need to check it. If you still don’t know what it looks like, go and have a look.
Why Do We Need char
When We Have int
?
Both char
and int
can store the number 65
or the character 'A'
.
This is because the character 'A'
is represented by the number 65
in the ASCII table.
So, whether we store 65
or 'A'
, both refer to the same value in memory, which is 65
.
This value is represented in binary (0s and 1s).
In the computer’s language, there is no 'A'
; it is just the number 65
.
When we use 'A'
, the computer sees it as 65
, and it stores it as that number in memory.
This means that 'A'
is just a human-readable representation of the number 65
, but the computer only understands numbers.
We can write the code like this:int lets_see = 'A';
orint lets_see = 65;
orchar lets_see = 'A';
orchar lets_see = 65;
All of these are valid because in the end, both 'A'
and 65
refer to the same value in memory, which is 65
.
So, you might wonder, why do we need char
when we can use int
?
The answer lies in the amount of memory each type uses.
The range of a char
is smaller.
It typically goes from -128
to 127
(for signed char
).
If you use an unsigned char
, the range is from 0
to 255
.
On the other hand, an int
can store much larger numbers.
The range of an int
is much bigger, usually from -2,147,483,648
to 2,147,483,647
.
This means an int
can store numbers far beyond what we need for characters.
But why use all that space when we only need a small range?
Characters in the ASCII system are represented by numbers between 0
and 127
.
This range is much smaller than the range of an int
.
So, a char
is the right choice for storing characters because it uses less memory.
An int
uses 4 bytes of memory, while a char
uses only 1 byte.
If we used int
to store characters, we’d be wasting a lot of memory.
It’s like needing to store a chair but choosing a big house instead of a small room.
The big house (the int
) is far too large for the small object (the character).
The small room (the char
) is more practical and saves space.
By using char
, we make our program more efficient.
It takes up less memory, and we don’t waste space storing small data like characters.
If we use int
to store a character but go beyond the range of the ASCII table (which is from 0 to 127), things can get unpredictable.
For example, if we store 200
in an int
and then print it with %c
, the result might not be what we expect.
The number 200
is beyond the ASCII range, and it may not correspond to any valid ASCII character.
In this case, the computer could use another encoding system, which might not be understood by all computers.
Similarly, if we try something like char let_see = -33
, this is also unexpected.
Here, we stop using ASCII and start using another system, which can lead to undefined or unexpected results.
Remember, we should not go beyond the ASCII character range, which is from 0
to 127
, when working with char
.
When we print the value, whether it’s a character or a number, it’s determined by the format specifier.
If we use %d
, the program treats the number as a decimal, showing 65
.
If we use %c
, the program treats it as a character and prints 'A'
.
The type (char
or int
) doesn’t decide how the value is printed—it’s the format specifier that determines how the value is displayed.
In conclusion, char
was created because it uses the right amount of memory for characters.
Using int
would waste space, and that’s not efficient.
Also, we should remember not to go beyond the ASCII character range, which is from 0
to 127
, when working with characters.
Char vs Int in C: The Ultimate Showdown – A Simple and Fun Data Type Challenge for Beginners!
Now that you’ve gotten the hang of char
and int
, it’s time for a fun little challenge! We’ll show you some simple C code, and your job is to guess what the output will be.
You already know that char
is for characters and int
is for numbers, so think about how each one will behave when the code runs. This is a great way to see how they work together in action.
I won’t be explaining why each output happens—you’ll need to figure that out for yourself. If you’re a bit unsure, feel free to revisit earlier parts of the post!
Alright, let’s get started and have some fun with this!
What Happens When a char
Meets %c
?
#include <stdio.h>
int main() {
char guess = 98;
printf("%c\n", guess);
return 0;
}
CWhy Does '1'
Show This When You Ask?
#include <stdio.h>
int main() {
char guess = '1';
printf("%d\n", guess);
return 0;
}
CWhat’s Behind the Number for 'A'
?
#include <stdio.h>
int main() {
char guess = 'A';
printf("%d\n", guess);
return 0;
}
CDid You See That? What’s Going On with the Previous Code?
#include <stdio.h>
int main() {
int guess = 'A';
printf("%d\n", guess);
guess = guess + 1;
printf("%d\n", guess);
return 0;
}
CLetters Are Just Numbers—What Happens When We Add to Them?
#include <stdio.h>
int main() {
int guess = 'A';
printf("%c\n", guess);
guess = guess + 1;
printf("%c\n", guess);
return 0;
}
C%c and %d—Hmm, I’ve Seen That Before… But What Does It Really Mean?
#include <stdio.h>
int main() {
char guess = 'A';
printf("%c\n", guess);
printf("%d\n", guess);
return 0;
}
CInt and the Letter ‘A’—What’s Going On? And Why %c and %d?
#include <stdio.h>
int main() {
int guess = 'A';
printf("%c\n", guess);
printf("%d\n", guess);
return 0;
}
CAhh, Again? What’s with 97 and %c, %d?
#include <stdio.h>
int main() {
char guess = 97;
printf("%c\n", guess);
printf("%d\n", guess);
return 0;
}
CAdd One to ‘C’—What Happens to Its ASCII Value?
#include <stdio.h>
int main() {
char guess = 'c';
printf("%c\n", guess);
guess = guess + 1;
printf("%d\n", guess);
printf("%c\n", guess);
return 0;
}
COh, I See That Before… But This One Looks Bigger!
#include <stdio.h>
int main() {
char guess1 = 'A';
int guess2 = 'A';
char guess3 = 97;
int guess4 = 97;
printf("%c\n", guess1);
printf("%d\n", guess1);
printf("%c\n", guess2);
printf("%d\n", guess2);
printf("%c\n", guess3);
printf("%d\n", guess3);
printf("%c\n", guess4);
printf("%d\n", guess4);
return 0;
}
CCharacter? Or Number? Ohhh… It’s All Just Numbers in the End!
#include <stdio.h>
int main() {
char guess1 = '1' + 1;
int guess2 = '1' + 2;
char guess3 = '5' - 3;
int guess4 = '9' - 1;
printf("%c %d\n", guess1, guess1);
printf("%c %d\n", guess2, guess2);
printf("%c %d\n", guess3, guess3);
printf("%c %d\n", guess4, guess4);
return 0;
}
CWhy 32?? Maybe ASCII Holds the Secret—Do the Math and See!
#include <stdio.h>
int main() {
// If you're lazy, 'A' = 65 decimal and 'a' = 97 in decimal
// Think of what happens between them!
char guess1 = 'A' + 32;
char guess2 = 'a' - 32;
int guess3 = 65 + 32;
int guess4 = 97 - 32;
printf("%c %d\n", guess1, guess1);
printf("%c %d\n", guess2, guess2);
printf("%c %d\n", guess3, guess3);
printf("%c %d\n", guess4, guess4);
return 0;
}
CFrom Here to There, Living Between Characters… Ah, I’m a Char Number with Number, That’s All!
#include <stdio.h>
int main() {
char guess1 = '0' - 0;
char guess2 = 49 - 0;
char guess3 = '9' + 1;
char guess4 = '0' - 1;
printf("%d %c\n", guess1, guess1);
printf("%d %c\n", guess2, guess2);
printf("%d %c\n", guess3, guess3);
printf("%d %c\n", guess4, guess4);
return 0;
}
CLetters, Lowercase, and a Little Mystery: Can You Find Where They Live?
#include <stdio.h>
int main() {
char guess1 = 'a';
char guess2 = 'b';
char guess3 = 'c';
char guess4 = 'x';
char guess5 = 'y';
char guess6 = 'z';
char guess7 = 'a' - 1;
char guess8 = 'z' + 1;
printf("%c %d\n", guess1, guess1);
printf("%c %d\n", guess2, guess2);
printf("%c %d\n", guess3, guess3);
printf("%c %d\n", guess4, guess4);
printf("%c %d\n", guess5, guess5);
printf("%c %d\n", guess6, guess6);
printf("%c %d\n", guess7, guess7);
printf("%c %d\n", guess8, guess8);
return 0;
}
CA!!! G??? A!!! I??? N!!! U/P/E/R!
#include <stdio.h>
int main() {
char guess1 = 'A';
char guess2 = 'B';
char guess3 = 'C';
char guess4 = 'X';
char guess5 = 'Y';
char guess6 = 'Z';
char guess7 = 'A' - 1;
char guess8 = 'Z' + 1;
printf("%c %d\n", guess1, guess1);
printf("%c %d\n", guess2, guess2);
printf("%c %d\n", guess3, guess3);
printf("%c %d\n", guess4, guess4);
printf("%c %d\n", guess5, guess5);
printf("%c %d\n", guess6, guess6);
printf("%c %d\n", guess7, guess7);
printf("%c %d\n", guess8, guess8);
return 0;
}
CYou’re doing an amazing job so far—keep it up! Thank you for sticking with it and trying to learn about characters and integers. Now, let’s dive into float
and double
. These are for numbers with decimals, and they’re going to be fun to explore! Let’s go!
I’ve completed a good part of this blog, and I’m excited to share it with you! The rest is still in progress, so stay tuned. I’d love to hear your thoughts and feedback on what I’ve published so far.