前言
嗨,我是firdawn,本章将简单介绍,<string.h>中部分库函数的模拟实现,如strncpy,strncat,memcpy,memmove。在本文片末,还讲简单介绍判断机器大小端的函数实现,下面是本章的思维导图,那么,让我们开始吧!
一,模拟实现strncpy
1.1 strncpy的介绍
srtncpy的介绍参考cplusplus:strncpy,如下图是该介绍的机器翻译,有些地方可能翻译不准。从图中我们可以知道,strncpy用于将一个字符串拷贝到另一个字符数组中。
1.strncpy被包含在<string.h>这个头文件中。
2.它的函数声明为:char * strncpy ( char * destination, const char * source, size_t num );
3.其中包含三个参数,destination表示被拷贝的字符要放的目的地,source表示要拷贝到字符串的起始地址,num表示要拷贝几个字符。
4.返回值,返回值的类型为 char*,返回的是destination的值。
1.2 strncpy的使用
具体使用如图1.2-a
这里src数组被放入了4个字符。
1.3 实现strncpy
#include <string.h>
#include <assert.h>
char* my_strncpy(char* dest, const char* src, size_t num)
{
assert(dest && src);
char* p1 = dest;
const char* p2 = src;
//拷贝num个字符
int i = 0;
for (i = 0; i < num; i++)
{
*p1++ = *p2++;
}
*p1 = '\0';
return dest;
}
//模拟实现strncpy
int main()
{
char arr1[20] = "a cute cat";
char arr2[20] = { 0 };
my_strncpy(arr2, arr1, 6);
return 0;
}
二,模拟实现strncat
2.1 strncat的介绍
srtncat的介绍参考cplusplus:strncat,同样的,因为该网站是国外的一个网站,所以有些地方可能翻译不准。如下图,是该介绍的机器翻译,从图中我们可以知道,strncat用于将一个字符串拼接到另一个字符数组的末尾。
1.使用函数所需的头文件:strncat 被包含在<string.h>这个头文件中。
2.函数声明:char * strncat ( char * destination, const char * source, size_t num );
3.参数:destination表示被拼接的字符要放的目的数组,source表示要被拼接到字符串的起始地址,num表示要拼接几个字符。
4.返回值:返回值的类型为 char*,返回的是destination的值。
2.2 strncat的使用
如上图,dest数组中被拼接了5个字符。
2.3 实现strncat
#include <string.h>
#include <assert.h>
char* my_strncat(char* dest, const char* src, size_t num)
{
assert(dest && src);
char* p1 = dest;
const char* p2 = src;
//让p1指向dest数组的'\0'位置
while (*p1)
{
p1++;
}
//拷贝num个字符
int i = 0;
for (i = 0; i < num; i++)
{
*p1++ = *p2++;
}
*p1 = '\0';
return dest;
}
//模拟实现strncat
int main()
{
char arr1[20] = "a cute cat";
char arr2[20] = "I have ";
my_strncat(arr2, arr1, 6);
return 0;
}
三,模拟实现memcpy
3.1 memcpy的介绍
memcpy的介绍参考cplusplus:memcpy,如下图,是该介绍的机器翻译,从图中我们可以知道,memcpy用于拷贝内存块的数据,拷贝大小单位是字节,不过,对于重叠内存块的拷贝,标准是未定义的。
1.使用函数所需的头文件:memcpy 被包含在<string.h>这个头文件中。
2.函数声明:void * memcpy ( void * destination, const void * source, size_t num );
3.参数:destination表示被拷贝的数据要放的目的数组,source表示要被拷贝的数据的起始地址,num表示要拷贝几个字节。
4.返回值:返回值的类型为 void*,返回的是destination的值。
3.2 memcpy的使用
如图,我们第一次将src数组中的数据拷贝到了dest数组中,第二次将src1数组中的数据拷贝到了dest1中。
3.3 实现memcpy
#include <assert.h>
void* memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
char* p1 = (char*)dest;
char* p2 = (char*)src;
int i = 0;
for (i = 0; i < num; i++)
{
*p1++ = *p2++;
}
return dest;
}
//模拟实现memcpy
int main()
{
char arr1[20] = "beautiful girl";
char arr2[20] = { 0 };
memcpy(arr2, arr1, sizeof(arr1));
return 0;
}
四,模拟实现memmove
4.1 memmove的介绍
memmove的介绍参考cplusplus:memmove,如下图,是该介绍的机器翻译,从图中我们可以知道,memmove用于拷贝内存块的数据,拷贝大小单位是字节,不过,它支持重叠内存块的拷贝,这在标准中是明确规定了的。
4.2 memmove的使用
在上图中,我们将src[ 2 ]的数据拷贝到了src后面,这里拷贝到内存块重叠了
4.3 实现memmove
#include <string.h>
#include <assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest && src);
const char* cur = (char*)src;
char* p1 = NULL;
if (dest > src)
{
p1 = (char*)dest + num - 1;
for (cur = (char*)src + num - 1; cur >= (char*)src; cur--)
{
*p1-- = *cur;
}
}
else
{
p1 = (char*)dest;
for (cur = (char*)src; cur <= (char*)src + num - 1; cur++)
{
*p1++ = *cur;
}
}
return dest;
}
//模拟实现memmove
int main()
{
char arr1[30] = "a beautiful girl";
my_memmove(arr1 + 2, arr1, sizeof(arr1));
return 0;
}
五,机器大小端的判断
5.1 简单介绍大小端
大小端(Endian)是计算机数据存储的一种方式。在计算机中,数据存储的最小单位是字节(byte),每个字节由8个二进制位组成。在一个多字节数据(如整数、浮点数等)在内存中存储时,需要决定字节的排列顺序。
大端存储(Big Endian):字节的高位保存在低地址,字节的低位保存在高地址。即最高有效字节(Most Significant Byte)存储在最低内存地址,最低有效字节(Least Significant Byte)存储在最高内存地址。
小端存储(Little Endian):字节的高位保存在高地址,字节的低位保存在低地址。即最低有效字节(Least Significant Byte)存储在最低内存地址,最高有效字节(Most Significant Byte)存储在最高内存地址。
不同的计算机架构和处理器可能采用不同的存储方式。例如,x86架构的计算机通常使用小端存储,而PowerPC架构的计算机通常使用大端存储。为了在不同架构的计算机之间进行数据交换,通常需要进行字节序转换操作。
5.2 大小端的函数实现
int CheckSystem()
{
int num = 1;
return *((char*)&num);
}
//编写判断大小端程序
int main()
{
int ret = CheckSystem();//小段返回1,大段返回0
return 0;
}