C语言有这个就够了七.实用调试技巧
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言有这个就够了七.实用调试技巧相关的知识,希望对你有一定的参考价值。
(一)什么是BUG
历史上第一个bug
导致程序运行错误的对象
(二)调试是什么
调试就是破案的过程,因为有人写代码是这样的:
1.调试
又称除错,是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。
2.调试的基本步骤
- 发现错误的存在
- 以隔离,消除等方式对错误进行定位
- 确定错误的产生原因
- 提出纠正错误的解决办法
- 对程序错误予以改正,重新测试
3.debug和release的介绍
debug称为调试版本,它包含调试信息,且不做任何优化,便于存程序员调试程序
release称为发布版本,它往往是进行了各种优化,使程序在代码大小和运行速度上都是最优的,以便用户使用
我们可以看到,同一个代码,在不同版本下,内存大小不同。
同样对于这个代码:
#include <stdio.h>
int main()
int i = 0;
int arr[10] = 0 ;
for (i = 0; i <= 12; i++)
arr[i] = 0;
printf("gaga\\n");
return 0;
如果是 debug 模式去编译,程序的结果是死循环;
如果是 release 模式去编译,程序没有死循环;
这样看来,release的确会优化。
(三) Windows环境调试介绍
1.准备
选择debug模式
2.快捷键
2.1 F5
启动调试,经常用来直接跳到下一个断点处。
注:F5通常与F9配合使用(在代码错误处用F9设置断点,用F5直接跳到断点处)
2.2 F9
创建断点和取消断点(代码执行到断点处停下来)
断点的重要作用,可以在程序的任意位置设置断点。
这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。
2.3 F10
逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。
2.4 F11
逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最常用的)
3.调试的时候查看程序当前信息
合理运用,可以更快找出bug。
(四) 一些调试的实例
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;
我们发现i=3时,ret为12,结果错误;
仔细分析,发现ret未初始化;
在 int j=0;
前增加ret=1;
2.研究程序死循环的原因
#include <stdio.h>
int main()
int i = 0;
int arr[10]=1,2,3,4,5,6,7,8,9,10;
for (i = 0; i <= 12; i++)
arr[i] = 0;
printf("gaga\\n");
return 0;
1.栈区的默认使用规则:
先使用高地址处的空间
再使用低地址处的空间
2.数组随着下标的增长,地址由低到高变化
3.过程中数组越界可能可能遇到i,在越界改变时可能把i变为0,导致程序死循环
(五)如何写出好代码
1.优秀的代码
代码运行正常
bug很少
效率高
可读性高
可维护性高
注释清晰
文档齐全
2.技巧
使用assert
尽量使用const
养成良好的编码风格
添加必要的注释
避免编码的陷阱
3.案例模拟实现strcpy
#include<stdio.h>
int main()
char arr1[] = "#########";
char arr2[] = "ajfhk";
strcpy(arr1, arr2);
printf("%s\\n", arr1);
return 0;
那为什么没有打印后面的#######?
通过调试发现:
拷贝了一个\\0过去,打印时遇到\\0停止
自己的strcpy
5分
#include<stdio.h>
void my_strcpy(char* dest, char* src)
while (*src != \\0)
*dest = *src;
src++;
dest++;
*dest = *src;//0
int main()
char arr1[] = "#########";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\\n", arr1);
return 0;
6分
#include<stdio.h>
void my_strcpy(char* dest, char* src)
while (*dest++ = *src++)
;
int main()
char arr1[] = "#########";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\\n", arr1);
return 0;
7分
#include<stdio.h>
void my_strcpy(char* dest, char* src)
if (dest != NULL && src != NULL)
while (*dest++ = *src++)
;
int main()
char arr1[] = "#########";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\\n", arr1);
return 0;
防止输入为NULL的时候,整个程序崩盘;但这种更改方式也没有进行拷贝,而且没提示;
8分
#include<stdio.h>
#include<assert.h>
void my_strcpy(char* dest, char* src)
assert(dest != NULL);//断言
assert(src != NULL);
while (*dest++ = *src++)
;
int main()
char arr1[] = "#########";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\\n", arr1);
return 0;
通过assert判断,并且及时报错
但是,当程序员写反时*src++=*dest++,依然有可能运行成功(只要arr1<arr2)
#include<stdio.h>
#include<assert.h>
void my_strcpy(char* dest, char* src)
assert(dest != NULL);
assert(src != NULL);
while (*src++=*dest++)
;
int main()
char arr1[] = "#####";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\\n", arr1);
return 0;
9分
#include<stdio.h>
#include<assert.h>
void my_strcpy(char* dest, const char* src)//加上const,反了会报错。
assert(dest != NULL);
assert(src != NULL);
while (*dest++ = *src++)
;
int main()
char arr1[] = "#####";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\\n", arr1);
return 0;
const使变量不能改变,注意
#include<stdio.h>
int main()
const int num = 10;
int* p = #
*p = 20;
printf("%d\\n", num);
return 0;
这里p改变了一个我们主观上不想改变的值,
#include<stdio.h>
int main()
const int num = 10;
int n=100;
const int* p = #//即使写错了,也能报错
//const放在*左边时,修饰*p,也就是说:不能通过p来改变*p(num)的值
*p = 20;
printf("%d\\n", num);
return 0;
#include<stdio.h>
int main()
const int num = 10;
int*const p = #
//const放在*右边时,修饰p,也就是说:不能改变p的值
*p = 20;
int n=10;
p=&n;
printf("%d\\n", num);
return 0;
10分
#include<stdio.h>
#include<assert.h>
char*my_strcpy(char* dest, const char* src)//加上const,反了会报错。
char*ret=dest;
assert(dest != NULL);
assert(src != NULL);
while (*dest++ = *src++)//把src指向的字符串拷贝到dest指向的字符串,包含\\0
;
return ret;
int main()
char arr1[] = "#####";
char arr2[] = "ajfhk";
printf("%s\\n",my_strcpy(arr1, arr2));//返回值时另一个函数的参数
return 0;
4.案例模拟实现strlen
#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str)//*str指向的内容不会被改变,但是指针的位置可以改变
int count = 0;
assert(str != NULL);
while (* str != \\0)
count++;
str++;
return count;
int main()
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\\n", len);
return 0;
(七)编程常见的错误
1.编译型错误
直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单。
2.链接型错误
看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不
存在或者拼写错误。
3.运行时错误
借助调试,逐步定位问题,最难搞。
以上是关于C语言有这个就够了七.实用调试技巧的主要内容,如果未能解决你的问题,请参考以下文章