在以前的学习我们掌握了基础的字符函数类型,知道了一些字符串函数如何使用,但不知道具体函数是如何实现的。本篇文章将系统介绍讲解C语言中的字符串函数。通过简洁高效的代码,为友友提供一个清晰明了的讲解,让我们开始吧!
前提!!在使用字符串函数前都要引用头文件#include
先看看C语言编译库是如何定义strlen函数的。
根据定义我们知道是将目标字符串的首元素地址传给strlen来进行测量。
使用时需要注意以下几点:
- 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包 含 ‘\0’ )。
- 参数指向的字符串必须要以 ‘\0’ 结束。
- 注意函数的返回值为size_t,是无符号的,所以返回值一定大于等于0
现在尝试运用一下strlen函数,代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
char arr[] = "1234567890";
size_t ret = strlen(arr);
printf("%zd\n", ret);
return 0;
}
通过上面的分析我们知道strlen函数的基本逻辑就是找到字符串的首地址然后一直计数直到遇到’\0‘就返回。那么根据这个逻辑我们试试模拟实现strlen函数,代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
//方法1:计数
size_t my_strlen1(const char* arr)
{
assert(arr);//检验arr是否为空指针
int count = 0;
while (*arr != '\0')
{
count++;
arr++;
}
return count;
}
//方法2:指针-指针
size_t my_strlen2(const char* arr)
{
assert(arr);
const char* arr1 = arr;
while (*arr != '\0')
{
arr++;
}
return arr - arr1;
}
//方法3:递归
size_t my_strlen3(const char * str)
{
if(*str == '\0')
return 0;
else
return 1+my_strlen(str+1);
}
int main()
{
char arr[] = "1234567890";
size_t ret1 = my_strlen1(arr);
printf("%zd\n", ret1);
size_t ret2 = my_strlen2(arr);
printf("%zd\n", ret2);
size_t ret3 = my_strlen3(arr);
printf("%zd\n", ret3);
return 0;
}
strcpy函数有复制字符串的作用,将source(源字符串)复制到destination(目标空间)。
使用时需要注意以下几点:
- 源字符串必须以 ‘\0’ 结束。
- 会将源字符串中的 ‘\0’ 拷贝到目标空间。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可更改(不是常量字符串也没有const修饰),否则报错。
现在尝试运用一下strcpy函数,代码如下:
#include
#include
int main()
{
char arr1[20] = "xxxxxxxxxxx";
char arr2[] = "abcdef";
char* ret = strcpy(arr1, arr2);
printf("%s\n", ret);
return 0;
}
同时我们可以看看arr1数组内部的变化:
知道了strcpy函数的逻辑,我们来试试模拟实现,代码如下:
#include
#include
#include
char* my_strcpy(char* str1, const char* str2)
{
assert(str1 && str2);
char* ret = str1;
while (*str1++ = *str2++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "xxxxxxxxxxx";
char arr2[] = "abcdef";
//char* ret = strcpy(arr1, arr2);
char* ret = my_strcpy(arr1, arr2);
printf("%s\n", ret);
return 0;
}
strcat函数功能是追加字符串,即在目标字符串后接上源字符串实现追加。
使用时需要注意以下几点:
- 源字符串必须以 ‘\0’ 结束。
- 会将源字符串中的 ‘\0’ 拷贝到目标空间。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可更改(不是常量字符串也没有const修饰),否则报错。
那么现在尝试运用一下strcpy函数,代码如下:
#include
#include
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "12345678";
char* ret = strcat(arr1, arr2);
printf("%s\n", ret);
return 0;
}
strcat函数是找到目标空间的末尾后开始将源字符串存入空间,同时最后也将’\0‘拷贝。
现在知道了strcat函数的逻辑,我们来试试模拟实现,代码如下:
#include
#include
#include
char* my_strcat(char* arr1,const char* arr2)
{
char* ret = arr1;
assert(arr1 && arr2);
while (*arr1)
{
arr1++;
}
while ((*arr1++ = *arr2++))
{
;
}
return ret;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "12345678";
//char* ret = strcat(arr1, arr2);
char* ret = my_strcat(arr1, arr2);
printf("%s\n", ret);
return 0;
}
strcmp函数意思是str compare,字符串比较。可以看到函数返回类型是整型,它通过 依次比较两字符串元素的ASCII值得出结果。那如何通过整型返回值来反映大小关系呢?
我们可以看看C程序编译库中对返回值的解释:
通过图片我们得知,ptr1是字符串1的地址,ptr2是字符串2的地址,而函数返回值的意思如下:
如果 *ptr1> *ptr2 ,那么就返回大于0的值,str1 > str2。
如果 *ptr1= *ptr2,那么就返回0即可, ’‘’‘’‘’‘ str1 = str2。
如果 *ptr1< *ptr2 ,那么就返回小于0的值,str1 < str2。
基本明白之后我们就可以来试着应用一下了,代码如下:
#include
#include
void my_judge(int ret)//判断结果函数
{
if (ret > 0)
{
printf(">\n");
}
if (ret < 0)
{
printf("<\n");
}
if (ret == 0)
{
printf("=\n");
}
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abce";//与arr1元素有不同,与arr1比应输出‘<’
char arr3[] = "abcde";//与arr1长度不同,其他元素相同,与arr1比应输出‘>’
int ret1 = strcmp(arr1, arr2);
my_judge(ret1);
int ret2 = strcmp(arr1, arr3);
my_judge(ret2);
return 0;
}
结果如下:
我们可以发现,字符串并不是越长值就越大,而是在比较过程中谁先有较大的元素,谁就是较大者 。
进行了一系列实践,现在我们可以试试来模拟实现strcmp函数,代码如下:
#include
#include
#include
void my_judge(int ret)//判断结果函数
{
if (ret > 0)
{
printf(">\n");
}
if (ret < 0)
{
printf("<\n");
}
if (ret == 0)
{
printf("=\n");
}
}
int my_strcmp(const char* ptr1, const char* ptr2)
{
assert(ptr1 && ptr2);
while (*ptr1 == *ptr2)
{
if (*ptr1 == '\0')
{
return 0;
}
ptr1++;
ptr2++;
}
if (*ptr1 > *ptr2)
{
return 1;
}
else
return -1;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abce";//与arr1元素有不同,与arr1比应输出‘<’
char arr3[] = "abcde";//与arr1长度不同,其他元素相同,与arr1比应输出‘>’
//int ret1 = strcmp(arr1, arr2);
//my_judge(ret1);
//int ret2 = strcmp(arr1, arr3);
//my_judge(ret2);
int ret1 = my_strcmp(arr1, arr2);
my_judge(ret1);
int ret2 = my_strcmp(arr1, arr3);
my_judge(ret2);
printf("\n别忘了点赞三连支持欧o(>ω< )o!!!\n");
printf("(深情)\n");
return 0;
}
结果如下:
strncpy函数和strcpy多了一个参数num,具体作用如下:
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
了解明白新内容现在就来简单应用一下!代码如下:
#include
#include
int main()
{
char str1[] = "To be or not to be";
char str2[40];
char str3[40];
strncpy(str2, str1, sizeof(str2));
strncpy(str3, str2, 5);
str3[5] = '\0';
puts(str1);
puts(str2);
puts(str3);
return 0;
}
和strcat函数很像,不过同样多了个num参数,具体作用如下:
函数将源字符串的前 num 个字符复制到目标字符串,外加一个终止空字符’\0’。
如果源字符串的长度小于 num,则只复制终止空字符之前的内容。
了解明白新内容现在就来简单应用一下!代码如下:
#include
#include
int main()
{
char str1[20];
char str2[20];
strcpy(str1, "To be ");
strcpy(str2, "or not to be");
strncat(str1, str2, 6);
puts(str1);
return 0;
}
结果如下:
可以看到只在str1后接了6个元素,然后停止,不论是否遇到’\0’。
该函数从每个字符串的第一个字符开始比较。如果两个字符串的第一个字符相等,则继续比较下面的字符对,直到两个字符串的字符不同,或者比较到一个终止的空字符’\0’,或者比较到两个字符串中匹配的字符个数,以先发生者为准。
通俗来讲可以理解成:在strcmp函数功能的基础上,由以往的从头比到尾变成了可以控制在一定长度范围内进行比较。
都多余了,开始实践!代码如下:
#include
#include
int main()
{
char str[3][5] = { "R2D2" , "C3PO" , "R2A6" };
int n;
puts("查找 R2 ...");
for (n = 0; n < 3; n++)
if (strncmp(str[n], "R2xx", 2) == 0)
{
printf("found %s\n", str[n]);
}
return 0;
}
结果如下:
可以看到,找到的字符串和“R2XX”后两位还是不一样的,但是还是成功找到了R2,成功使用strncmp!!^ ^
返回 字符串str1 中第一次完整出现 字符串str2 的指针,如果 str2 不是 str1 的一部分,即查找不到,则返回空指针NULL。
匹配过程不包括空字符’\0’,但会在此位置时停止。
还是得实操一下才能真正理解,代码如下:
#include
#include
int main()
{
char str[] = "This is a simple string";
char* pch;
pch = strstr(str, "simple");//pch存放查找到对应字符串的首字母地址
if (pch != NULL)
strncpy(pch, "sample", 6);
puts(str);
return 0;
}
结果如下:
sep参数是个字符串,定义了用作分隔符的字符集合。
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
开始冻手!!代码如下:
#include
#include
int main()
{
char arr[] = "[email protected] to be";
char buf[200] = {0};//"[email protected] to be"
strcpy(buf, arr);
char* p = "@.";
char* s = strtok(buf, p);
printf("%s\n", s);
s = strtok(NULL, p);
printf("%s\n", s);
s = strtok(NULL, p);
printf("%s\n", s);
return 0;
}
这个函数有些特别,它所返回的是错误码所对应的错误信息的地址。
那我就会问了,错误码是什么呢?其实很好理解,我们上网打开网页经常会出现问题,例如“404Not found!!”等等,这些都是错误码。通过strerror函数可以把这些错误码对应的具体问题详细输出,就不仅仅只是个数字在屏幕上了。
冻手!冻手!代码如下:
#include
#include
int main()
{
int i = 0;
for (i = 1; i < 10; i++)
{
printf("%d:%s\n", i, strerror(i));
}
return 0;
}
结果如下:
函数memcpy具体功能实现是从source的位置开始向后复制num个字节的数据到destination的内存位置。这个函数在遇到 ‘\0’ 的时候并不会停下来。
注意!! 如果source和destination有任何的重叠,复制的结果都是未定义的。
那就试试呗,代码如下:
#include
#include
void test()
{
char arr1[] = "abcdef";
char arr2[5] = { 0 };
memcpy(arr2, arr1, 3);
printf("%s", arr2);
}
int main()
{
test();
return 0;
}
在这也试试模拟实现memcpy,代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
//模拟实现memcpy
//void* memcpy(void* destination, const void* source, size_t num);
#include
#include
#include
void* my_memcpy(void* dest,const void* str, size_t sz)
{
void* ret = dest;
while (sz--)
{
*(char*)dest = *(char*)str;
djieguoest = (char*)dest + 1;
str = (char*)str + 1;
}
return ret;
}
int main()
{
char arr1[] = "hello world";
char arr2[] = "abc";
my_memcpy(arr1, arr2, 3);
printf("%s\n", arr1);
printf("\n别忘了点赞三连支持欧o(>ω< )o!!!\n");
printf("(深情)\n");
return 0;
}
这个很好理解,它和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
尝试着使用一下,都差不多的了,我就不在这里赘述了,我觉得很彳亍
那memmove是如何实现的呢?代码如下:
//memmove模拟实现
//void * memmove ( void * destination, const void * source, size_t num );
#include
#include
#include
void* my_memmove(void* dest,const void* str, size_t num)
{
assert(dest && str);
void* ret = dest;
if (dest < str)
{
//从前到后
while (num--)
{
*(char*)dest = *(char*)str;
dest = (char*)dest + 1;
str = (char*)str + 1;
}
}
else
//从后到前
{
dest = (char*)dest + num - 1;
str = (char*)str + num - 1;
while (num--)
{
*(char*)dest = *(char*)str;
dest = (char*)dest - 1;
str = (char*)str - 1;
}
}
return ret;
}
int main()
{
char arr[] = "memmove can be very useful......";
void* str = my_memmove(arr + 20, arr + 15, 5);
puts(arr);
return 0;
}
好了以上就是本篇“【C语言】字符串函数分析及模拟实现”博客的全部内容啦,感谢各位的阅读=v=,如有不足之处欢迎在评论区指出哦!!
觉得可以的话别忘了点赞三连支持一下欧!拜托啦这对我真的很重要o(>ω< )o!!!