一、前言
昨天晚上我正在看资料写博客时,我的同学在学习数据结构时遇到了疑点,让我看看,因为现在学校的学习的进度不快,所以没做什么准备就去了宿舍,心想应该不会太难,准备快速解决继续码博客。
但是当面对和我的代码风格不同,命名格式不规范,文件不分开创建的代码时,我有些蒙了,看着代码有些大脑空白的感觉,在同学面前又是分析,又是调试的,但都失败了,这个时候感觉自己想法失败了,装13失败了,但我认为自己面对这种代码应该是可以解决的,所以推辞一番,晚上又重新查找,心里暗较劲今晚一定要解决这个bug,要不然之前的学习就白学了。
最终在我对代码的调试之下,我发现了错误,并且这个错误多少有些简单了,但这也让我有所反思,一方面还是自己的基本知识不熟练,另一方面是调试时的粗心导致的。下面就让我们开始对代码调试的讲解
二、常用按键
这里我们将我们对代码进行调试时的常用按键进行讲述:
F10:
我们将代码进入调试模式;同时我们在调试中每按一次F10,我们程序就执行一次语句,当我们执行的语句是调用函数时,也是相同,直接将当前语句执行结束。
F11:
当我们在调试我们的代码是,就像我们上述情况,如果我们的执行的语句中含有调用函数,同时我们想进入调用函数中查看分析代码,我们按F11,我们就会进入我们当前语句中调用函数中。
F9:
如果我们的代码过长,而我们又执行执行部分代码查看情况,此时我们选择我们要执行的语句,按下F9,我们就对这一语句打下来一个断点,然后我们按下F5,我们的代码就会直接运行到我们打下断点的语句。
F5:
当我们代码中有打下断点的语句时,我们按下F5,既可以将我们代码直接运行到我们打下断点的地方。
三、举例分析
我们上面得知了调试时常用的按键,当然,实践出真知,我们先给出同学的代码让大家分析,如果基本功熟练的读者相信一眼就可以看出代码中的问题
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef struct DynamicArrayStack //初始化栈结构体
{
int top;
int capacity;
int* array;
}DynamicArrayStack;
DynamicArrayStack* InitStack() //初始化栈
{
DynamicArrayStack* S =(DynamicArrayStack*) malloc(sizeof(DynamicArrayStack));
if (!S)
return NULL;
S->capacity = 1;
S->top = -1;
S->array = (int*)malloc(S->capacity * sizeof(int));
if (!S->array)
return NULL;
return S;
}
int IsFullStack(DynamicArrayStack* S) //判断栈是否已满
{
return (S->top == S->capacity-1);
}
void DoubleStack(DynamicArrayStack* S) //分配空间函数
{
S->capacity *= 2;
S->array = (int*)realloc(S->array, S->capacity);
}
void Push(DynamicArrayStack* S, int x) //将元素data压入栈中
{
if (IsFullStack(S))
DoubleStack(S);
S->array[++S->top]= x;
//->的优先级大于++ 先执行S->top,然后将S->top的值加1
}
int IsEmptyStack(DynamicArrayStack* S) //判断栈是否为空
{
return (S->top == -1);
}
int Pop(DynamicArrayStack* S) //从栈中弹出栈顶元素
{
if(IsEmptyStack(S))
return INT_MIN;
return S->array[S->top--]; //将S->top的值先返回,然后S->top减1
}
void DeleteStack(DynamicArrayStack* S) //删除栈
{
if (S)
{
if (S->array)
free(S->array);
free(S);
}
}
void conversion() //数制转换
{
}
void PrintStack(DynamicArrayStack* S) //打印栈
{
DynamicArrayStack* p= S;
int i = 0;
while (i <= p->top)
{
printf("%d ", p->array[i]);
i++;
}
}
int main()
{
printf("初始化栈\n");
DynamicArrayStack* L;
L = InitStack();
printf("现在栈为空\n");
printf("请输入第一个要入栈的值:");
int e;
scanf_s("%d", &e);
Push(L,e);
printf("现在栈中有一个元素:");
PrintStack(L);
printf("\n请输入第二个要入栈的值:");
scanf_s("%d", &e);
Push(L, e);
printf("现在栈中有二个元素:");
PrintStack(L);
}
此时我先对同学要实现的代码进行一下背景描述:我们要实现栈,同时实现栈的增删查改等基本接口
而我的同学在运算代码时出现的问题是:
那么这个时候我们进行调试之前,我们先对代码大体看一眼,这里我们就发现了一个错误:
①我们的main函数中,没有"return0"语句,这是一个非常明显的错误。
现在我们对代码也无法直观的看出什么内容了,那么这个时候我们选择进行调试,我们按下F10,开始我们的调试过程:
这个时候,我们继续根据我们上述的按键进行调试分析
(这里我们补充一点,关于监视窗口的展开)
当我们调用监视窗口之后
现在,我们就行我们代码的调试工作
此时我们输入元素1;然后继续运行我们的代码
此时我们监视窗口中关于变量的数值与地址等信息如图,这个时候按照代码中的定义我们得出下面的图解
我们继续运行我们的代码
我们按照上述讲解的内容,F10运行当前代码语句,F11进入我们调用函数内部,我们得出下面图解
我们按照上述讲解的内容,F10运行当前代码语句,F11进入我们调用函数内部,就行我们的代码调试,我们得出下面图解
这个时候我们得知,当前代码中内存分配函数出现了问题,并且我们得知,当我们的数组容量已满的时候,函数并没有将我们的数组容量翻倍,所以我们回看代码时发现:
②这里的主动内存realloc函数使用错误;
②realloc函数的使用时,两个参数,第一个参数是我们要改变空间大小的地址,一般用指针来作为参数;第二个参数是我们想要的空间大小,这里他直接写的是int类型数据,也就是他想要的对应int类型的空间个数,但我们的大小是:空间个数乘每个数据类型所占的空间,所以我们应该改为sizeof(int * ) * S->capacity,这个时候才是我们真正想要的空间大小
现在我们就解决了我们的代码问题,让我们当前的代码成功运行,但我对上述的代码仍要修改一下,因为当前的代码可读性较差,部分函数的参数设置不友好,可读性较差。
我们在实现他当前的程序时,我们一般创建三个文件
test.c文件:用来测试main()函数
Stack.c文件:用来实现我们栈中的各种函数的具体代码
Stack.h文件:用来声明我们的结构体,声明函数,包含头文件等
还有这里,他在创建之初使用的是指针去接受我们的初始化函数的返回值,这里他的初始化函数的返回值,而里面是先创建一个结构体,再将结构体中数据改变后返回这个结构体的指针;我们应该在main函数中实现的是创建一个结构体变量,然后我们想初始化函数中创递我们这个变量的地址,去改变这个参数的数据内容,这样比较符合我们的代码习惯,以及我们代码的可读性。
Stack.h
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef struct DynamicArrayStack //初始化栈结构体
{
int top;
int capacity;
int* array;
}DynamicArrayStack;
DynamicArrayStack* InitStack(); //初始化栈
int IsFullStack(DynamicArrayStack* S); //判断栈是否已满
void DoubleStack(DynamicArrayStack* S); //分配空间函数
void Push(DynamicArrayStack** S, int x); //将元素data压入栈中
int IsEmptyStack(DynamicArrayStack* S); //判断栈是否为空
int Pop(DynamicArrayStack* S); //从栈中弹出栈顶元素
void DeleteStack(DynamicArrayStack* S); //删除栈
void PrintStack(DynamicArrayStack* S); //打印栈
Stack.c
#include"stack.h"
DynamicArrayStack* InitStack() //初始化栈
{
DynamicArrayStack* S = (DynamicArrayStack*)malloc(sizeof(DynamicArrayStack));
if (!S)
return NULL;
S->capacity = 1;
S->top = -1;
S->array = (int*)malloc(S->capacity * sizeof(int));
if (!S->array)
return NULL;
return S;
}
int IsFullStack(DynamicArrayStack* S) //判断栈是否已满
{
return (S->top == S->capacity - 1);//
}
void DoubleStack(DynamicArrayStack* S) //分配空间函数
{
S->capacity = S->capacity * 2;
S->array = (int*)realloc(S->array, sizeof(int*)*S->capacity);
}
void Push(DynamicArrayStack* S, int x) //将元素data压入栈中
{
if (IsFullStack(S))//判断是否空间已满,满了则空间翻倍
DoubleStack(S);
S->array[++S->top] = x;
//->的优先级大于++ 先执行S->top,然后将S->top的值加1
}
int IsEmptyStack(DynamicArrayStack* S) //判断栈是否为空
{
return (S->top == -1);
}
int Pop(DynamicArrayStack* S) //从栈中弹出栈顶元素
{
if (IsEmptyStack(S))
return INT_MIN;
return S->array[S->top--]; //将S->top的值先返回,然后S->top减1
}
void DeleteStack(DynamicArrayStack* S) //删除栈
{
if (S)
{
if (S->array)
free(S->array);
free(S);
}
}
void conversion() //数制转换
{
}
void PrintStack(DynamicArrayStack* S) //打印栈
{
DynamicArrayStack* p = S;
int i = 0;
while (i <= p->top)
{
printf("%d ", p->array[i]);
i++;
}
}
test.c
#include"stack.h"
int main()
{
printf("初始化栈\n");
DynamicArrayStack* L;
L = InitStack();
printf("现在栈为空\n");
printf("请输入第一个要入栈的值:");
int e;
scanf_s("%d", &e);
Push(L, e);
printf("现在栈中有一个元素:");
PrintStack(L);
printf("\n请输入第二个要入栈的值:");
scanf_s("%d", &e);
Push(L, e);
printf("现在栈中有二个元素:");
PrintStack(L);
return 0;
}
四、总结
关于调试的方式与内容,我就进行这些讲解,我们在这里最重要知道四个调试常用按键,同时当我们的代码遇到问题时,不要凭感觉随意修改,要养成调试的好习惯,知道自己是什么地方出现的问题;
关于调试中还有其他的监视窗口,我们后续会继续讲解
以上就是我对代码调试的个人理解
上述内容如果有错误的地方,还麻烦各位大佬指教【膜拜各位了】【膜拜各位了】