1.strcpy库函数函数的应用
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "XXXXXXXXXXXX";
char arr2[] = "hello bit";
printf("%s\n", strcpy(arr1,arr2));
return 0;
}
strcpy使用前需要引用头文件string.h
strcpy的使用:strcpy(目标空间,源数据)
strcpy拷贝数据的时候会把源字符串的\0也拷贝过去
2.模拟实现strcpy函数功能
主函数
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "XXXXXXXXXXXX";
char arr2[] = "hello bit";
my_strcpy(arr1,arr2);
printf("%s\n", arr1);
return 0;
}
my_strcpy函数
void my_strcpy(char* dest,char* src)
{
while(*src != '\0')
{
*dest = *src;
dest++;
src++;
}
*dest = *src;
}
当src不是\0的时候进入循环,当src是\0的时候退出循环
最后再把\0给*dest。
这样写看着没什么问题,但这种代码如果总分是10分只能
给5分,想想这样写会不会太啰嗦了呢?while的时候进行
拷贝,退出while的时候又拷贝一次,太啰嗦了。
下面对其进行改进
3.改进一
void my_strcpy(char* dest,char* src)
{
while(*dest++ = *src++)
{
;//空语句
}
}
这样写会不会觉得眼前一亮?先说明一下后置加加在这里的意思
比如:*dest++的意思是先对dest解引用,再对dest加加,通俗来讲
就是,先找到dest中的数据,再对dest这个指针(也就是地址)+1。
那么*dest++ = *src++,当拷贝的不是\0的时候,是真,就进入循环,
当拷贝的是\0的时候就不进入循环,注意这里是先拷贝再看是否进入
循环,所以\0已经拷贝上了。
但是这样的代码还不够完美,还会有出现bug的可能。
4.改进二
#include<assert>
void my_strcpy(char* dest,const char* src)
{
//断言
assert(src != NULL);
assert(dest != NULL);
while(*dest++ = *src++)
{
;//空语句
}
}
int main()
{
char arr1[20] = "XXXXXXXXXXXXXXXXX";
char arr2[] = "hello bit";
char* p = NULL;
my_strcpy(arr1, p);
printf("%s\n", arr1);
return 0;
}
如果把空指针传过去,对其解引用是很危险的,所以这里我们就要
使用断言assert,看一下具体效果
这样就避免了空指针的危险
const char* src这里加const也是为了减少bug的出现
如果我们在写while语句的时候这样写
//err
while (*src++ = *dest++)
{
;//空语句
}
//ok
while (*dest++ = *src++)
{
;//空语句
}
如果我们写成err的代码的话,编译器会直接报错的
关于const的解释
int main()
{
const int m = 10;
m = 100;
printf("%d\n", m);
return 0;
}
const的作用就是保护源数据
但我们可以通过取地址,再对地址指向的对象进行改变的方法更改m的值
int main()
{
const int m = 10;
int* p = &m;
*p = 100;
printf("%d\n", m);
return 0;
}
这里是绕过const的语法限制
取m的地址,去改变m的值
属于翻窗户的行为
下面是对const放在 * 左边和 * 右边的解释
1.const放在 * 左边,不能改变p指向的对象,但可以改变p本身
int main()
{
const int m = 10;
const int* p = &m;//const int*等价于int const*
int n = 20;
*p = 100;//err
p = &n;//ok
printf("%d\n", m);
return 0;
}
2.const放在 * 右边,可以改变p指向的对象,但不能改变p本身
int main()
{
const int m = 10;
int* const p = &m;
int n = 20;
*p = 100;//ok
p = &n;//err
printf("%d\n", m);
return 0;
}
3. * 两边都加const 都不能改变
const int* const p
5.完美代码
注意到strcpy函数,其函数原型为
char* strcpy(char* destination, const char* source);
但是我们写的模拟函数没有返回,所以是不够完美的
#include<stdio.h>
#include<assert>
//为什么返回char*呢?
//是为了实现链式访问(就是把一个函数的返回值作为另一个函数的参数)
//strcpy函数返回的是目标空间的首元素地址
char* my_strcpy(char* dest,const char* src)
{
//保存起始地址
char* ret = dest;
//断言
assert(src != NULL);
assert(dest != NULL);
while(*dest++ = *src++)
{
;//空语句
}
//return dest;//err
return ret;
}
int main()
{
char arr1[20] = "XXXXXXXXXXXXXXXXX";
char arr2[] = "hello bit";
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
到了这里我们才明白原来写一个几乎没有bug的代码需要考虑这么多
那么怎样才能写出优秀的代码呢?