字符串函数的模拟实现
文章目录
- 前言
- 函数介绍
- strlen 函数
- strcpy 函数
- strcat 函数
- strcmp函数
- strncpy
- strncat
- strncmp
- strstr
- strtok
- strerror
- memcpy 函数
- memmove 函数
- memcmp 函数
前言
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串或者字符数组中。
字符串常量适用于那些对它不做修改的字符串函数。
函数介绍
strlen 函数
strlen函数是一个求字符串长度的函数,它遇到字符串末尾的’\0’结束计数,cplusplus网站上对这个函数的解释是这样的:
注意事项:
参数是一个char类型的指针,传入其他类型的变量会导致位置错误。
注意:
- 函数的返回值为size_t(无符号整型)。
- 参数指向的字符串必须以 ‘\0’ 结尾。
模拟实现strlen函数
#include <stdio.h>
// 计数器
size_t my_strlen1(const char* str )
{
size_t count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
// 递归方法
size_t my_strlen2(const char* str)
{
if (*str != '\0')
{
return 1 + my_strlen2(str + 1);
}
else
{
return 0;
}
}
int main()
{
char arr[10] = "abcdef";
size_t ret1 = my_strlen1(arr);
size_t ret2 = my_strlen2(arr);
printf("函数一:%d\n",ret1);
printf("函数二:%d\n",ret2);
return 0;
}
运行结果:
strcpy 函数
strcpy的作用是将一个字符数组中的内容拷贝到另一个字符串数组中,返回值是目标空间的起始地址。
注意事项:
源字符串必须以 ‘\0’ 结束。
目标空间需要足够大,可以容纳源字符串的内容。
目标空间必须可修改。
模拟实现
char* my_strcpy(char* dest, const char* src)
{
char* temp = dest;
//会把/0拷贝过去,
while (*dest++ = *src++)
{
;
}
return temp;
}
int main()
{
char arr[10] = { "abcdef" };
char arr1[10] = { 0 };
char* ret = my_strcpy(arr1, arr);
printf("%s\n", ret);
return 0;
}
strcat 函数
strcat 函数的作用是把一个字符串的内容追加到另一个字符串的后面,覆盖掉原来字符串里的 \0。从 \0 开始追加。
对于strcat函数的解释是这样的:
注意事项
源字符串末尾用**\0**结尾。
目标空间足够大,能容纳源字符串内容。
目标空间必须可修改。
字符串自己给自己追加,会发生指针越界访问。
模拟实现
strcat 的模拟实现
char* my_strcat(char* destination, const char* source)
{
char* temp = destination;
//由于是从目标字符串的\0字符处开始追加的,那么我们可以
//找到\0 去进行字符串的拷贝。
while (*destination != '\0')
{
destination++;
}
while (*destination++ = *source++)
{
;
}
//返回目标空间的起始地址。
return temp;
}
int main()
{
char arr1[30] = "hello ";
char arr2[10] = "world";
char* ret = my_strcat(arr1, arr2);
printf("%s\n", ret);
return 0;
}
strcmp函数
它的作用是比较两个字符串的大小,小于返回小于零的数字,大于返回大于零的数字。
对于strcmp函数的解释是这样的:
模拟实现
int my_strcmp(const char* str1, const char* str2)
{
//相等返回0
//小于返回-1
//大于返回1
while (*str1 == *str2)
{
//如果str1指向了末尾,说明是相等的
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
if (*str1 - *str2 < 0)
{
return -1;
}
else
{
return 1;
}
}
int main()
{
char arr1[10] = "abc";
char arr2[10] = "abcd";
int ret = my_strcmp(arr1, arr2);
printf("%d\n", ret);
return 0;
}
以上的函数都是字符串长度不受控制的函数,这样就会出现一些安全问题。那么以下就是字符串长度受限制的函数。strcat函数是不适合自己给自己追加的而strncat是可以自己给自己追加的。
下面我们来练习一些长度受限制的字符串函数的使用:
strncpy
void test1()
{
char arr[10] = "abcdef";
char arr1[10] = { 0 };
char* ret = strncpy(arr1, arr, 3);
printf("%s\n", ret);
}
strncat
//strncat 的使用
void test2()
{
char arr[20] = "abcdef";
char* ret = strncat(arr, arr, 6);
printf("%s\n", ret);
}
strncmp
//strncmp 的使用
void test3()
{
char arr[10] = "abcdef";
char arr1[10] = "abc";
int ret = strncmp(arr, arr1, 3);
printf("%d\n", ret);
}
strstr
strstr函数是在一个字符串里找子串。返回子串的开始位置。
它的内容是这样的:
模拟实现
//strstr 判断是否存在子字符串
char* my_strstr(const char* str1, const char* str2)
{
char* cp = str1;
char* s1, *s2;
while (*cp) //注意这里的cp是一个非常重要的地方
{
s1 = cp;
s2 = str2;
while (*s1 && *s2 && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2=='\0')
{
return cp;
}
cp++;
}
return NULL;
}
int main()
{
char arr[10] = "abcdef";
char arr1[10] = "bcd";
char* ret = my_strstr(arr, arr1);
printf("%s\n", ret);
return 0;
}
strtok
strtok函数是按特殊符号分割字符串的。
内容是这样的:
注意事项
- sep参数十个字符串,定义了用作分隔符的字符集合
- 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
- strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。) - strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串
中的位置。 - strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
记。 - 如果字符串中不存在更多的标记,则返回 NULL 指针。
strerror
strerror函数是返回错误码所对应的错误信息。C语言库函数在调用失败的时候,会把一个错误码放在一个叫errno的变量中,当我们想要知道调用库函数发生了什么错误的时候我们可以将错误码翻译成错误信息。
使用
//strerror 的使用
#include<errno.h>
int main()
{
FILE* pf = fopen("text.txt", "r");
printf("文件打开错误!%s\n", strerror(errno));
fclose(pf);
pf = NULL;
return 0;
}
memcpy 函数
是用来拷贝内存空间的。
解释:
注意事项
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
- 这个函数在遇到 ** ‘\0’ ** 的时候并不会停下来。
- 如果source合destination有任何重叠,复制的结果都是未定义的。
模拟实现
void* my_memcpy(void* dest, const void* src,size_t num)
{
void* temp = dest;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return temp;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr1[10] = { 0 };
my_memcpy(arr1, arr, 40);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
}
memmove 函数
拷贝内存的函数
主要内容:
注意事项
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
模拟实现
void* my_memmove(void* dest, const void* src, size_t 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;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr + 2, arr, 12);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
}
memcmp 函数
使用
/* memcmp example */
#include <stdio.h>
#include <string.h>
int main ()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n=memcmp ( buffer1, buffer2, sizeof(buffer1) );
if (n>0)
printf ("'%s' is greater than '%s'.\n",buffer1,buffer2);
else if (n<0)
printf ("'%s' is less than '%s'.\n",buffer1,buffer2);
else
printf ("'%s' is the same as '%s'.\n",buffer1,buffer2);
return 0;
}