程序的调试

程序的编译过程

1.预处理:进行宏替换,去除注释,引入头文件,进行条件编译

2.编译:程序的语法语义纠错,构建代码树,没有问题则解释为汇编指令

3.汇编:将汇编指令解释为机器可以识别的二进制指令

4.链接:将使用到的库中的代码以及项目所有.c源码文件生成的二进制指令进行打包,生成可执行程序

debug的分类

1.编译错误:程序在编译阶段,语法语义纠错的时候发现的语法错误(变量未声明、函数返回值不对)

2.链接错误:程序在链接阶段,将使用到的库函数要加载到可执行程序中,可执行程序中用到了某个功能,

因此必须有功能的实现过程,才能一步步的完成功能(找不到变量或函数的定义)。

3.运行时错误:程序运行过程中,因为流程问题导致运行逻辑有问题,得不到预期的结果,因为一些异常导致程序崩溃。

程序的调试就是找运行时的错误(编译器无法检测出来)。

调试:观察程序的运行过程,查看运行中的数据变化是否符合预期。

debug调试版程序,程序不会进行任何的代码优化,并且会加入调试符号信息。

代码优化:编译器为了提高程序的运行效率,对代码进行的一些优化。

例如:CPU要处理数据先将数据从内存加载到CPU的寄存器中进行处理,如果某个数据使用的非常频繁,

则会将这个数据直接放在寄存器中,不需要重复从内存中获取数据。

还有,比如某个功能解释之后对于了某个指令,但是这个功能可以使用精简指令来完成,则会进行指令替换。

这些优化是不利于程序调试的,因为优化可能会改变程序的小范围逻辑。

release发布版程序,是实现上线运行的程序,会进行代码优化(提高性能),而且不会加入调试信息。

程序员调试的是debug,测试人员测试的是release(因为要保证发布的程序是没有问题的)

常见的调试操作

  1. 逐步调试

逐过程:快捷键:F10 功能:逐行运行代码,遇到函数直接将函数运行结束。

逐语句:快捷键:F11 功能:逐行运行代码,遇到函数则进入函数继续运行。

2.逐步调试时,查看程序中各个数据的变化是否符合预期——变量监控

程序的调试_第1张图片

3.运行调试 快捷键:F5 功能:非逐行调试,而是在代码中打断点,使程序直接运行到断点所在位置,等待下一步调试。

4.打断点 鼠标直接点击代码指定行的行号前面,F9打断点或者取消断点。

功能:让程序运行到指定行停止;继续调试,当前断点位置调试完毕,F5继续调试到达下一个断点处停止。

#include
int main()
{
    int i = 0;
    int arr[10] = { 0 };
    for (i = 0; i <= 12; i++)
    {
        arr[i] = 0;
        printf("hello");
    }
}
程序的调试_第2张图片
i变量先定义,因此地址更大,arr的起始地址偏小,但是随着下标增大访问的地址也越来越大。
在函数内,内存空间的管理用的是 栈空间——随着变量的定义,地址从高往低进行分配。
arr[12]这个位置的地址刚好就是i变量的地址,因此越界访问arr[12]=0,相当于将i的值修改为0,因此重新进入for循环,导致程序死循环。
程序的调试_第3张图片

示例:将src字符串的内容,给dest空间拷贝一份。

#include
#include
#include

//功能:将src字符串的内容,给dest空间拷贝一份,在这个字符串拷贝函数中是不应该修改原空间数据的
char *mystrcpy(char *dest, const char *src)
{
    //assert函数叫做断言函数,传入一个真假值,若为假则退出程序,若为真则继续运行
    assert(dest != NULL);
    assert(src != NULL);
    //容错处理:当有可能出错的时候该如何操作
    if (dest == NULL || src == NULL)
    {
        printf("输入空间有问题\n");
        return NULL;
    }
    int len = 0;
    while (src[len] != '\0')//src对应的位置不是结尾标志则一直循环
    {
        dest[len] = src[len];
        len++;
    }
    dest[len] = src[len];//将结尾标志也赋值给dest
    return dest;
}

int main()
{
    char buf[32] = { 0 };
    char data[] = "hello world";
    char *p = NULL;
    mystrcpy(buf, p);
    printf("%s\n", buf);
    system("pause");
    return 0;
}

const修饰的值不能被改变。

const char *src; const修饰的是*src,表示指向空间的内容不能被改变。

const *char src; const修饰的是src,表示src指针变量的指向不能被改变。

char const *src; const修饰的是*src,表示指向空间的内容不能被改变。

你可能感兴趣的:(c++,开发语言)