实用调试技巧(三)

简介: 实用调试技巧

5、一些调试的实例。

5.1 实例一

实现代码:求 1!+2!+3! ...+ n! ;不考虑溢出。

演示错误代码:

1. #include<stdio.h>
2. int main()
3. {
4.  int i = 0;
5.  int sum = 0;//保存最终结果
6.  int n = 0;
7.  int ret = 1;//保存n的阶乘
8.  scanf("%d", &n);
9.  for (i = 1; i <= n; i++)
10.   {
11.     int j = 0;
12.     for (j = 1; j <= i; j++)
13.     {
14.       ret *= j;
15.     }
16.     sum += ret;
17.   }
18.   printf("%d\n", sum);
19.   return 0;
20. }

很明显,结果是不对的,那么我们怎么去找毛病所在呢?调试!!!

首先,我们打开监视,看看过程中是什么原因:

我们可以看到当i=2的时候一切还正常,接下来:

当i=3的时候我们看到ret=12!!

这说明了什么问题?问题出在ret上,因为ret一直在累加,每一次循环结束后,ret的值并没有归1,这就导致后面的数值变大,所以,正确的应该是这样的:

1. #include<stdio.h>
2. int main()
3. {
4.  int i = 0;
5.  int sum = 0;//保存最终结果
6.  int n = 0;
7.  int ret = 1;//保存n的阶乘
8.  scanf("%d", &n);
9.  for (i = 1; i <= n; i++)
10.   {
11.     ret = 1;
12.     int j = 0;
13.     for (j = 1; j <= i; j++)
14.     {
15.       ret *= j;
16.     }
17.     sum += ret;
18.   }
19.   printf("%d\n", sum);
20.   return 0;
21. }

5.2 实例二

1. #include <stdio.h>
2. int main()
3. {
4. int i = 0;
5. int arr[10] = {0};
6. for(i=0; i<=12; i++)
7. {
8. arr[i] = 0;
9. printf("hehe\n");
10. }
11. return 0;
12. }

代码死循环的原因上面已经讲过了!这是一个典型的调试题。

6、如何写出好(易于调试)的代码。

6.1 优秀的代码:

1. 代码运行正常

2. bug很少

3. 效率高

4. 可读性高

5. 可维护性高

6. 注释清晰

7. 文档齐全

常见的coding技巧:

1. 使用assert

2. 尽量使用const

3. 养成良好的编码风格

4. 添加必要的注释

5. 避免编码的陷阱。

 

6.2 示范:

模拟实现库函数:strcpy

首先我们打开MSDN看一下strcpy的信息:

没有下载的小伙伴可以看我往期的一个博客里面有链接,现在放下面了:

https://blog.csdn.net/m0_67995737/article/details/124789657

1. 
2. char* strcpy(char* dst, const char* src)
3. {
4.  char* cp = dst;
5.  assert(dst && src);
6.  while (*cp++ = *src++)
7.    ; /* Copy src over dst */
8.  return(dst);
9. }

其中assert函数是断言的意思,当assert出现错误时,就会报错,帮助提醒你进行修改,这里是防止空指针的情况!

6.3 const的作用

1. #include <stdio.h>
2. //代码1
3. void test1()
4. {
5.  int n = 10;
6.  int m = 20;
7.  int* p = &n;//可以更改p的指向,也可以更改p所指内存的数值
8.  *p = 20;//ok
9.  p = &m; //ok
10. }
11. void test2()
12. {
13.   //代码2
14.   int n = 10;
15.   int m = 20;
16.   const int* p = &n;//可以更改p的指向,但不能更改p所指内存的数值
17.   *p = 20;//err
18.   p = &m; //ok
19. }
20. void test3()
21. {
22.   int n = 10;
23.   int m = 20;
24.   int* const p = &n;//可以修改p所指内存的数值,但不能更改p的指向
25.   *p = 20; //ok
26.   p = &m; //err
27. }
28. int main()
29. {
30.   //测试无cosnt的
31.   test1();
32.   //测试const放在*的左边
33.   test2();
34.   //测试const放在*的右边
35.   test3();
36.   return 0;
37. }

结论:
const修饰指针变量的时候:
1. const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改
变。但是指针变量本身的内容可变。
2. const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指
针指向的内容,可以通过指针改变。

6.4模拟实现一个strlen函数

参考代码:

1. #include <stdio.h>
2. #include<assert.h>
3. int my_strlen(const char* str)
4. {
5.  int count = 0;
6.  assert(str != NULL);
7.  while (*str)//判断字符串是否结束
8.  {
9.    count++;
10.     str++;
11.   }
12.   return count;
13. }
14. int main()
15. {
16.   const char* p = "abcdef";
17.   //测试
18.   int len = my_strlen(p);
19.   printf("len = %d\n", len);
20.   return 0;
21. }

7、编程常见的错误

 

7.1 编译型错误

直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单。

这个很常见:

比如:

像这种的就叫编译型错误。

7.2 链接型错误

看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不

存在或者拼写错误。

比如这个

7.3 运行时错误

前面列举的调试中的问题就是运行时的错误。

借助调试,逐步定位问题。最难搞。

温馨提示:
做一个有心人,积累排错经验。

相关文章
|
7月前
|
C++
VS调试技巧
VS调试技巧
38 0
|
网络协议 C++
继续分享 5 个实用的 vs 调试技巧
继续分享 5 个实用的 vs 调试技巧
|
6月前
|
NoSQL 程序员 Linux
实用调试技巧(1)
实用调试技巧(1)
50 7
|
6月前
实用调试技巧(2)
实用调试技巧(2)
40 0
|
7月前
|
IDE 开发工具
掌握条件断点,调试技巧大揭秘
掌握条件断点,调试技巧大揭秘
124 0
|
安全 程序员 Windows
实用调试技巧
实用调试技巧
91 0
|
程序员 编译器
实用调试技巧(上)
实用调试技巧
|
程序员 C语言
5 个非常实用的 vs 调试技巧
5 个非常实用的 vs 调试技巧
|
程序员 C语言
实用调试技巧 下
实用调试技巧 下