文章目录
1.前言
今天我们来了解一些常用的字符串库函数和内存函数
了解这些有什么用呢?
肯定是百益而无一害😎,下面我们就看看他有多么的好用。
https://legacy.cplusplus.com/reference/cstdio/printf/大家有什么函数想要查可以在这上面查
2.字符串库函数
1.strlen
size_t strlen ( const char * str );
这个函数的功能是读取字符串的长度
- 它以’\0’为结束标志,返回’\0’前面字符个数,但是=='\0’不包括在内==
- strlen函数返回值为无符号整型
- strlen函数头文件==<string.h>==
下面看看他是如何用的
#include<stdio.h>
#include<stdio.h>
#include<string.h>
int main()
{
char* ch = "hello world!";
printf("%d\n", strlen(ch));
return 0;
}
简简单单三行代码就可以搞定,如果没有这样的库函数,我们又要去费劲的写一个函数来实现,这样不就很麻烦。
所以说如果你会用库函数,那么写代码对你来说就会简单很多。
所以没事可以多看看C语言的库函数。一定要搞懂后再用,不然会出错
那么这个函数是如何实现的呢?
下面我们看看的是如何做到的,让我们仿照strlen写一个my_strlen函数来实现strlen函数的功能
strlen函数有一个参数,和一个返回值,
参数是:一个内容不可修改指针(在该函数中内容不可以修改)
返回值:是个无符号整型
#include<stdio.h>
#include<stdio.h>
size_t my_strlen(char* ch)
{
int count = 0;
while (*ch) //如果遇到'\0'while循环停止
{
count++;
ch++;
}
return count;
}
int main()
{
char* ch = "hello world!";
printf("%d\n",my_strlen(ch));
return 0;
}
2.strcpy
char * strcpy ( char * destination, const char * source );
这个函数功能是将一个字符串(参数source原字符串)拷贝到另一个字符串(参数destination目标字符串)中
- 以原字符串中的’\0’为结束标志
- 同时会将原字符串中的==‘\0’==拷贝到目标字符串中
- 目标字符串必须足够大,大过原字符串,这样才可以放下
- 目标空间是可变的
例如:char * p = “ajdla”;
这是不能作为目标字符串的,以为"ajdla"是常量字符串,不可以修改
所以p不能作为目标字符串
说那么多了,看看他是怎么用的就懂了 —实践是理解最快的方法
#include<stdio.h>
#include<string.h>
int main()
{
char ch1[20] = { 0 };
printf("原来:%s\n", ch1);
char* ch2 = "hello world!";
strcpy(ch1, ch2);
printf("拷贝后:%s\n", ch1);
return 0;
}
相信看到这里,你们也就懂的了这个函数的用途
那它又是如何实现的呢?
strcpy函数有两个参数一个返回值
两个参数:一个是内容可修改的字符指针,一个是内容不可修改的字符指针 (在该函数中内容不可以修改)
返回值:字符指针
#include<stdio.h>
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* ch1, const char* ch2)
{
assert(ch1 && ch2); //判断ch1和ch2是否为空指针
char* ret = ch1;
while (*ch1++ = *ch2++)
{
;
}
return ret;
}
int main()
{
char ch1[20] = { 0 };
printf("原来:%s\n", ch1);
char* ch2 = "hello world!";
my_strcpy(ch1, ch2);
printf("拷贝后:%s\n", ch1);
return 0;
}
为什么这里的返回值是==char*==呢?
像我这样的小白就认为void当返回值就可以,为什么要用==cahr*==呢,这不是多此一举。
这样写肯定是有好处的
strcpy()可以直接作为printf()的参数进行显示
如:printf(“%s\n”,strcpy(ch1,ch2));
而如果定义成void类型便不能进行函数的链式访问了。
3.strcat
char * strcat ( char * destination, const char * source );
这个函数的作用是将source原字符串追加到destination目标字符串后面
- 以原字符串中的’\0’结束标志
- 将原字符串中的’\0’也拷贝到目标空间中
- 目标空间足够大,能容下两个字符串之和
- 目标空间可改变----和上面strcpy一样的原因
下面看看如何使用
#include<stdio.h>
#include<string.h>
int main()
{
char ch1[20] = "hello ";
printf("原来:%s\n", ch1);
char* ch2 = "world!";
strcat(ch1, ch2);
printf("拷贝后:%s\n", ch1);
return 0;
}
同样的问题,这个函数是如何实现呢?
strcat()函数有两个参数和一个返回值
参数:一个是内容可修改的字符指针,一个是内容不可修改的字符指针 (在该函数中内容不可以修改)
返回值:字符指针
#include<stdio.h>
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* ch1, char* ch2)
{
assert(ch1 && ch2); // 判断两个字符串是否为空
char* ret = ch1;
while (*ch1 != '\0') //找到目标字符串的'\0'
{
ch1++;
}
while (*ch1++ = *ch2++) // 从'\0'开始将原字符串追加上去,直到'\0'
{
;
}
return ret;
}
int main()
{
char ch1[20] = "hello ";
printf("原来:%s\n", ch1);
char* ch2 = "world!";
my_strcat(ch1, ch2);
printf("拷贝后:%s\n", ch1);
return 0;
}
有一个问题,可以自己追加自己吗?
int main()
int main()
{
char arr[30] ="abcdef";
strcat(arr, arr + 2);
printf("%s", arr);
return 0;
}
正常情况下追加完后,输出:abcdefcdef
结果是这样吗? ------下面我们看看
为什和我们想的不一样呢?
4.strcmp
int strcmp ( const char * str1, const char * str2 );
这个函数的作用是比较两个字符串是否相等
- 如果两个字符串相等返回0
- 如果第一个字符串大于第二个字符串返回>0的数
- 如果第一个字符串小于第二个字符串返回<0的数
如何判断两个字符串谁大谁小呢?
通过ASIIC码进行判断
例如:char* ch1 = “abcdef”;
cahr* ch2 = “ac”;
一个一个字符比较,第一个字符相等则比较后面一个字符,第二个字符c的ASIIC码值大于b的则ch2>ch1
下面看看这个函数如何使用
#include<stdio.h>
#include<string.h>
int main()
{
char ch1[20] = "hello ";
char* ch2 = "hello ";
int ret = strcmp(ch1, ch2);
if (ret == 0)
printf("=\n");
else if (ret > 0)
printf(">\n");
else
printf("<\n");
return 0;
}
这个函数又是如何实现的呢?
strcmp()函数有两个参数一个返回值
参数:两内容不可修改的字符指针
返回值:整型
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* ch1, const char* ch2)
{
assert(ch1 && ch2);
int ret = 0;
while ( !(ret = *(unsigned char*)ch1 - *(unsigned char*)ch2) && *ch2)
{
ch1++;
ch2++;
}
return *ch1 - *ch2;
}
int main()
{
char ch1[20] = "hello ";
char* ch2 = "hello ";
int ret = my_strcmp(ch1, ch2);
if (ret == 0)
printf("=\n");
else if (ret > 0)
printf(">\n");
else
printf("<\n");
return 0;
}
5.strstr
char * strstr (const char * str1, const char * str2 );
这个函数在字符串一中找是否含有字符串二,如果有返回其首地址,如果没有返回空指针。
说的多不如实践,我们看看如何用
#include<stdio.h>
#include<stdio.h>
#include<string.h>
int main()
{
char* ch1 = "abcdef";
char* ch2 = "cd";
char* ret = strstr(ch1, ch2);
if (ret == NULL)
{
printf("没有找到\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
如果有多组相同的字符,则返回第一组的地址。
这个函数如何实现?
strstr()函数有两个参数和一个返回值
参数:两个内容不可修改的字符指针
返回值:字符指针
char* my_strstr(const char* ch1, const char* ch2)
#include<stdio.h>
char* my_strstr(const char* ch1, const char* ch2)
{
char* cp = (char*)ch1;
char* s1, * s2;
if (!*ch2) //如果ch2为空,则直接返回ch1的内容
return((char*)ch1);
while (*cp)
{
s1 = cp;
s2 = (char*)ch2;
while (*s1 && *s2 && !(*s1 - *s2))
s1++, s2++;
if (!*s2)
return(cp);
cp++;
}
return(NULL);
}
int main()
{
char* ch1 = "abcdef";
char* ch2 = "cd";
char* ret = my_strstr(ch1, ch2);
if (ret == NULL)
{
printf("没有找到\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
这种算法比较暴力,时间复杂度比较高。
有一种KMP算法,感兴趣可以去了解一下。我会在下一篇文章中写这个。
6. strtok
char * strtok ( char * str, const char * delimiters );
这个函数的作用是分割字符串一,分隔符是字符串二中的内容
- delimiters参数是个字符串,定义了分隔符的字符集合
- str参数是个字符串,其中有0个或多个delimiters中的字符
- strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。
注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修 改。
- strtok函数的第一个参数不为 NULL ,函数将找到strs中第一个标记,strtok函数将保存它在字符串中的位置。
- strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标 记。
- 如果字符串中不存在更多的标记,则返回 NULL 指针
说了这么多,看看如何用吧。
#include<stdio.h>
#include<stdio.h>
#include<string.h>
int main()
{
char* ch1 = "123456789@qq.com";
const char* ch2 = "@.";
char p[30];
strcpy(p, ch1);
char* str = NULL;
for (str = strtok(p, ch2);str != NULL;str = strtok(NULL, ch2))
{
printf("%s\n", str);
}
return 0;
}
strtok第一次调用第一个参数要传目标字符串地址,往后再次调用第一个参数要传NULL指针
还有strtok会改变第一个参数的内容
7.strncpy
char * strncpy ( char * destination, const char * source, size_t num );
这个函数和strcpy函数很像,只是多了一个参数,第三个参数是个无符号整型
这个函数可以决定考入目标字符串的字符个数,而不会将source中的所以内容全部拷贝在目标字符串中。
直接上代码看看。
#include<stdio.h>
#include<stdio.h>
#include<string.h>
int main()
{
char ch1[20] = "abcdefg";
char* ch2 = "hello";
strncpy(ch1, ch2,3);
printf("%s", ch1);
return 0;
}
8.strncat
char * strncat ( char * destination, const char * source, size_t num );
这个函数同样和strcat函数很像,只不过多了一个参数,去决定追加多少个字符。
同时它可以让数组自己追加自己,不会像strcat那样无线追加。他自己在追加结束后自己补’\0’。
看看他如何用吧
#include<stdio.h>
#include<stdio.h>
#include<string.h>
int main()
{
char arr[30] ="abcdef";
strncat(arr, arr + 2,4);
printf("%s", arr);
return 0;
}
9.strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
和前面两个一样多了个n所以它和strcmp函数类似,只是多一个参数,用来决定比较多少个字符。
看看如何用吧
#include<stdio.h>
#include<stdio.h>
#include<string.h>
int main()
{
char* ch1 = "abcdef";
char* ch2 = "abcfrgt";
int ret = strncmp(ch1, ch2, 3);
if (ret > 0)
printf(">\n");
else if (ret == 0)
printf("=\n");
else
printf("<\n");
return 0;
}
从这里可以看出,它只进行前三个字符的比较。
10.strerror
char * strerror ( int errnum );
这个函数作用:返回错误码,所对应的错误信息。
#include<stdio.h>
#include<stdio.h>
#include<string.h>
int main()
{
printf("%s\n", strerror(0));
printf("%s\n", strerror(1));
printf("%s\n", strerror(2));
printf("%s\n", strerror(3));
printf("%s\n", strerror(4));
printf("%s\n", strerror(5));
printf("%s\n", strerror(6));
return 0;
}
它会将一些我们看不懂的错误码转换成文字。
比如我们上网有时候出现404 ------指所请求的页面不存在、已被删除或无法访问。
3.内存函数
1.memcpy
void * memcpy ( void * destination, const void * source, size_t num );
其实这个函数和strncpy函数几乎一样,只不过它可以拷贝任意类型,而strncpy只针对字符串。
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
- 这个函数在遇到 ‘\0’ 的时候并不会停下来。
- 如果source和destination有任何的重叠,复制的结果都是未定义的。(不能自己拷贝自己)
看看如何用吧
#include<stdio.h>
#include<stdio.h>
#include<memory.h>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[5] = { 10,9,8,7,6 };
memcpy(arr1, arr2, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
下面看看他是如何实现的
#include<stdio.h>
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dst, const void* src, size_t num)
{
void* ret = dst;
assert(dst&& src);
while (num--)
{
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[5] = { 10,9,8,7,6 };
my_memcpy(arr1, arr2, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
2.memmove
void * memmove ( void * destination, const void * source, size_t num );
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理。(可以自己拷贝自己)
看看它如何使用
#include<stdio.h>
#include<stdio.h>
#include<memory.h>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1, arr1 + 2, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
看看这个函数如何实现
#include<memory.h>
#include<stdio.h>
#include<assert.h>
void* memmove(void* dst, const void* src, size_t num)
{
assert(dst && src);
void* ret = dst;
if (dst <= src || (char*)dst >= ((char*)src + num))
{
while (num--)
{
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
}
else
{
dst = (char*)dst +num - 1;
src = (char*)src + num - 1;
while (num--)
{
*(char*)dst = *(char*)src;
dst = (char*)dst - 1;
src = (char*)src - 1;
}
}
return(ret);
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1, arr1 + 2, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
3.memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
memcmp函数和strncmp函数基本相同,但是它可以比较任意类型
-
比较从ptr1和ptr2指针开始的num个字节
-
返回值:
返回值 比较结果 >0 ptr1>ptr2 =0 ptr1=ptr2 <0 ptr1<ptr2
#include<stdio.h>
#include<memory.h>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[6] = { 1,2,3,4,6,7};
int ret = memcmp(arr1, arr2, 20);
if (ret > 0)
printf(">\n");
else if (ret == 0)
printf("=\n");
else
printf("<\n");
return 0;
}
4.结束语
今天就写到这里了,库函数还有很多,希望大家没事可以去了解,它会使我们写代码变得轻松😄
有志者,事竟成。
在学习c语言的过程中,会有许多困难,希望大家可以克服,好好学,终究会有回报,终究会学到东西的。