【C语言】如何写出好(易于调试)的代码——assert和const的使用

简介: 【C语言】如何写出好(易于调试)的代码——assert和const的使用

一、优秀的代码

1. 代码运行正常

2. bug很少

3. 效率高

4. 可读性高

5. 可维护性高

6. 注释清晰

7. 文档齐全

常见的coding技巧:

1. 使用assert

2. 尽量使用const

3. 养成良好的编码风格

4. 添加必要的注释

5. 避免编码的陷阱

二、示范:模拟实现库函数:strcpy

如果只是写成这样,那么会面临一些问题:当函数传入空指针时,是非常危险的。

#include <cassert>
char* myStrcpy(char* dst, char* src)
{
  char* ret = dst;
  while (*dst = *src)
  {
    dst++;
        src++;
  }
  return ret;
}
int main()
{
  char arr1[] = {"Hello nash"};
  char arr2[11] = { 0 };
  myStrcpy(arr2, arr1);
  int i = 0;
  printf("%s\n", arr2);
  return 0;
}

那么这样的话,有的人想到的解决方法是在执行之前先判断一下传入的参数,如果不等于NULL再执行。

1. char* myStrcpy(char* dst, char* src)
2. {
3.  if(dst != NULL && src != NULL)
4.  {
5. char* ret = dst;
6.      while (*dst = *src)
7.      {
8.        dst++;
9.             src++;
10.       }
11.     }
12.   return ret;
13. }

但是这样写又面临一个问题,因为if语句不管在debug模式还是release模式下,只要进入函数就一定会执行if语句,这样就降低了函数的效率,浪费时间。而这里我给大家介绍一个宏:assert

三、宏assert

assert只会在debug模式下被使用,能够防止程序员错误使用空指针。当在release模式下时会被自动优化消失,不参与编译。这样既能做到不让程序员使用空指针,又能不降低效率。

包含头文件: cassert

当给assert传入的表达式如果为假,那么就会触发宏报错,并且还会返回报错信息,这样也能帮助程序员快速解决问题,显然比直接使用if判断好很多。

那么只要将src和dst传给assert,就可以避免错误运行函数。

char* myStrcpy(char* dst, char* src)
{
  if(dst != NULL && src != NULL)
  {
        char* ret = dst;
      while (*dst = *src)
      {
        dst++;
            src++;
      }
    }
  return ret;
}

四、const的作用

1、const修饰变量

const能够限制被修改。当const修饰变量时,只是在语法层面限制了变量的修改,但本质上它依然是变量,是一种并不能被修改的变量。

2、const修饰指针

const修饰指针有两种方式:

  • const放在*的左边    const int* p
  • const放在*的右边    int* const p

测试const放在*的左边

测试const放在*的右边

结论:

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

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

五、 strcpy库函数

这是strcpy函数的官方写法,可以看到就是使用了assert与const提高了代码的质量。

/***
*char *strcpy(dst, src) - copy one string over another
*
*Purpose:
*       Copies the string src into the spot specified by
*       dest; assumes enough room.
*
*Entry:
*       char * dst - string over which "src" is to be copied
*       const char * src - string to be copied over "dst"
*
*Exit:
*       The address of "dst"
*
*Exceptions:
*******************************************************************************/
char * strcpy(char * dst, const char * src)
{
       char * cp = dst;
assert(dst && src);
       while( *cp++ = *src++ )
               ;     /* Copy src over dst */
       return( dst );
}

如果觉得作者写的不错,求给作者一个大大的点赞支持一下,你们的支持是我更新的最大动力!

目录
相关文章
|
2月前
|
存储 搜索推荐 C语言
深入C语言指针,使代码更加灵活(二)
深入C语言指针,使代码更加灵活(二)
|
2月前
|
存储 程序员 编译器
深入C语言指针,使代码更加灵活(一)
深入C语言指针,使代码更加灵活(一)
|
2月前
|
C语言
深入C语言指针,使代码更加灵活(三)
深入C语言指针,使代码更加灵活(三)
深入C语言指针,使代码更加灵活(三)
|
3月前
|
安全 C语言
在C语言中,正确使用运算符能提升代码的可读性和效率
在C语言中,运算符的使用需要注意优先级、结合性、自增自减的形式、逻辑运算的短路特性、位运算的类型、条件运算的可读性、类型转换以及使用括号来明确运算顺序。掌握这些注意事项可以帮助编写出更安全和高效的代码。
51 4
|
2月前
|
C语言
C语言调试
C语言调试
19 0
|
2月前
|
C语言
C语言练习题代码
C语言练习题代码
|
3月前
|
存储 算法 C语言
C语言手撕实战代码_二叉排序树(二叉搜索树)_构建_删除_插入操作详解
这份二叉排序树习题集涵盖了二叉搜索树(BST)的基本操作,包括构建、查找、删除等核心功能。通过多个具体示例,如构建BST、查找节点所在层数、删除特定节点及查找小于某个关键字的所有节点等,帮助读者深入理解二叉排序树的工作原理与应用技巧。此外,还介绍了如何将一棵二叉树分解为两棵满足特定条件的BST,以及删除所有关键字小于指定值的节点等高级操作。每个题目均配有详细解释与代码实现,便于学习与实践。
|
3月前
|
存储 算法 C语言
C语言手撕实战代码_二叉树_构造二叉树_层序遍历二叉树_二叉树深度的超详细代码实现
这段代码和文本介绍了一系列二叉树相关的问题及其解决方案。其中包括根据前序和中序序列构建二叉树、通过层次遍历序列和中序序列创建二叉树、计算二叉树节点数量、叶子节点数量、度为1的节点数量、二叉树高度、特定节点子树深度、判断两棵树是否相似、将叶子节点链接成双向链表、计算算术表达式的值、判断是否为完全二叉树以及求二叉树的最大宽度等。每道题目均提供了详细的算法思路及相应的C/C++代码实现,帮助读者理解和掌握二叉树的基本操作与应用。
|
3月前
|
存储 算法 C语言
C语言手撕实战代码_循环单链表和循环双链表
本文档详细介绍了用C语言实现循环单链表和循环双链表的相关算法。包括循环单链表的建立、逆转、左移、拆分及合并等操作;以及双链表的建立、遍历、排序和循环双链表的重组。通过具体示例和代码片段,展示了每种算法的实现思路与步骤,帮助读者深入理解并掌握这些数据结构的基本操作方法。
|
3月前
|
算法 C语言 开发者
C语言手撕实战代码_单链表
本文档详细介绍了使用C语言实现单链表的各种基本操作和经典算法。内容涵盖单链表的构建、插入、查找、合并及特殊操作,如头插法和尾插法构建单链表、插入元素、查找倒数第m个节点、合并两个有序链表等。每部分均配有详细的代码示例和注释,帮助读者更好地理解和掌握单链表的编程技巧。此外,还提供了判断子链、查找公共后缀等进阶题目,适合初学者和有一定基础的开发者学习参考。