适合初学者的超详细实用调试技巧(下)二

简介: 适合初学者的超详细实用调试技巧

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


6.1 优秀的代码


优秀的代码应该满足以下条件。


1. 代码运行正常


2. bug很少


3. 效率高


4. 可读性高


5. 可维护性高


6. 注释清晰


7. 文档齐全


为了达到这样的条件,我们可以使用以下常见的coding技巧:


1. 使用assert


2. 尽量使用const


3. 养成良好的编码风格


4. 添加必要的注释


5. 避免编码的陷阱。


6.2 示范


我们来模拟实现库函数strcpy:


函数的参数形式char* strcpy(char*destination,const char*source);


该参数说明了strcpy返回类型是char类型的指针,将源头(不能被改)拷贝到目的地。


strcpy特点和strlen类似,遇到‘\0’就停止。


比较容易想到的写法是:


#include<stdio.h>
#include<string.h>
#include<assert.h>
void my_strcpy(char* a, char* b)
{
  while (*a != '\0')
  {
  *b = *a;
  b++;
  a++;
  }
  *b = *a;
}
int main()
{
  char a[] = "abcdef";
  char b[10];
  my_strcpy(a, b);
  printf("%s", b);
  return 0;
}

虽然可以实现strcpy函数的内容,但是优化不怎么样,将简单的功能写的非常麻烦,且无法避免空指针的情况,下面为优化后的写法:


#include<stdio.h>
#include<assert.h>
void my_strcpy(const char a[],char b[])
{
    assert(a!=NULL&&b!=NULL);//断言函数来避免空指针的情况
  while (*b++ = *a++)
  {
  ;//当*a为\0的时候,while里的值为假,跳出循环
  }
}
int main()
{
  char a[] = "abcdef";
  char b[10]="";//定义第二个数组来拷贝数组
  my_strcpy(a,b);
  printf("%s", b);
  return 0;
}


值得注意的是,assert断言函数和const的使用,可以大大增加代码的安全性。


6.3 const的作用


#include <stdio.h>
//代码1
void test1()
{
    int n = 10;
    int m = 20;
    int *p = &n;
    *p = 20;//ok?
    p = &m; //ok?
}
void test2()
{
     //代码2
    int n = 10;
    int m = 20;
    const int* p = &n;
    *p = 20;//ok?
    p = &m; //ok?
}
void test3()
{
    int n = 10;
    int m = 20;
    int *const p = &n;
    *p = 20; //ok?
    p = &m;  //ok?
}
int main()
{
    //测试无cosnt的
   test1();
    //测试const放在*的左边
    test2();
    //测试const放在*的右边
    test3();
    return 0;
}


结论:


const修饰指针变量的时候:


1. const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改 变。但是指针变量本身的内容可变。


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


6.4. const的实例


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int my_strlen(const char a[])//用const来使代码更加安全
{
  int count = 0;
  while (* a++ != '\0')
  {
  count++;
  }
  return count;
}
int main()
{
  char a[]="abcdef";
  int b = my_strlen(a);
  printf("%d", b);
  return 0;
}

7.编程常见的错误


7.1 编译型错误


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


如:逗号的使用,分号的添加,括号的对应,各类操作符的使用,库函数的使用格式等。


对于这种问题,我们可以直接通过错误列表的提示来定位问题所在,解决问题。


7061185533853e088741a440e88e4c11_5dc86addf01d448ea5327cc1e51023ed.png


7.2 链接型错误


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


如:变量、头文件的包含,文件的引入,常量和宏的定义,库函数名的拼写,自定义函数名的一致等等。


就例如将main写错为mian这样的错误。


38dccda431b394734ba296f0738d6e6e_040f8ff91e8644d2afb2bf5aea558311.png


7.3 运行时错误


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


如:栈溢出,逻辑漏洞,未指针的越界访,未初始化的变量,字符串溢出,数组越界,重复释放内存,使用无效的指针等等。


就像上文里的几个例子。


对于这样的问题,可以通过调试来解决。


说了这么多,调试的章节终于结束了!


希望大家都能成为20%的时间在写程序,但是80%的时间在调试的程序员!

264815a6a5f2bb76efd8f5ee9055f1f9_822107916c7b4ff68d081b6c4925d4c7.jpeg


相关文章
|
7月前
|
缓存 前端开发 JavaScript
【第22期】 一文读懂前端调试利器whistle
【第22期】 一文读懂前端调试利器whistle
138 0
|
4月前
R语言错误处理与调试:如何高效调试R代码
【8月更文挑战第28天】调试R代码是一项需要不断练习和提高的技能。通过理解常见的错误类型、使用`traceback()`查看错误路径、逐步执行代码、利用`tryCatch()`捕获和处理错误、设置更严格的警告级别、利用RStudio的调试工具以及编写可复现的示例,你可以更加高效地调试R代码,并快速解决遇到的问题。
|
6月前
|
Shell 数据安全/隐私保护 开发者
详细解读ApolloGPS调试笔记
详细解读ApolloGPS调试笔记
28 0
|
7月前
|
NoSQL 编译器 C语言
【C 言专栏】C 语言中的调试技巧与工具
【5月更文挑战第6天】在C语言编程中,调试是必不可少的技能,涉及基本技巧如打印输出、断点调试和单步执行,以及使用GCC、GDB、Visual Studio和Eclipse CDT等工具。高级技巧包括内存检查和性能分析。通过分析问题、设置断点、逐步调试和检查逻辑来解决错误。调试时需保持耐心,合理选用工具,记录过程,并避免过度调试。熟练掌握这些技能将提升代码质量和开发效率。
172 0
【C 言专栏】C 语言中的调试技巧与工具
|
程序员 编译器
编程终极技能-调试(上)
编程终极技能-调试
|
IDE 程序员 编译器
必备技能:程序的调试
本节内容相对来说比较笼统一些,但是也是非常非常非常重要的一节内容,毕竟一个程序猿不能只会写bug,你写一堆bug谁来修呢?所以通过调试去排查错误的能力是一个优秀的程序猿必须要掌握的技能,而且不能仅仅是掌握,更要精通,本节内容总体来说只有两大部分,一是学习调试的方法,会有举例实际去感受一下,二是在写代码就要考虑的一些问题,养成良好的写代码习惯,防患于未然。
必备技能:程序的调试
|
程序员 Windows
适合初学者的超详细实用调试技巧(上)二
适合初学者的超详细实用调试技巧
75 0
|
程序员 编译器 C++
适合初学者的超详细实用调试技巧(上)一
适合初学者的超详细实用调试技巧
88 0
|
编译器
适合初学者的超详细实用调试技巧(下)一
适合初学者的超详细实用调试技巧
76 0
|
程序员 编译器 C语言
程序员必备的VS调试技巧
程序员必备的VS调试技巧
164 0
程序员必备的VS调试技巧
下一篇
DataWorks