调试技巧
实用的调试技巧
本篇内容:
- 什么是Bug?
- 调试是什么?有多重要?
- debug和release介绍
windows环境调试介绍。- 一些调试的实例
- 如何写出好的代码
- 编程常见的错误
1.什么是Bug?
Bug翻译过来是臭虫的意思,如今简单来讲就是程序错误
注释:第一次被发现的导致计算机错误的飞蛾,也是第一个计算机程序错误
2.调试是什么?有多重要?
调试就是一次推理的过程,一次查错的过程,一名优秀的程序员是一名出色的侦探。
这可能是我们写代码的样子:
1.那么说到底什么是调试呢?
官方说法:调试(英语:Debugging / Debug),又称除错,是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。
2.调试的基本步骤:
3.debug和release介绍
Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
首先,我们写一段代码,然后看看这段代码在两个不同环境下的区别
#include<stdio.h>
int main()
{
int n = 0;
int a = 0;
scanf("%d %d", &n, &a);
int i = 0;
int k = 0;
int sum = 0;
for (i = 0; i < n; i++)
{
k = k * 10 + a;
sum += k;
}
printf("%d\n", sum);
return 0;
}
3.1Debug环境下
- 按F10进入调试,在调试中点击窗口,在窗口中点击监视
3.2Release环境下
- 按F10进入调试,在调试中点击窗口,在窗口中点击监视
3.3总结
- 同一段代码在Debug环境下,包含调试信息,可进行调试,代码大小比Release环境下大,运行速度相对Release环境下慢。
- 在Release环境下,不包含调试信息,不可进行调试,代码大小比Debug环境下小,运行速度更快,同时也进行了优化。
- 作为程序员我们用的最多的还是Debug版本
4.windows环境调试介绍
注意:windows环境下我们用的是vs,Linux环境下编译器是Gcc,调试器是Gdb。
4.1调试环境的准备
4.2快捷键的使用
最常使用的几个快捷键:
1.F5
启动调试,经常用来直接跳到下一个断点处。
2.F9
创建断点和取消断点
断点的重要作用,可以在程序的任意位置设置断点。
这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。
一般而言,F5和F9是一起使用的。
3.F10
逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。
4.F11
逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最常用的)
一般逐语句的话,F10和F11没什么区别,但想要进入函数内部必须用F11。
5.CTRL + F5
开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用。
5.调试的时候查看程序当前信息
5.1 查看临时变量的值
按F10,在调试开始之后,用于观察变量的值
先看一段简单的代码,如何观察a,b的值?
int add(int x, int y)
{
return x+y;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int ret=add(a, b);
printf("%d\n", ret);
return 0;
}
一定记得先按F10,然后在调试中点击窗口,在窗口中点击监视
输入监视的变量:
删除某个变量按delete。
接下来看看数组如何监视?
F10调试后,调试—窗口—监视
进入函数呢?
如何完整看到数组里的元素呢?
5.2查看内存信息
先按F10进行调试,调试—窗口–内存
int a = 0;
int main()
{
int b = 20;
int arr[12] = { 1,2,3,4,5,6,7,8,9 };
return 0;
}
5.3查看寄存器和反汇编
按F10进入调试后,调试—窗口—反汇编/寄存器
5.4查看调用堆栈
首先,大概了解一下队列和栈
注意:局部变量放在栈区,一般来说,栈区的使用习惯是:先使用高地址,再使用低地址。
看一段代码
void test2()
{
printf("hehe\n");
}
void test1()
{
test2();
}
void test()
{
test1();
}
int main()
{
test();
return 0;
}
按F10进入调试后,调试—窗口—调用堆栈
6.一些调试的实例
实现代码:求 1!+2!+3! …+ n! ;
int main()
{
int i = 0;
int sum = 0;
int n = 0;
int ret = 1;
scanf("%d", &n);
for(i=1; i<=n; i++)
{
int j = 0;
for(j=1; j<=i; j++)
{
ret *= j;
}
sum += ret;
}
printf("%d\n", sum);
return 0;
}
输入:
3
运行结果:
15
为什么?
大家可以自己动手试试,实践才能出真知。
原因:ret每次都要赋值为1,但此程序没要。
7.如何写出好的代码?
优秀代码:
- 代码运行正常
- bug很少
- 效率高
- 可读性高
- 可维护性高
- 注释清晰
- 文档齐全
常见的coding技巧:
- 使用assert
- 尽量使用const
- 养成良好的编码风格
- 添加必要的注释
- 避免编码的陷阱。
首先,讲一下assert的用法:
assert是断言语句,assert包含表达式,如果表达式为真就啥事都不做,如果表达式为假就会报警告,当然在使用assert时要有头文件#include<assert.h>。
趁热打铁,我们来模拟strcpy函数
strcpy(目标字符串,源头字符串);
未优化的代码
void my_strcpy(char* dest, char* str)
{
while (*str != '\0')
{
//拷贝内容
*dest++ = *str++ ;
}
//拷贝'\0'
*dest = *str;
}
int main()
{
char arr1[20] = "***********";
char arr2[] = "hello";
my_strcpy(arr1, arr2);
printf("%s\n",arr1);
return 0;
}
运行结果:
hello
优化后的代码
#include<assert.h>
char* my_strcpy(char* dest,const char* str)
{
char *ret=dest;
assert(str && dest);//断言语句,用来判断是否为空指针
while (*dest++ = *str++)
{
;
}
return ret;//在cplusplus上我们可以看到库函数strcpy是有返回值的,返回值是目标字符串的首地址
}
int main()
{
char arr1[20] = "***********";
char arr2[] = "hello";
printf("%s\n",my_strcpy(arr1, arr2));
return 0;
}
7.1const的作用
const修饰变量,本身是变量具有常值属性,即不可直接修改
int main()
{
const int num = 10;
num = 20;//不可修改
return 0;
}
运行结果:
编译器报错
但是,我们可以间接修改,用指针修改试试
int main()
{
const int num = 10;
int* p = #
*p = 20;
printf("%d\n", num);
return 0;
}
运行结果:
20
那么该如何避免这种漏洞呢?
const修饰指针时
1.const放在* 号左边时,指针变量是可以改的,但是指向内容是不可改的,除非二级指针。
2.const放在* 号右边时,指针变量是不能改的,但是指向内容是可以改的。
第一种,看一段代码:
int num = 10;
const int * p = #
p=0x0000ff48;
printf("%p",p);
运行结果:
0000FF48
int main()
{
int num = 10;
const int * p = #
*p = 20;//不可修改,除非二级指针
printf("%d\n", num);
return 0;
}
运行结果:
编译器报错
第二种,看一段代码:
int main()
{
int num = 10;
int *const p = #
*p = 20;
printf("%d\n", num);
return 0;
}
运行结果:
20
int num = 10;
int *const p = #
p = 0x0000ff44;
printf("%p", p);
运行结果:
编译器报错
补:unsigned int可以写成size_t
8.编程常见的错误
8.1编译型错误
就是语法错误,直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单。
8.2链接型错误
看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不存在或者拼写错误。
解决方法:按Ctrl+f查找,定位,修改。
8.3运行时错误
借助调试,逐步定位问题。最难搞。
总结
以上就是调试的所有内容了,调试还是得多练,如果喜欢本篇,不妨点个小小的赞,如果想要了解更多编程知识,不妨点个关注,你们的关注是对我最大的支持,谢谢可爱的你的喜欢,下期间!!!