模拟strcpy
一份代码不仅注重结果,优秀的代码一定要注意以下方面:
- 使用assert
- 常用const
- 养成好的编码风格
- 添加必要的注释
- 避免编码的陷阱
越界访问
先来看一段越界代码:

这段代码陷入了死循环,但为什么呢,我们调试观察一下。

可以发现在我们第12次循环赋值后,i的值也变成了0,好像是跟着arr[12]一起改变的,我们打印一下它们的地址来验证我们的猜测。

它们的地址竟然是一样的!要想解释这个现象,就要考虑栈空间的存储结构了。栈区中储存数据时先使用高地址后使用低地址。由于我们先创建的i变量再创建的数组,就可能导致越界访问时修改i的值。
注:中间相隔多少个元素取决于编译器。
模拟strcpy
先来看看库函数中的strcpy函数是怎样实现的:

大家看看这样的代码有什么问题:
void my_strcpy(char* str, char* scr)
{
while (*str++ = *scr++)
{
;
}
}
函数接收了两个char*类型的指针变量,如果为空指针,那程序就会出错,所以我们可以添加assert来进行断言。
#include<aseert.h>
assert(str != NULL);//断言
assert(scr != NULL);//断言
assert(str);//断言
assert(scr);//断言
assert(str && scr);//断言
其次,被拷贝的变量可以在前面加上const使其无法修改指向的值,如果不小心将赋值写反了就能被编译器检测出,我们代码的健壮性也会大大提高。
*src = *str;//ERR
此外,对比库函数具有返回值char*,使其可以作为参数被接收,我们可以这样修改
char* my_strcpy(char* str, const char* scr)
{
char* ret = str;
assert(dest && src);
while (*str++ = *scr++)
{
;
}
return ret;
}
注意返回值必须是函数首地址,所以需要先储存目标变量的地址。
const用法
const修饰变量使其转换为具有常属性的常变量,本质上是变量,只是具有了常属性。通过定义数组可以发现[ ]内使用它会被不支持变长数组的编译器认为变量。
const int a = 0;
const修饰的指针
被它修饰的指针无法改变指向对象的值,但是如果你想改变该指针指向的地址,发现是可以的。
int a = 0;
int b = 0;
//const int a = 0;
const int *p = &a;
\\错误写法*p = 10;
p = &b;
下面两条语句的意思是相同的:
const int *a;
int const *a;
常量指针
在*后面加上const,被它修饰的指针自身无法改变、赋值,但可以通过解引用操作指向的空间。
int a = 0;
int *const p = &a;
*p = 10;
指向常量的常指针
指针常量则是二者结合,既不能通过它改变地址,也不能通过它改变地址所储存的值。
int a = 0;
const int *const p = &a;

被折叠的 条评论
为什么被折叠?



