Initial C Language (8) – Debugging Tips

Since we want to learn debugging skills, we first need to know what to debug? what’s the effect? Is debugging important?

Let’s look down with questions

1. What is a bug?

A bug is a programming error discovered before an application is put into production or during use, causing the program to work poorly, produce incorrect results, or crash. It can be a bug in software or hardware, or it can be a human error.

Common bugs in programs include the following:

1. Infinite loop

2. Array subscript out-of-bounds exception

3. Arithmetic operation exception

4.Type mismatch

5. Null pointer exception

6. Class not found exception

7. Illegal access anomalies

8.Type cast exception

9. Stack overflow exception

10. There is no exception in the attribute

11. There is no exception in the method

The above are common bugs. We need to pay attention to these issues when writing code to avoid these exceptions.

2. What is debugging?

Everything that happens must be traceable. If you have a clear conscience, there will be no need to cover it up and there will be no signs. If you have a clear conscience, you will definitely need to cover it up, then there will definitely be signs. The more signs, the better. It is easy to follow the vine, and this is the path of reasoning. Following this path downstream is crime, and swimming upstream is truth.

Every debugging is a process of trying to solve a crime.

How do we generally write code?

How to troubleshoot problems?

2.1 What is debugging?

Debugging (English: Debugging / Debug), also known as debugging, is a process of discovering and reducing program errors in computer programs or electronic equipment.
Debugging refers to the process of discovering and solving errors and problems in the program through a series of technical means during the running of the program. Debugging can help programmers find logical errors, syntax errors, memory leaks and other problems in the program, and can use debugging tools to observe the running status of the program to better understand the execution process and debugging results of the program. Debugging is a very important part of the program development process, which can improve the quality and stability of the program.

2.2 Basic steps of debugging

  • Discover the existence of program errors (programmers, testers, users)
  • Locate errors by means of isolation, elimination, etc.
  • Determine the cause of the error
  • Propose solutions to correct errors
  • Correct program errors and retest

Introduction to 2.3Debug and Release

Debug is usually called a debug version, which contains debugging information without any optimization, making it easier for programmers to debug programs.
Release is called a release version. It is often implemented various optimizations to make the program optimal in terms of code size and running speed so that users can use it well .

Give a chestnut:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char* p = "hello bit.";
printf("%s\\
", p);
return 0;
}

Shown in Debug environment:

Shown in Release environment:

So we say that debugging is a process of finding potential problems in the code in the Debug version environment.
So what optimizations has the compiler performed?
Please see the following code:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int i = 0;
int arr[10] = { 0 };
for (i = 0; i <= 12; i + + )
{
arr[i] = 0;
printf("hehe\\
");
}
return 0;
}

If compiled in debug mode, the program will result in an infinite loop.


If compiled in release mode, the program will not have an infinite loop.


So what’s the difference between them?
It is caused by optimization.

Let’s take a look at the address under the Debug version:

Will you find the same thing? Why is this

We can see that the address is the same

Under the vs compiler, when i==12, it becomes 0 and falls into an infinite loop. If i changes arr[12], it will also change. It will never be greater than 12.

  • i and arr are local variables, and local variables are stored on the stack.
  • The usage rule of stack area memory is to use the high address space first, and then use the low address space.
  • The array changes from low to high as the subscript increases.

The order in which variables are allocated in memory has changed, affecting the results of program execution.

3. Introduction to Windows environment debugging

3.1 Preparation of debugging environment

Select the debug option in the environment to debug the code normally.

3.2 Learn shortcut keys

Let’s take a look at some commonly used shortcut keys

F5

Start debugging, often used to jump directly to the next breakpoint.

F9

Create and cancel breakpoints
The important role of breakpoint is that you can set a breakpoint anywhere in the program.
This allows the program to stop execution at the desired location and continue executing step by step.

F10

Process-by-process is usually used to process a process. A process can be a function call or a statement.

F11

Statement-by-statement means executing one statement each time, but this shortcut key allows our execution logic to enter the function (this is the most commonly used).

ctrl + F5

