补充上篇文章关于调试的相关知识点(以自定义strcpy为例)
我们在调试之前,应该保证自己能够写出一个利于调试的代码
一个好的代码要有以下的标准
- bug少
- 效率高
- 可读性强
- 可维护性高
- 注释清晰
- 文档齐全
***
同时还要有良好的编程习惯
-
多使用assert
-
尽量使用const
-
养成良好的编码风格
-
添加必要的注释
-
避免编码陷阱(以之前的数组arr和i的变量的地址重和为例)
以自定义#include<string.h>中的strcpy为例
void my_strcpy(char* dest , char* src)
{
while(*src != '\0') //利用while 语句将src中的替换到dest中
{
*dest ++ = *src ++;
}
*dest = *src; //别忘记最后的'\0',也要复制到dest中
}
上述代码 其实存在不少的问题
1.如果 dest 或者是 src 为空指针,程序就运行出错了。
2.官网上的是 char * strcpy ( char * destination, const char * source );
//== char*== 和我定义的void 存在差异,const 的应用是不是体现了代码的不完善??
==首先 ==
调用assert //使用之前#include<assert.h>
即 assert(src != NULL);
assert(dest != NULL);
// 若src和dest 中有任何一个是空指针,程序就会报错.
接下来
const 的使用
如果,我们在输入复制对象和复制内容的位置搞反了,结果就不是我们所期望的,所以可以通过const 修饰我们的复制内容,一旦我们的程序位置输入错误,程序会立即报错,提醒我们输入错误,这也是一个不错的调试技巧。
//补充 const 修饰指针变量的相关知识点
1.如果const 放在*之前,修饰的是指针所指向的内容无法改变
例如: const int * * number =& zhi; //表示zhi这个变量无法通过指针number改变,编译器不允许 **number =10,这样的语句对zhi的值进行改变.
2.const 放在 * 之后,修饰的是指针变量本身,指针变量无法改变,但是指针指向的内容可以发生变化.
例如: int * const number =&zhi; //表示number 这个指针就指向zhi这个变量,无法被改变指向其他的变量地址.
3.同时,也允许在*的左右两边都加上const进行修饰.
最后
对自定义函数的输出格式进行改变
从void 到 char** 意味着我们从不输出结果,到我们输出char* 类型变量的地址
以下是自定义函数的更改
char* my_strcpy(char* dest, const char* src)
{
//assert 的使用,防止空指针
asser(char* dest) != NULL;
asser(char* src) != NULL;
// 定义一个char类型的指针变量存放dest的地址
char* ret = dest;
//存在对while 函数的改进
while(*dest ++ = *src ++) //直接用*src的值作为判断循环是否结束的标志,同时将'\0'复制到dest上
{
;}
return ret; //返回ret的地址,即复制之后dest的地址.
}
int main()
{
char arr1[22]={xxxxxxxxxxx}; //定义dest
char arr2[22]={dingyi_mystrcpy}; //定义src
//调用函数my_strcpy
my_strcpy(arr1,arr2); //数组也是指针变量,其值为首地址
printf("%s\n",my_strcpy);
return 0;
}
以上就是关于调试的补充
接下来,我们讲#define 定义标识符常量和宏
//#define 定义标识符常量 //之前的文章有讲,就跳过
//#define 定义宏
例:
#define add (x,y) ((x)+(y)) //这就是宏的定义
#include<stdio.h>
int main()
{
int a = 0 ; //定义变量a , b
iny b = 3 ;
int c = add (a,b); //调用宏
printf("%d",c);
return 0;
}