Let me give you some detailed explanations on void
, variable declarations, functions, and pointers, since you mentioned that you are class 12. Let me start with variable declarations, as that would be more appropriate for my explanation.
First, what happens when you declare a variable? In other words, what happens when you say int x
? As you know, all variables are in memory. The memory is divided into blocks, where each block has a width of 8 bits. These blocks are called bytes — this is the smallest addressable unit of memory in most computer architectures. Each byte has a number, and we usually use hexadecimal numbers to represent the memory address of each byte. So, for example, the first memory position is the address 0000 0000
, which can contain only 8 bits. The second byte is at 0000 0001
. And so on, until you reach the last byte, which is located at FFFF FFFF
.
The important thing is that the bit inside the memory blocks is 0 and 1. Example: 01101010
. What I'm trying to say is that 0 and 1 are not integers, nor characters, nor decimal values. They are not in nature, it is you who decides how you will look at them. If you decide to see them as integers, then 01101010
will be considered as 106 (6A in hexadecimal, which is written 0x6A
), and if you decide to see these bits as characters, then the bits will be treated as the letter "j".
Returning to my question. What happens when you say int x
? There are many things:
- You tell the computer that you are ready to see bits in memory as integer values.
- You ask to reserve enough bytes in memory which can contain
int
, and how much is it? Since an int
usually 32 bits (it may be more or less depending on the processor, OS, etc.), Then you ask to reserve 32 bits from memory. And how many bytes is this? Since we already said that each memory block has 8 bits, then you request 4 bytes of memory, and they will be sequential (for example, you will reserve addresses 00AA F000
, 00AA F001
, 00AA F002
, 00AA F003
). This means that different types of variables reserve a different number of bytes in memory depending on their size. Thus, char
reserve only 1 byte, since it is 8 bits, and float
reserve 8 bytes, since it requires 64 bits, and so on. This is not the case in pointers, so please pay attention!
Before moving on to pointers, I would like to repeat the idea in a different way: type variable_name
like int x
means that you will consider the contents of the memory as integers, and you will reserve 4 bytes. Changing the type will change the processing of bits.
Now pointers. What happens when you say int *p
? It is completely different from a regular variable. A pointer is something that tells you the location of something (the memory address of something). Based on the above explanation, each memory address is something like this hexadecimal number: AA00 F001. Thus, the memory address is an eight-digit hexadecimal number, which means that it is a 32-bit number. Therefore, when you create a pointer, you say that you want to treat the bits as a memory address (not an integer, not a character, not a decimal value, etc.). Because of this, all pointer variables store as many blocks in memory as 4 bytes (32 bits), since any memory address is 32 bits. Thus, int *p
and char *q
reserve 4 bytes in memory, because both will contain a memory address that is 32 bits wide.
This is where the action begins. Theoretically speaking, if all types of pointers reserve the same number of bits in memory, why not use the char
pointer to point to an int
variable (for example, char *q; int x; q = &x;
)? Theoretically, you can make this pointer, but there is a problem. As I said, int
will take 4 bytes in memory, and char
will only accept 1 byte. This means that if int
is in memory at address AA00 FF00
, and you want to put a new one next to it, the new one will sit on address AA00 FF04
, because the first int
has already reserved 4 bytes (from AA00 FF00
to AA00 FF03
), and the next the available memory location (address) will be in this case AA00 FF04
. Still with me?
Thus, declaring a pointer means 2 things:
- Reserve 32-bit memory to fit the memory address into.
- Each time we say
p++
, we will jump in memory over several blocks, which is equivalent to the size (in bytes) of the pointer type and does not apply to the type of thing you are pointing to. Here is an example: char c; int *p; p = &c;
char c; int *p; p = &c;
now p
points to the memory address where c
is located, and p++
does not point to the next memory address, it will point to the address located 4 bytes from the initial one because the step size for the int pointer is 4 bytes.
So what is void
? void
is something that means “nothing” or “no type”. Having said that, let's check the void on variables and pointers:
Can you say void x
as you said int x
? No, you cannot, because in variable declarations you specify how to process some bits and how much you need. When you say void x
, you do not specify how to handle the bits, and do not say how much you need.
Can you say void *p
as you said int *p
? Yes, you can, because you say that you want a pointer, and knowing that it is a pointer that we directly know that you need 32 bits in memory, and we also know that you want to treat them as a memory address, so there is no ambiguity in the previous case. Well, what happens when we tell the void
pointer to increment in p++
? Here is the problem. When the type of pointer was known, the jump in memory was known, but here it is unknown. What is the solution? You need to cast the void
pointer later so that you can find out how many blocks you can jump in memory each time you increment. Well, what good will we get if we drop something in the end? Why don't we create it directly in the type of this thing from the start? Usually a void
pointer is created where you will use it to point to different types each time, and not just to one type. If in a certain application you already know that you will always point to int
, for example, there is no use for creating a void
pointer, but if you know that you will need to point to different types, then void
will be convenient. Of course, this is not an entry-level topic.
OK, so void
doesn't mean anything, what should it do with functions? As you know, a function type is a definition of what the function returns. That way, the int
function returns int
every time you call it. Here are some examples:
int Function1();
When you say that the function is of type void
, you say that it does not return anything when you call it (which is really in C ++). Here is what you can do and what you cannot do with it:
void Function2();
Do we use the void
function? Yes, a lot, not every function returns us something. Suppose you want to write a program to play with a scoreboard. When a new game starts, you want the reset score to be 0. Suppose you have a function called ResetScore()
to complete this task, the reset has nothing useful to get back to you after calling it, so you probably will execute the function as void ResetScore()
. If you need some feedback with this function, you can start thinking of another type.
Hope this clarifies everything for you. Again, I wrote a detailed answer, since you said you were class 12. Good luck!
EDIT: answer your question in the comment below:
Before understanding the difference between the void
function and non-empty functions, we need to answer the question. If the function is not void
and whenever we call it, it will return something, then who will catch the return of the function? "
Simple The one who catches the return, the one who called. For example, if we have an int F1()
function, and somewhere in the middle of your program there is x = F1();
then x
is the one who catches the return of the F1()
function. This concept does not work with void
functions because they do not return anything, in other words void F2()
, then somewhere y = F2();
will not work because F2 returns nothing and therefore we cannot use it in the same way we used F1.
Thus, the main rule is the one who calls the return function. In this case, what is the difference between void main()
and int main()
? In C ++, the main () function must have a return value, so void main()
not allowed. But for other functions, the difference is that void
tags do not return anything to the caller, and those int
. Well, who calls the main
function? The operating system (OS) calls it. What is the advantage of the OS from returning from the main
function? It is useful to know if the normal operation is stopped or has an abnormal termination, so if the abnormal termination is completed, the OS may show you the well-known message "Send / not send" (here it is about Microsoft Windows). Thus, the return type of main()
will not affect your program or its output, it will only affect how it ends, because the return of the function is the last thing that happens in the function, and the return of main()
function is the last thing throughout the program (when you exit the program).
Hope this clarifies your question.