Much of the time spent on software development is usually devoted to finding and resolving bugs in the code, a task that can be very time consuming and can cause a lot of frustration. There are many tools that facilitate this process, but the best known and most widely used are debuggers, also known as debuggers.

What is a debugger?
The debuggers observe the execution flow of the program they are debugging, and save information about it such as the values of the variables or the call stack of the process where the calls to the methods and/or functions that have been executed are stored... We can access this information in different ways depending on the debugger we are using, but in general the debuggers provide us with one or more ways to view this information.
If you have done research on debuggers previously, I am sure that the term breaking point has appeared more than once. A main feature of the vast majority of debuggers is the possibility of stopping the execution of the program when it reaches a point that we have indicated (the vast majority of IDEs with debugger built-in let you select it before starting debugging, others such as gdb you must first run the debugger). When the program reaches that point, the execution will stop and we will be able to see the information at that moment.

This point where we indicate to stop the execution is what is called breaking point, o breakpoint in English. The debugger will detect that there is a breakpoint on that line and when it reaches that line, the execution will stop. This is where another of the functionalities of the debuggers, the function single-stepping.
The debuggers allow us, instead of letting the code run to the end, to go line by line in such a way that we can control the execution of the code at the pace we want. This is useful when we want to know, for example, what value a variable has before a particular point and see if that value is what we expect, or if in a conditional flow it follows the path we want it to follow.
Now, let's imagine that we have the following snippet of code in C.
#include <stdio.h>
int sum(int a, int b) {
return a + b;
}
int main() {
printf("hello world");
int c = sum(4,2);
return 0;
}If we go step by step in the debugging of the code, we will see how we go from the line where the variable is declared c but we have not entered the function sum. By default, when we go step by step in debugging the debugger goes through the functions but does not go into them. In order to be able to enter the functions instead of a step a step-into. In this way we will be able to enter inside the functions and see step by step how they are executed. In the same way, if we are inside a function but we want to exit it to return to the flow we have the option of step-out which allows us to return to the point where the function was executed.
Most popular debuggers
The standard GNU debugger, gdb, is a debugger widely used in Unix environments. Without graphical user interface, it allows to trace the execution of the program and to access the symbol table of the process in order to debug the code and to be able to analyze it.
Normally the vast majority of IDEs (Eclipse, the whole Jetbrains family...) carry a debugger which allows debugging in a more friendly way than gdb. Browsers such as Firefox or Google Chrome have a debugger in developer tools that allow us to debug our web applications in the same way that we can debug programs written in another language.
Advantages of debuggers
You've probably wondered what you can get from a debugger that you don't want to add a console.log or a print to your program. While it may seem that using prints is much easier and faster than debugging using debuggers, the advantages of these tools are many and not negligible, to be highlighted:
- Greater control: we can control the execution flow to adapt it to our needs
- More information: From variable values to executed methods...
- No need to modify the code: When we add a print we modify our code. Debugging does not modify the code at any time, which makes the information displayed by the tool represent the state of the application.
Conclusions
Knowing how to use a debugger correctly makes the detection and correction of errors faster, in addition to the fact that, although at the beginning they can be somewhat complex tools to understand their potential and take full advantage of them, once their use has been internalized they become an essential tool for any developer.