Start execution without debugging. If you want the program to run directly without debugging, you can use it directly.

3.3 Check the current information of the program during debugging

3.3.1 View the value of temporary variables

Used to observe the value of a variable after debugging has started.
?

3.3.2 View memory information

Used to observe memory information after debugging starts.
?

3.3.3 View call stack

After the view begins, observe the stack.

?

3.3.4 View assembly information

After debugging starts, there are two ways to go to assembly:
(1) The first method: right-click the mouse and select [Go to Disassembly]:

?
(2) The second way
?

3.3.5 View register information

You can view the register usage information of the current running environment.

?

Only by doing more hands-on work and trying to debug can you make progress.

  • Be sure to master debugging skills.
  • Beginners may spend 80% of their time writing code and 20% of their time debugging. But a programmer may spend 20% of the time writing programs, but 80% of the time debugging.
  • Very complex debugging scenarios may occur in the future: debugging of multi-threaded programs, etc.
  • Use shortcut keys more to improve efficiency.

4. How to write good (easy to debug) code.

4.1 Excellent Code

1. The code runs normally
2. Few bugs
3. High efficiency
4. High readability
5. High maintainability
6. Clear comments
7. Complete documentation

Common coding skills:

1. Use assert
2. Try to use const
3. Develop a good coding style
4. Add necessary comments
5. Avoid coding pitfalls.

4.2 assert

assert is a macro definition in C language that is used to check whether an expression is true while the program is running. If the expression evaluates to false, assert prints an error message and terminates the program. Assert is usually used for debugging programs to help programmers quickly locate the error when a problem occurs in the program. Using assert in your code can improve the robustness and reliability of your program.

The usage of assert is as follows:

  1. Use the assert macro definition in the code, followed by the expression that needs to be checked.
  2. If the expression evaluates to false, assert outputs an error message and terminates the program.
  3. In the release version, assert will be automatically ignored and will not affect the running of the program.

4.3 const

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//Code 1
void test1()
{
int n = 10;
int m = 20;
int* p = &n;
*p = 20;//ok?
p = & amp;m; //ok?
}
void test2()
{
//Code 2
int n = 10;
int m = 20;
const int* p = & amp;n;
*p = 20;//ok?
p = & amp;m; //ok?
}
void test3()
{
int n = 10;
int m = 20;
int* const p = & amp;n;
*p = 20; //ok?
p = & amp;m; //ok?
}
int main()
{
//Test without cosnt
test1();
//The test const is placed to the left of *
test2();
//The test const is placed on the right side of *
test3();
return 0;
}

We will find that the compiler will report a syntax error

?

For test2(); *p cannot be changed, that is, the content pointed to by p cannot be changed by p, but p can be changed, and p can point to other content.

For test3(); p cannot be changed, but the content *p pointed to by p can be changed through p.

Let’s look at an example to understand:

?

When const modifies pointer variables:

1. If const is placed on the left side of *, it modifies the content pointed by the pointer, ensuring that the content pointed by the pointer cannot be changed through the pointer. But the content of the pointer variable itself is mutable.
2. If const is placed on the right side of *, it modifies the pointer variable itself, ensuring that the content of the pointer variable cannot be modified, but the content pointed to by the pointer can be changed through the pointer.

Simulate the actual application of a strlen function:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
int count = 0;
assert(str != NULL);
while (*str)//Determine whether the string ends
{
count + + ;
str + + ;
}
return count;
}
int main()
{
const char* p = "abcdef";
\t//test
int len = my_strlen(p);
printf("len = %d\\
", len);
return 0;
}

The running results are as follows:

?

5. Common mistakes in programming

5.1 Compilation error

Compilation errors are generally simple and easy to solve

?

5.2 linkability error

According to the error message, find the identifier in the error message, then locate and solve it.

5.3 runtime error

Printing 0-4, the result is not the desired result. Debugging shows that the printf parameter is wrong, written as & amp;i.

Runtime errors can be found step by step through debugging.

?

The above is all the content of this debugging technique. In general, debugging still requires multiple debugging and testing to accumulate experience! ! !