【c语言:常用字符串函数与内存函数的使用与实现】
文章目录
- 1. strlen函数
- 1.1使用
- 1.2模拟实现
- 2.strcmp函数
- 2.1使用
- 2.2模拟实现
- 3.strncmp函数
- 3.1使用
- 3.2模拟实现
- 4.strcpy函数
- 4.1 使用
- 4.2模拟实现
- 5.strcncpy
- 5.1使用
- 5.2模拟实现
- 6.strcat函数
- 6.1使用
- 6.2模拟实现
- 7.strncat函数
- 7.1使用
- 7.2模拟实现
- 8.strstr函数
- 8.1使用
- 8.2模拟实现
- 9.strtok函数
- 10.strerror函数
- 11.memcpy
- 11.1使用
- 11.2模拟实现
- 12.memmove函数
- 12.1使用
- 12.2模拟实现
- 13.memset函数
- 13.1使用
- 13.2模拟实现
- 14.memcmp函数
- 14.1使用
- 14.2模拟实现
简介:本篇文章是对C语言中常用的字符串函数和内存函数的学习以及模拟实现
文档内容来自:https://legacy.cplusplus.com/
1. strlen函数
1.1使用
- 字符串以 ‘\0’ 作为结束标志,
- strlen函数返回的是在字符串中 ‘\0’ 前⾯出现的字符个数(
不包含 '\0'
)。 - 参数指向的字符串必须要以 ‘\0’ 结束。
- 注意函数的返回值为size_t,是无符号的(
易错
) - 使用需要包含对应的头文件<string.h>
下面这个代码的执行结果是什么呢?
int main()
{
const char* str1 = "abcdef";
const char* str2 = "bbb";
if (strlen(str2) - strlen(str1) > 0)
{
printf("str2>str1\n");
}
else
{
printf("srt1>str2\n");
}
return 0;
}
strlen(str1) = 6,strlen(str2) = 3。3-6小于0,所以输出str>str2对吗?
恭喜你,掉坑里了
两个无符号数运算的结果还是无符号数,-3看成无符号数就是3,3>0所以输出str2>str1。
1.2模拟实现
- 定义新变量的方法
size_t my_strlen(char* str)
{
size_t count = 0;
while (*str)
{
count++;
str++;
}
return count;
}
- 指针-指针
size_t my_strlen(char* str)
{
char* cur = str;
while (*str)
{
str++;
}
return str-cur;
}
- 不定义新变量,递归法
size_t my_strlen(char* str)
{
if (*str == '\0')
{
return 0;
}
else
{
return 1 + my_strlen(str + 1);
}
}
2.strcmp函数
2.1使用
两个字符串进行比较的时候就不能再像整数那样使用 > < = 来比较了,它实际比较的是两个字符串对应字符的ASCLL码值
- 第⼀个字符串大于第⼆个字符串,则返回大于0的数字
- 第⼀个字符串等于第⼆个字符串,则返回0
- 第⼀个字符串小于第⼆个字符串,则返回小于0的数字
2.2模拟实现
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);
while (*str1 == *str2)
{
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
/*if (*str1 > *str2)
{
return 1;
}
else
return -1;*/
}
3.strncmp函数
3.1使用
strncmp函数与strcmp函数的使用十分相似,strncmp函数只是限定了比较几个字符的大小
例如:比较前五个字符的大小
当要比较的长度大于两个串本身的长度时,比较到其中一个串的末尾即可
3.2模拟实现
int my_strncmp(const char* str1, const char* str2, int num)
{
assert(str1 != NULL);
assert(str2 != NULL);
//无字符串可比,直接返回0
if (!num)
{
return 0;
}
//1.两字符串相等
//2.在规定的范围内
//3.字符串未到末尾
while ((*str1 == *str2) && --num && *str1 != '\0')
{
str1++;
str2++;
}
return *str1 - *str2;
}
4.strcpy函数
4.1 使用
- 源字符串必须以 ‘\0’ 结束
- 会将源字符串中的 ‘\0’ 拷贝到目标空间。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可修改。
- 函数返回目标空间的起始地址
4.2模拟实现
写法1:
char* my_strcpy(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
while (*src)
{
*dest = *src;
dest++;
src++;
}
*dest = *src;
return ret;
}
写法2:
char* my_strcpy(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
5.strcncpy
5.1使用
- 将源字符串的前 num 个字符复制到目标字符串。
- 如果在复制 num 个字符之前找到源 C 字符串的末尾(由 null 字符表示),则 destination 将用零填充,直到总共写入 num 个字符。(不足num个,用0填充)
5.2模拟实现
char* my_strncpy(char* dest, const char* src, int num)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
while ((*dest++ = *src++) && --num)
{
;
}
while (--num)
{
*dest = 0;
dest++;
}
return ret;
}
6.strcat函数
6.1使用
- 源字符串必须以 ‘\0’ 结束
- 目标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可修改。
- 函数返回目标空间的起始地址
- 字符串自己给自己追加,如何?(需要使用memmove)
6.2模拟实现
char* my_strcat(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
//找dest的\0
while (*dest)
{
dest++;
}
//开始追加
while (*dest++ = *src++)
{
;
}
return ret;
}
7.strncat函数
7.1使用
- 将源的前 num 个字符附加到目标,外加一个终止 null 字符
- 如果 source 中 C 字符串的长度小于 num,则仅复制 ‘\0’ 之前的内容
7.2模拟实现
char* my_strncat(char* dest, const char* src, int num)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
//找dest的\0
while (*dest)
{
dest++;
}
//开始追加
while (num-- && (*dest++ = *src++))
{
;
}
*dest = 0;
return ret;
}
8.strstr函数
8.1使用
- str1中找str2字符串,返回str2第一次出现位置的地址
- 字符串的比较匹配不包含 \0 字符,以 \0 作为结束标志
8.2模拟实现
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);
char* ptr1 = NULL;
char* ptr2 = NULL;
if (!(*str2))
{
return (char*)str1;
}
while (*str1)
{
ptr1 = (char*)str1;
ptr2 = (char*)str2;
while ((*ptr1 == *ptr2) && *ptr1 && *ptr2)
{
ptr1++;
ptr2++;
}
if (*ptr2 == 0)
{
return (char*)str1;
}
str1++;
}
return NULL;
}
9.strtok函数
- delimiters参数指向⼀个字符串,定义了用作分隔符的字符集合
- 第⼀个参数指定⼀个字符串,它包含了0个或者多个由delimiters字符串中⼀个或者多个分隔符分割的标记。
- strtok函数找到str中的下⼀个标记,并将其⽤ \0 结尾,返回⼀个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷⻉的内容并且可修改。
- strtok函数的
第⼀个参数不为 NULL
,函数将找到str中第⼀个标记,strtok函数将保存它在字符串中的位置。 - strtok函数的
第⼀个参数为 NULL
,函数将在同⼀个字符串中被保存的位置开始
,查找下⼀个标记。 - 如果字符串中不存在更多的标记,则返回 NULL 指针。
是不是有点难理解?
用大白话说就是:
strtok函数是以一个delimiter函数中的字符为分隔依据的函数,第一次调用该函数需要将要分隔的字符串的地址传给他,它会根据分隔依据找第一次在字符串中出现该分隔符的位置,将其用\0替代,并且返回一个指向这个分隔符的指针。下一次调用就只需要传给它空指针和分隔依据,它会从上一个分隔符位置再次开始找,直到找到分隔符。最终找到字符串结尾即可。
10.strerror函数
strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。
- 在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说明的,C语⾔程序启动的时候就会使⽤⼀个全⾯的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0, 表⽰没有错误,
- 当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会讲对应的错误码,存放在errno中,⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是 有对应的错误信息的。
strerror函数就可以将错误对应的错误信息字符串的地址返回。
打印0-10错误码对应的信息:
例如:我们使用fopen函数打开本地某一个文件夹,它就会自动打印处使用该函数产生的错误。
再我们以上所讲的所有字符串函数,你要相对字符串进行操作,是不是必须知道它的类型呀?可不是什么时候我们都能准确的知道的,比如一个结构体类型的数据。当我们不知道的时候,那么该如何操作呢?下面我们将进行讲解:
11.memcpy
11.1使用
- 将 num 字节的值从源指向的位置直接复制到目标指向的内存块
- 源指针和目标指针指向的对象的基础类型与此函数无关;结果是数据的二进制副本
- 该函数不
检查源中的任何终止 null 字符 - 它始终准确复制 num 个字节
11.2模拟实现
void* my_memcpy(void* dest, const void* src, int num)
{
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
12.memmove函数
12.1使用
- 和memcpy的差别就是memmove函数处理的源内存块和⽬标内存块是可以重叠的。
- 如果源空间和⽬标空间出现重叠,就得使⽤memmove函数处理
12.2模拟实现
void* my_memmove(void* dest, const void* src, int num)
{
void* ret = dest;
//从前向后拷
if (dest < src)
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
//从后向前拷
else
{
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
13.memset函数
13.1使用
- memset是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容。
- 将ptr指向的内存的第一个字节设置为指定的值
13.2模拟实现
void* my_memset(void* ptr, int x, int num)
{
void* ret = ptr;
while (num--)
{
*((char*)ptr + num) = x;
}
return ret;
}
14.memcmp函数
14.1使用
- 比较从ptr1和ptr2指针指向的位置开始,向后的num个字节,
- 如果它们都匹配,则返回零,或者返回一个不同于零的值,如果它们不匹配,则表示哪个值更大。
- 请注意,与 strcmp 不同,该函数在找到 null 字符后不会停止比较,
14.2模拟实现
/*
当buf1<buf2时,返回值<0
当buf1=buf2时,返回值=0
当buf1>buf2时,返回值>0
*/
int my_memcmp(const void* buffer1, const void* buffer2, int num)
{
当比较位数不为0时,且每位数据相等时,移动指针
while (--num && *(char*)buffer1 == *(char*)buffer2)
{
buffer1 = (char*)buffer1 + 1;
buffer2 = (char*)buffer2 + 1;
}
return (*(char*)buffer1) - (*(char*)buffer2);
}
目前本人学习和使用到的字符串、内存函数就这些,如有错误,请批评指正!