Summary of Debugging Tips

Table of contents

1. What is debugging?

2. Basic steps of commissioning

3. Introduction to Debug and Release 

4. Debugging example

4.1 Implementation code: seek 1! +2! +3! ...+ n! ; overflow is not considered

4.2 Analyzing this code

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

5.1 Good code:

5.2 Demonstration

6. Supplementary knowledge

6.1 Explanation of const 

7. Common compilation errors


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

2. Basic steps of commissioning

Find the existence of program errors Locate
the errors by isolation, elimination, etc.
Determine the cause of the errors
Propose solutions
to correct errors Correct the program errors and retest

3. Introduction to Debug and Release 

Debug is usually called the debug version, it contains debugging information, and does not make any optimization, which is convenient for programmers to debug programs.
Release is called the release version, which is often optimized to make the program optimal in code size and running speed
, so that users can use it well.

4. Debugging example

4.1 Implementation code: seek 1! +2! +3! ...+ n! ; overflow is not considered

#include <stdio.h>

int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = 1;
	int sum = 0;
	for (n = 1; n <= 3; n++)
	{
		int i = 0;
		for (i = 1; i <= n; i++)
		{
			ret *= i;
		}
		sum += ret;
	}
	printf("%d\n", sum);
	return 0;
}

1! +2! +3! = 9 But the result of the above code is 15. This shows that there is something wrong with our code, so start debugging. 

When we calculate the factorial of 3, the value of ret is still 2. This code is written from 1 to the desired number, so we need to set the value of ret to 1 every time we enter the loop.

correct code

int main()
{
	int n = 0;
	scanf("%d", &n);

	int ret = 1;
	int i = 0;
	int sum = 0;
	for (i = 1; i <= n; i++)
	{
		ret *= i;
		sum += ret;
	}
	printf("%d", sum);
	return 0;
}

4.2 Analyzing this code

#include <stdio.h>


int main()
{
	int i = 0;
	int arr[10] = { 0 };
	for (i = 0; i <= 12; i++)
	{
		arr[i] = 0;
		printf("hehe\n");
	}
	return 0;
}

First of all, we can easily see that the array is accessed out of bounds, but the results of the group code are different in different environments. In vs, it will be an infinite loop.

Explanation: Because the habit of using the stack area in the memory is to use the high address space first, and then use the low address space, so the operating system first allocates a space for the local variable i in the stack, and then allocates a space for the array , while the array in memory is stored continuously, and its address increases from low to high as the subscript increases. And after we put element 0 in the array, the array is out of bounds in VS, the VS compiler will still store the number 0 in the memory after the array out of bounds, but the position of the variable in VS and the array in memory differ by two words Section, when the program reaches arr[12], it actually accesses the space of the variable i. At this time, putting data 0 in arr[12] actually changes the value in the variable i to 0, because this When both point to the same block of memory space.

Note again that the results may be different in different compilation environments. In vc6.0, there is no gap between i and arr in memory.

While in gcc there is one byte difference between the two, in vs there is a difference of two bytes.

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

5.1 Good 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 traps.

5.2 Demonstration

Simulate the realization of strcpy, the blogger will show the continuously optimized code

The blogger will show the continuously optimized code with a full score of 10

Method 1, 5 points 

void my_strcpy(char* dest, char* src)//传进来两个指针
{
	while (*src != '\0')
	{
		*dest = *src;
		src++;
		dest++;
	}
	*dest = *src;   //这里最后将src指向的'\0'赋给dest指向的区域
}

int main()
{
	char arr1[] = "hello haha";
	char arr2[20] = "xxxxxxxxxxxxxx";

	my_strcpy(arr2,arr1);
	printf("%s\n", arr2);
	return 0;
}

 Method 2, 6 points

void my_strcpy(char* dest, char* src)//传进来两个指针
{
	while (*src != '\0')
	{
		*dest++ = *src++;
		
	}
	*dest = *src;   //这里最后将src指向的'\0'赋给dest指向的区域
}

int main()
{
	char arr1[] = "hello haha";
	char arr2[20] = "xxxxxxxxxxxxxx";

	my_strcpy(arr2,arr1);
	printf("%s\n", arr2);
	return 0;
}

 Method 3, 7 points

void my_strcpy(char* dest, char* src)//传进来两个指针
{
	while (*dest++ = *src++)
	{
		;
	}  
}

int main()
{
	char arr1[] = "hello haha";
	char arr2[20] = "xxxxxxxxxxxxxx";

	my_strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

 Explain, this sentence is actually to assign *src to *dest first, then src++, dest++, when src points to '\0', first assign '\0' to dest, but at this time *dest++ = * src++ This expression evaluates to 0, and the loop ends.

Method 4, 8 points 

#include <stdio.h>
#include <assert.h>

void my_strcpy(char* dest, char* src)
{
	assret(src != NULL);
	assret(dest != NULL);
	while (*dest++ = *src++)
	{
		;
	}  
}

int main()
{
	char arr1[] = "hello haha";
	char arr2[20] = "xxxxxxxxxxxxxx";
	int* p = NULL;

	my_strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

Here, a function assert (assertion) is used. The reason for this is that we sometimes mistakenly pass in a null pointer when passing parameters. At this time, read and write exceptions will occur. After using assert, you can quickly Help us locate the problem, because when you pass a null pointer, you won't even be allowed to compile it.

Method 5, 9 points

void my_strcpy(char* dest, char* src)
{
	assret(src && dest);
	
	while (*dest++ = *src++)
	{
		;
	}
}

int main()
{
	char arr1[] = "hello haha";
	char arr2[20] = "xxxxxxxxxxxxxx";
	//int* p = NULL;

	my_strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

Here is the combination of two asserts.

Method 6, full marks

I don’t know if you have noticed that strcpy returns a character pointer, and there is a const modification in front of src. If we want to simulate, we must do our best. The return value type of the my_strcpy function is designed to implement chained access to functions.

#include <stdio.h>
#include <assert.h>

char* my_strcpy(char* dest, const char* src)
{
	assert(src && dest);
	char* ret = dest;
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[] = "hello haha";
	char arr2[20] = "xxxxxxxxxxxxxx";
	//int* p = NULL;

	
	printf("%s\n", my_strcpy(arr2, arr1));
	return 0;
}

6. Supplementary knowledge

6.1 Explanation of const 

int main()
{
	//const int num = 10;  //这里编译不同的,是因为表达式必须是可修改的值
	//num = 20;            //这里的num此时已经是常变量了,所以不可被修改。
	
	int num = 20;
	int n = 0;
	const int* p1 = &num;
	p1 = &n;

	int* const p2 = &num;
	*p2 = 10;

	return 0;
}

const can modify the pointer
const to the left of * (const int* p1;)
const is modified by *p1, which means that the object pointed to by p1 cannot be changed through p1, but the address in the variable p1 can be changed.
const is placed in * The right side (int* const p2;)
const is modified by p2, indicating that the content of p2 cannot be changed, but the object pointed to by p2 can be changed through p

7. Common compilation errors


编译型错误就是语法错误
链接型错误
运行时错误 - 借助调试解决的错误

#include <stdio.h>

int Add(int x, int y)
{
	return x + y;
}

int main()
{
	int a = 10;
	int b = 20;
	
	int c = Add(a, b);
	
	printf("%d\n", c);

	return 0;
}

void* p;

void test(void)
{
	printf("hehe\n");
}

int main()
{

	return 0;
}

Guess you like

Origin blog.csdn.net/m0_63562631/article/details/126227656