1.优秀的代码具有的条件
- 代码运行正常
- bug很少
- 效率高
- 可读性高
- 可维护性高
- 注释清晰
- 文档齐全
2.常见的编码技巧
- 使用assert
- 尽量使用const
- 养成良好的编码风格
- 添加必要的注释
- 避免编码的陷阱
-
代码的优化
示例:模拟实现strcpy函数
方法一:
void my_strcpy(char* dest, char* src)
{
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}//到这里src所指的字符串还剩下\0没有拷贝过去
*dest = *src;//这样就可以拷贝过去了
}
int main()
{
char arr1[20] = "xxxxxxxxxxxxx";
char arr2[] = "hello bit";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
将上方代码进行优化:
void my_strcpy(char* dest, char* src)
{
while (*dest++=*src++)//利用\0的ASCII码值是0
{
;
}
}
int main()
{
char arr1[20] = "xxxxxxxxxxxxx";
char arr2[] = "hello bit";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
思考:如果误将空指针传入函数,怎么办?
接下来我们引入assert相关知识来解决这个问题。
-
assert
void assert( int expression );
assert宏的原型定义在<assert.h>中,其作用是先计算表达式 expression ,如果expression的值为假(即为0),那么它先向stderr(标准错误输出)打印一条出错信息,然后通过调用abort(异常终止一个进程) 来终止程序运行。
下面进行代码优化:
include <assert.h>
void my_strcpy(char* dest, char* src)
{
//断言
assert(dest != NULL);
assert(src != NULL);
while (*dest++ = *src++)//利用\0的ASCII码值是0
{
;
}
}
int main()
{
char arr1[20] = "xxxxxxxxxxxxx";
char arr2[] = "hello bit";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
到这里,我们在和标准库函数对比一下:
这里发现库函数strcpy的返回类型是char*(函数返回的是目标空间的起始地址)
接下来我们继续优化代码:
#include <assert.h>
char* my_strcpy(char* dest, char* src)
{
char* ret= dest;//保留好dest的起始地址
assert(dest != NULL);
assert(src != NULL);
while (*dest++ = *src++)//利用\0的ASCII码值是0
{
;
}
return ret;
}
int main()
{
char arr1[20] = "xxxxxxxxxxxxx";
char arr2[] = "hello bit";
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
结果:hello bit
-
const修饰
1.const修饰变量
const修饰变量时,只是在语法层面限制了变量修改,但是本质上,num还是变量,是一种不能被修改的变量(可称 常变量)
2.const修饰指针
先看一个例子:
int main()
{
const int num = 10;
printf("num=%d\n", num);
int* p = #
*p = 20;
printf("num=%d\n", num);
return 0;
}
这里代码虽然能运行,点这是一种违规行为。
下面我们通过const修饰指针的方式来改善代码:
const修饰指针变量需要关注的五个方面:
- 指针变量p本身能不能更改
- 指针变量指向的对象能不能改(*p)
- const放在*的左边
- contst放在*的右边
- const在*左右都存在
-
const放在*左边
int main()
{
const int num = 10;
printf("num=%d\n", num);
const int* p = #
*p = 20;
printf("num=%d\n", num);
return 0;
}
const放在*左侧,限制的是指针变量所指向的内容(即不能通过指针来修改指针所指向的内容);但是指针变量本身可以修改(即指针变量可以指向其他对象)
-
const放在*右边
int main()
{
const int num = 10;
printf("num=%d\n", num);
int* const p = #
*p = 20;
int n = 100;
p = &n;
printf("num=%d\n", num);
return 0;
}
const放在*右侧,限制的是指针变量本身(即指针变量不能再指向其他对象);但是可以通过指针变量来修改其指向的内容
-
const存在于*左右两侧
int main()
{
const int num = 10;
printf("num=%d\n", num);
const int*const p = #
*p = 20;
int n = 100;
p = &n;
printf("num=%d\n", num);
return 0;
}
const存在于左右两侧时,则指针变量本身及其所指向的内容(*p)都不能更改。
3.检测小妙招
了解完上述知识后,我们来学习一个小技巧来检测上方模拟strcpy函数是否出错的情况,可以帮我们提高效率,节省时间。
下面看:
#include <assert.h>
char* my_strcpy(char* dest, char* src)
{
char* ret= dest;//保留好dest的起始地址
assert(dest != NULL);
assert(src != NULL);
while (*src++ = *dest++) 假设这里我们写反了,运行时并没有报错,但结果是错的
{
;
}
return ret;
}
int main()
{
char arr1[20] = "xxxxxxxxxxxxx";
char arr2[] = "hello bit";
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
如果按正常步骤走的话,我们就要进行调试一步一步查找错误,但我们可以添加const修饰,让我们直接定位到这个错误:
#include <assert.h>
char* my_strcpy(char* dest, const char* src) //这里添加const修饰
{
char* ret= dest;
assert(dest != NULL);
assert(src != NULL);
while (*src++ = *dest++)0
{
;
}
return ret;
}
int main()
{
char arr1[20] = "xxxxxxxxxxxxx";
char arr2[] = "hello bit";
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
这样代码在运行时问题就直接暴露出来了,可以直接进行更正了。