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

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

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


相关文章
|
5月前
|
Java Maven
程序调试:日常经验总结(一)
程序调试:日常经验总结(一)
|
10月前
|
编译器
适合初学者的超详细实用调试技巧(下)一
适合初学者的超详细实用调试技巧
41 0
|
10月前
|
程序员 Windows
适合初学者的超详细实用调试技巧(上)二
适合初学者的超详细实用调试技巧
46 0
|
10月前
|
程序员 编译器 C++
适合初学者的超详细实用调试技巧(上)一
适合初学者的超详细实用调试技巧
54 0
|
11月前
|
程序员 C语言
实用调试技巧【下篇】
实用调试技巧【下篇】
58 0
|
12月前
|
IDE NoSQL 程序员
必备技能:程序的调试
本节内容相对来说比较笼统一些,但是也是非常非常非常重要的一节内容,毕竟一个程序猿不能只会写bug,你写一堆bug谁来修呢?所以通过调试去排查错误的能力是一个优秀的程序猿必须要掌握的技能,而且不能仅仅是掌握,更要精通,本节内容总体来说只有两大部分,一是学习调试的方法,会有举例实际去感受一下,二是在写代码就要考虑的一些问题,养成良好的写代码习惯,防患于未然。
必备技能:程序的调试
|
程序员 编译器 C++
VS2019调试 实用调试技巧 (优秀程序员必看)
Debug :通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。 Release :称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优 的,以便用户很好地使用。
501 0
VS2019调试 实用调试技巧 (优秀程序员必看)
|
存储 NoSQL Ubuntu
调试基础知识及原理
调试基础知识及原理
92 0
|
程序员 编译器 C语言
程序员必备的VS调试技巧
程序员必备的VS调试技巧
133 0
程序员必备的VS调试技巧