文章目录
1.什么是bug?
2.调试是什么,如何调试?
2.1 调试的概念
2.2调试基本步骤
3.release和debug介绍
Debug版本和release版本比较:
显然,release版本的空间大小要比debug空间大小要小。
还有一点就是:release版本是没有调试的,debug版本具有调试信息,因为release版本是给用户使用的,而用户又不懂编程调试,所以就没有调试信息。
4.visual studio 2022编辑器快捷键学习
4.1 关键一步
了解到debug版本是可以调试的,所以在使用visual studio 2022版本时首先环境是配置是debug版本:
4.2 快捷键介绍
4.2.1 常用快捷键
4.2.1.1 生成快捷键
4.2.1.2 调试常用快捷
4.2.1.3 编辑常用快捷键
4.2.1.4 文件常用快捷键
4.2.1.5 项目常用快捷方式
以上快捷是根据我的默认的visual studio 2022选出的常用实用快捷键,如果在你们的编译器上不同话可根据编译器上提供的快捷消息来采取,也可以看看这个链接:visual studio 2022键盘快捷方式
4.2.2 调试时有需求查看的信息
4.2.2.1 查看临时变量
4.2.2.2 查看内存消息
4.2.2.3 查看调用堆栈
4.2.2.4 查看汇编信息
4.2.2.5 查看寄存器信息
5.调试实例
5.1 实例一
求 1!+2!+3! …+ n! ;不考虑溢出.
int main()
{
int i = 0;
int sum = 0;//保存最终结果
int n = 0;
int ret = 1;//保存n的阶乘
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;
}
这段代码输出;
为什么1!+2!+3!的阶乘是15呢?不应该是9吗?,下面F10调试起来看一看:
最终解决后的代码:
int main()
{
int i = 0;
int sum = 0;//保存最终结果
int n = 0;
int ret = 1;//保存n的阶乘
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
int j = 0;
ret = 1;
for (j = 1; j <= i; j++)
{
ret *= j;
}
sum += ret;
}
printf("%d\n", sum);
return 0;
}
5.2 实例二
问这段代码在debug版本下x86平台下,为什么是死循环?
#include <stdio.h>
int main()
{
int i = 0;
int arr[10] = { 0 };
for (i = 0; i <= 12; i++)
{
arr[i] = 0;
printf("hehe\n");
}
return 0;
}
下面我们来通过调试来解释这个为什么?
真有这么巧吗?
其实并不是在VC6.0中arr[9]和i变量中间其实没有多余空间,在gcc编译器下arr[9]和i变量中间有一个整型的空间,visual studio 2022\2019\2013中的x86平台下arr[9]和i变量之间是由两个整型的空间。这些都不是巧合,而是编辑器本身规定的,不同的编译器有不同的规定。
6.如何写好优秀代码
6.1 优秀的代码
6.2 用例题示范
模拟实现库函数:strcpy
6.2.1 方法一:按照思路实现
void my_strcpy(char* dest, char* src)
{
while (*src != '\0')
{
*dest++ = *src++;
}
*dest = *src;
}
int main()
{
char arr1[20] = "xxxxxxxxxx";
//xxxxxxxxxx
char arr2[] = "hello";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
6.2.2 进一步优化
void my_strcpy(char* dest, char* src)
{
//停止条件就是'\0','\0'对应的ASCII码值是0
while (*dest++ = *src++)
{
;
}
}
int main()
{
char arr1[20] = "xxxxxxxxxx";
//xxxxxxxxxx
char arr2[] = "hello";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
6.2.3 用断言assert库函数进一步优化
对assert函数介绍:
简单来说,assert库函数就是为了保证指针的有效性。
void my_strcpy(char* dest, char* src)
{
assert(dest != NULL);//断言
assert(src != NULL);//断言
//NULL是#define NULL ((void *)0)
while (*dest++ = *src++)
{
;
}
}
int main()
{
char arr1[20] = "xxxxxxxxxx";
char arr2[] = "hello";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
6.2.4 再一步优化
void my_strcpy(char* dest, char* src)
{
assert(dest&&src);
//NULL是#define NULL ((void *)0)
while (*dest++ = *src++)
{
;
}
}
int main()
{
char arr1[20] = "xxxxxxxxxx";
char arr2[] = "hello";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
6.2.5 最后一步完善优化
//strcpy有返回类型,源头数组不可变这些要求
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);//断言
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "xxxxxxxxxx";
char arr2[] = "hello";
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
这就是调试后慢慢对细节的慢慢优化的过程。过程比结果重要,所以重在把握过程细节。
完善优化中const关键字再次理解
首先我们要知道const的作用:
1.const关键字修饰变量情景
这里的const修饰的是变量,所以这个变量是不能被修改的。但是可以用指针间接修改,如:
2.const关键字修饰数组操作数请景
3.const关键字修饰指针情景
3.1 const int *p
3.2 int const *p
这里int const *p和上述const int p是一样的,const都是修饰的p。
3.3 int* const p
3.4 const int* const p
4.const关键字修饰函数返回值情景
const int* test()
{
static int a = 10;
return &a;
}
int main()
{
int* p = test();
return 0;
}
这里的const修饰函数返回值的意义就是提示程序员后期维护中,不要对其返回值进行更改。
6.3 实现模拟strlen库函数
int my_strlen(const char* str)
{
//计数器
int count = 0;
//保证指针有效性
assert(str != NULL);
//判断条件再*str='\0'时停止
while (*str)
{
count++;
str++;
}
return count;
}
int main()
{
const char* p = "abcdef";
int len = my_strlen(p);
printf("len = %d\n", len);
return 0;
}
7.常见编程错误
我们要做一个善于发现问题,解决问题的人,让脑袋高速飞转解决问题,这样才能成为一个厉害的人,还是要保持空杯心态,重复输入,高效输出。加油!