调试指南
调试指南
由于图床一些问题,本篇博客暂时不添加图片,可以自行运行代码片段查看运行结果。
一、预处理指令的妙用
参考文献:爽文219
1、使用ifdef注释
只有在宏定义了ifdef后判断的内容时,使用ifdef和endif括住的内容才会被编译运行。
样例:
int main()
{
#define lky233
#ifdef lky233
freopen("testdata.in", "r", stdin);
freopen("testdata.out", "w", stdout);
#endif
int a, b;
cin >> a >> b;
cout << a + b << endl;
}
除了使用define进行宏定义,还可以在编译命令中添加 -D *** 实现。
例如:-D lky233
另外,ifndef表示若没有定义。
样例:
int main()
{
#define lky233
#ifndef lky233
freopen("testdata.in", "r", stdin);
freopen("testdata.out", "w", stdout);
#endif
int a, b;
cin >> a >> b;
cout << a + b << endl;
}
还有就是,一般常用的OJ都有宏定义ONLINE_JUDGE。
(HOJ也有的)
2、define
define在调试中用来进行宏定义,并用来一句话注释所有调试代码
#define debug
#ifdef debug
printf("debug");
#endif
3、warning/pragma message()
使用warning/pragma message()在一些修改处进行警告,防止自己失智。
int main()
{
#warning
int a,b;
#pragma message("debug")
cout << a << b << endl;
}
二、cerr的使用
输出一些调试信息,但没有注释导致\({\color{red}{\mathrm {WA}}}\)?。
为了查看调试信息注释了freopen?
不要慌,快用\(cerr\)。
cerr 一个ostream对象,关联到标准错误,通常写入到与标准输出相同的设备。默认情况下,写到cerr的数据是不缓冲的。Cerr通常用于输出错误信息与其他不属于正常逻辑的输出内容。 ——百度百科
简单来说,cerr可以在你已打开文件输入输出的时候,依旧在屏幕上输出信息, 而非在文件中输入输出。
使用和cout是一样的。
int main()
{
freopen("testdata.in", "r", stdin);
freopen("testdata.out", "w", stdout);
cerr << 1 << endl;
cout << 2 << endl;
}
另外一提,syzoj可以输出你的标准错误流。在OJ上debug
关于标准错误流, 还有一个clog,没用过,感兴趣的自己康康。
三、assert
用于判断一些错误。
assert(),传入一个bool表达式,如果信息为假,程序会停止并抛出错误信息。
int main()
{
assert(0);
}
四、使用dev进行debug
这个是dev的debug,要想学习gdb调试:请点我(虽然本质区别不大)
由于个人感觉dev的debug太难用了,大多数情况我个人还是喜欢手动调试。
使用时编译器先选择debug,之后进行编译。
由于一些缓冲区的问题,建议使用文件输入输出。
否则可能不可预测的翻车。
编译完成后摁下\(F5\)进行调试。
1、设置断点
调试情况下若没有断点程序将会直接正常运行,并且不会在控制台暂停。
单击行号以在该行设置断点。
程序会在这一行暂停运行。
2、添加查看
单击添加查看,输入变量名称,在左侧项目管理栏便可以看到所要查看的变量。
运行过程中,右键可以修改变量值。
3、下一步/单步进入
单击[下一步]或使用\(F7\)进入下一步。将会执行下一个函数。
单击[单步进入]或使用\(F8\)进入该函数进行调试。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
int n;
int a[MAXN];
inline void out()
{
for(register int i = 1; i <= n; ++i)
{
cout << a[i] << '\n';
}
}
int main()
{
#ifdef lky233
freopen("testdata.in", "r", stdin);
freopen("testdata.out", "w", stdout);
#endif
scanf("%d", &n);
for(register int i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
}
out();
return 0;
}
4、RE报错
当调试一个RE的程序时,dev会暂停在RE的那行。如果是在函数中RE,会跳转到函数中。包括库函数,比如STL。
折腾半天想找一个RE的程序
我也不知道为什么负下标没有RE。
但是,scanf不传地址就会RE啊。(初学C++常犯错误)
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100;
int a[MAXN];
int n;
int main()
{
#ifdef lky233
freopen("testdata.in", "r", stdin);
freopen("testdata.out", "w", stdout);
#endif
scanf("%d",n);
}
五、对拍
对拍是考场debug、证明正确性以及平时调试的利器。
贪心只能过样例
1、一个重要的maker
#include<bits/stdc++.h>
using namespace std;
int main()
{
freopen("testdata.in", "w", stdout);
srand(time(0)/* *new int */)
int a = rand() % 10 + 1;
int b = rand() % 10 + 1;
cout << a << b << endl;
}
2、对拍程序
#include<bits/stdc++.h>
using namespace std;
int main()
{
for(register int i = 1; i <= 10000; ++i)
{
system("maker.exe");
system("force.exe");
system("right.exe");
//system("force.exe<testdata.in>force.out");
//system("force.exe<testdata.in>right.out");
if(system("fc force.out right.out"))
{
puts("wrong");
exit(0);
}
}
}