如何运用长尾词技巧来提高调试效率?
- 内容介绍
- 文章标签
- 相关推荐
本文共计2156个文字,预计阅读时间需要9分钟。
山川相隔,心念星河,星河难及。上课啦!接上节课的调试验听(1),本节课进一步讲解调试验听(2)。
1. 调试验听实例讲解(2)
2. 招生笔试题解析
2. 如何写出好的(易于调试验听)的代?
所爱隔山海,山海皆可平,所念皆星河,星河不可及。
上课!
接着上节课讲的调试(1),本节课进一步讲解调试(2). @TOC 1.调试实例讲解(2)
校招笔试题
2.如何写出好的(易于调试)代码?
3.编程常见的错误
代码改错
int main()
{
int i = 0;
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (i = 0; i <=12; i++)
{
printf("hehe\n");
arr[i] = 0;
}
return 0;
}
在Release版本底下,i和 arr[12]所在的地址也不一样了。到这里,有同学会问到:既然 局部变量i 先创建内存空间,arr后创建那为什么不先创建arr的内存空间,后创建局部变量i的空间呢?这样i的内存空间不就在arr下面了吗,这样不就不会死循环了吗?来演示一下结果:
现在把 i 放在arr之后,也就是 i 的创建是在arr之后的,出现上面的结果
意思就是,数组越界了。 那为什么第一次死循环的时候 , 又没有报这个错误呢? 因为程序在忙着打印hehe,没空给你报错 就是这个道理 程序在忙着做自己的事情打印hehe 根本没空搭理你,给你报错 下面来一道题目
- 公司校招笔试题: 在Linux x86_64 gcc环境下,下面的程序会出现什么问题?运行的结果是什么?int main(int argc,char*argv[]) { long i; long a[16]; for (i = 0; i <= 17; i++) { a[i] = 0; printf("%d", i); } return 0; }其实这道题的本质是与上面的例题相同的只要你写出上面的分析过程,就能拿下这道题该题运行的现象仍然是会出现死循环
2.如何写出好的代码?
2.1代码运行正常bug很少效率高可读性高可维护性高注释清晰文档齐全
常见的coding技巧使用assert尽量使用const养成良好的编码风格5添加必要的注释避免编码的陷阱下面以一个例子说明上面所有的要点:模拟实现my_strcpy的功能strcpy函数,简单来说就是把一个字符串拷贝到另一个字符串里面//先观察strcpy的功能
#include
int main()
{
char arr[20] = "xxxxxxxxxxxxxxx";
char str[] = "hello world";
strcpy(arr, str);
printf("%s\n", arr);
}运行结果如下:
在c库中,可以搜索到strcpy函数的相关信息:
现在来模拟my_strcpy函数void mystrcpy(char* dst, char* src)
{
while(*dst++=*src++)
//等价于
//*dst = *src;
//dst++,src++;
{
;
}
}
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
}我们一般是这么写的但是这样写还有什么隐患呢?1.假如传过去的指针是空指针,就会出现问题,所以我们需要在while前面判断是否为空指针if(*dst ==NULL || *stc == NULL)
{
return ;
}但是这样写,还是会有问题,为什么呢?
1.每次进入my_strcpy函数内部,都要执行if语句,不管它是不是空指针。
2.它不会暴露错误出来,就算是空指针,也会悄悄规避掉,程序员无法知道自己穿的是空指针。
所以,引用 “断言”-----assert
assert内部可以放一个表达式,表达式如果为假,就报错,为真,啥事没有。仍然用上面的代码,来举例:void my_strcpy(char* dst, char* src)
{
assert(dst !=NULL && src != NULL);//断言
while (*dst++ = *src++)
{
;
}
}
int main()
{
char arr1[20] = { 0 };
char* p = NULL;//p指向的常量字符串无法更改
my_strcpy(arr1, p);
//如果是反着来,是无法更改的
printf("%s\n", arr1);
}运行结果如下:
它不仅能报错,还指出是哪个文件目录下的错误这就是(断言) assert 的好处假设有一个程序员,将void my_strcpy(char* dst, char* src)
{
assert(dst && src);
while(*dst++ = *src++ )
{
;
}
}
int main()
{
char arr1[20] = { 0 };
char* p = "hello";//p指向的常量字符串无法更改
my_strcpy(arr1, p);
printf("%s\n", arr1);
}写成了while(*src++ =*dst++ )
{
;
}也就是在while循环里面,将两个指针位置互换了这样写一定会有问题,那么会是什么问题?
可以知道,arr里面只有\0,把\0 复制到src的第一个位置后
循环马上停下了,输出的也就是arr1里面的内容,即\0如何避免呢?-----const
先来看一个例子,
可以通过指针修改 n 内部的值。但是当我在指针变量前面加上了 const后 , 结果如下:
它说,左值是必须可修改的,这就意味着,加上了const 后,指针指向的内容不可更改再来看一个例子:
看看有什么不同?
在这个例子中,我把const 放在了 * 的后面,这时候 p不能更改了。总结:
const修饰指针变量的时候
1.const放在的左边,修饰的是指针指向的内容
表示指针指向的内容,不能通过指针来改变*2.也可以放在的右边,const修饰的是指针变量本身
表示指针变量本身的内容不能被修改,但是指针指向的内容,
可以通过指针来改变回到上面的例子,所以当我写成
const char* src的时候,就算写反了位置,也没关系
因为这样写的时候void my_strcpy(char* dst, const char* src)
{
assert(dst && src);
while(*src++ = *dst++ )
{
;
}
}
int main()
{
char arr1[20] = { 0 };
char* p = hello;
my_strcpy(arr1, p);
printf("%s\n", arr1);
}编译器都报错了,更别说运行起来了看到这里,细心的朋友还会发现,
这里是char *类型的返回值呀,为什么上面写的都是void类型呢?
别着急,这就马上讲char* my_strcpy(char* dst, const char* src)
{
assert(dst && src);
char* ret = dst;//存储dst的起始位置
while(*src++ = *dst++ )
{
;
}
return ret ;
//这里不能返回dst,因为dst指向的空间不再是起始位置的地址了
}
int main()
{
char arr1[20] = { 0 };
char* p = hello;
my_strcpy(arr1, p);
printf("%s\n", arr1);
}大功告成!
总结:使用assert尽量使用const养成良好的编码风格5添加必要的注释避免编码的陷阱
3.编程常见的错误 3.1编译型错误直接看错误信息提示(双击错误行),或者根据经验直接判断,相对比较简单下面这个例子就是把英文的小括号写成了中文的小括号 3.2链接型错误 下面是一个链接型错误,链接型错误中,双击错误行是没有什么反应的,看行数也没什么效果,解决办法就是 "搜索" 按Ctrl +F5 打开搜索框进行搜索 下面是最后一个,也是最难的一个 3.3运行时错误运行时错误,也是最难解决的一个错误,就需要用到调试,上面讲的第一个例子就是运行时错误产生的,调试可以说是专门为了解决这个错误而产生的。今天的内容就到这里。总结:调试是重中之重,万事开头难,当你勇敢地迈出第一步,就成功了一半。 下课————— END —————
本文共计2156个文字,预计阅读时间需要9分钟。
山川相隔,心念星河,星河难及。上课啦!接上节课的调试验听(1),本节课进一步讲解调试验听(2)。
1. 调试验听实例讲解(2)
2. 招生笔试题解析
2. 如何写出好的(易于调试验听)的代?
所爱隔山海,山海皆可平,所念皆星河,星河不可及。
上课!
接着上节课讲的调试(1),本节课进一步讲解调试(2). @TOC 1.调试实例讲解(2)
校招笔试题
2.如何写出好的(易于调试)代码?
3.编程常见的错误
代码改错
int main()
{
int i = 0;
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (i = 0; i <=12; i++)
{
printf("hehe\n");
arr[i] = 0;
}
return 0;
}
在Release版本底下,i和 arr[12]所在的地址也不一样了。到这里,有同学会问到:既然 局部变量i 先创建内存空间,arr后创建那为什么不先创建arr的内存空间,后创建局部变量i的空间呢?这样i的内存空间不就在arr下面了吗,这样不就不会死循环了吗?来演示一下结果:
现在把 i 放在arr之后,也就是 i 的创建是在arr之后的,出现上面的结果
意思就是,数组越界了。 那为什么第一次死循环的时候 , 又没有报这个错误呢? 因为程序在忙着打印hehe,没空给你报错 就是这个道理 程序在忙着做自己的事情打印hehe 根本没空搭理你,给你报错 下面来一道题目
- 公司校招笔试题: 在Linux x86_64 gcc环境下,下面的程序会出现什么问题?运行的结果是什么?int main(int argc,char*argv[]) { long i; long a[16]; for (i = 0; i <= 17; i++) { a[i] = 0; printf("%d", i); } return 0; }其实这道题的本质是与上面的例题相同的只要你写出上面的分析过程,就能拿下这道题该题运行的现象仍然是会出现死循环

