调试指南

调试指南

由于图床一些问题,本篇博客暂时不添加图片,可以自行运行代码片段查看运行结果。

一、预处理指令的妙用

参考文献:爽文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);
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/Shiina-Rikka/p/11778146.html