目录
前言
之前为大家分享了函数相关的知识点,当时讲述的函数的知识点大多都是自定义函数,而今天为大家分享的就是C语言库中的一些函数,何为库函数,库函数就是C语言自身封装的一些函数,我们可以直接通过引入头文件的形式对这些函数进行使用,就比如我们在写C语言程序之前,好多小伙伴都直接引入了#include<stdio.h>,很多人不知道为什么,其实这便是引入了库函数,因为我们在写程序时,会使用到scanf和printf函数,这两个函数就是C语言中的库函数,所以我们要对其引入头文件。这期,主要为大家讲述的就是C语言中比较重要的一些库函数,以及如何通过自己的方法去实现这些库函数。
字符串函数
strlen
这个函数想必大家都不陌生吧,这个函数我们之前是讲到过的,先来看一段代码:
#include<stdio.h>
int main(){
char ch1[20] = "123456789";
int len = strlen(ch1);
printf("%d\n",len);
return 0;
}
我们知道strlen是求字符串长度的一个库函数,但是我们通过运行结果发现,ch1这个字符串的长度是9,我们知道一个字符串的末尾是有一个'\0'作为字符串结束的标志的,'\0'本身也是一个字符,如此,打印的结果应该是10,但是我们打印的结果确是9,这就证明,strlen这个函数在求字符串的长度时,只求'\0'之前的所有字符串的长度,'\0'是不用记作长度的。
strlen的模拟实现
#include<stdio.h>
int my_strlen(const char* dest) {
int count = 0;
while (*dest++) {
count++;
}
return count;
}
int main(){
char ch1[20] = "123456789";
int len = strlen(ch1);
printf("%d\n",len);
int len2 = my_strlen(ch1);
printf("%d", len2);
return 0;
}
不难发现,运行结果是相同的。上述的模拟实现只是一种方式,还有其它的方法,递归的方法实现在之前的递归那期有讲到,感兴趣的小伙伴可以自行查看。
strcpy
这玩意儿是干嘛的,先说结论,它是字符串拷贝函数,就相当于将一个字符串的内容复制粘贴到了另一个字符串。来吧,展示:
#include<stdio.h>
int main()
{
char ch1[20] = "zhangsan";
char ch2[20] = "lisi";
printf("%s\n",ch1);
strcpy(ch1, ch2);
printf("%s\n",ch1);
return 0;
}
运行结果如下:
不难发现,我们已经将ch2的值拷贝到了ch1
注意:strcpy进行拷贝时,依旧是将'\0'之前的字符串进行拷贝。在进行拷贝时,目标字符串的空间应该足够大,起码得等于源字符串。
strcpy的模拟实现
直接上代码:
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char ch1[10] = "zhangsan";
char ch2[10] = "wangmazi";
printf("%s\n",ch1);
my_strcpy(ch1,ch2);
printf("%s\n",ch1);
return 0;
}
通过运行结果不难发现,我们模拟实现的函数也实现了字符串的拷贝。
strcat
这个函数是用来做字符串追加的,字符串追加是什么意思呢?很简单,就是在一个字符串的后面追加一些字符串。直接上代码:
int main()
{
char ch1[10] = "xiongda";
char ch2[10] = "xionger";
printf("%s\n", ch1);
strcat(ch1,ch2);
printf("%s\n",ch1);
return 0;
}
运行结果如下:
通过运行结果不难发现strcat的用法。
注意:strcat的追加时,源字符串必须以'\0'结束
strcat的模拟实现
直接上代码:
char* my_strcat(char* dest,const char* src)
{
char* ret = dest;
while (*dest)
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char ch1[10] = "zhangsan";
char ch2[20] = "lisi";
printf("%s\n",ch1);
my_strcat(ch1, ch2);
printf("%s\n",ch1);
return 0;
}
我们的自定义函数也实现了strcat的模拟。
strcmp
用于比较字符串的内容,注意:与字符串的长度无关,只与字符所对应的asc码的大小有关。
直接上代码:
int main()
{
char ch1[20] = "aaaaaaaaaaaa";
char ch2[20] = "bbb";
int b = strcmp(ch1, ch2);
if (b < 0)
{
printf("ch1 < ch2");
}
else if (b == 0)
{
printf("ch1 == ch2");
}
else
{
printf("ch1 > ch2");
}
return 0;
}
大家先猜测一下,这两个字符串,哪个字符串的长度比大一点,大部分小伙伴第一次一定会认为是第一个ch1较大,但是事实是这样吗?我们直接看运行结果;
运行结果进一步验证了我们的猜想是错误的,这里我们需要注意:
1.strcmp函数是内容比较函数,比较的是字符串的内容的大小,并非是字符串的长度。
2.strcmp函数的返回值是一个整型,返回的数有三种类型:>0,=0,<0,每一种分别对应了不同的大小关系。
3.strcmp的函数的比较是从字符串第一个不想同的字符开始比较的,比如上述的ch1和ch2,因为它们的字符都不相同,所以是从第一个字符开始进行比较的,因为a的asc码是小于b的asc码的,所以会返回一个小于零的数,所以ch1<ch2
strcmp的模拟实现
代码如下:
int my_strcmp(const char* s1, const char* s2)
{
assert(s1 && s2);
while (*s1 == *s2)
{
if (*s1 == '\0')
return 0;
s1++;
s2++;
}
return *s1 - *s2;
}
以上四个便是我们常见的字符串函数,但是上述函数有一个缺点,就是不管字符串有多长都会拿去拷贝,连接和比较,没有空间的限制,这样就会导致内存溢出的情况,因此我们又引入了以下的函数;strncpy,strncat,strncmp这些函数就保证了内存不会溢出,因为它们规定了字符的个数。
这里只给出一个实例,其它的都是类似的:
比较前四个字符:
int main()
{
char arr1[] = "abcde";
char arr2[] = "abcft";
int ret = strncmp(arr1, arr2, 4);
printf("%d\n", ret);
return 0;
}
内存函数
我们为什么要引入内存函数呢?比如上面的字符串拷贝函数,它只能在字符串之间进行拷贝,如果我们要实现整型数组的拷贝,strcpy肯定是行不通的,所以在此基础上我们引入了内存函数,我们通过内存函数,可以实现其它类型数组的拷贝。
memcpy
与strcpy功能大致类似,内存拷贝函数,可以拷贝任何类型的数据,是以字节为单位进行拷贝的。
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
int i = 0;
for (i = 0; i < 20; i++) {
printf("%d ", arr2[i]);
}
printf("\n");
memcpy(arr2, arr1, 40);
for (i = 0; i < 20; i++) {
printf("%d ",arr2[i]);
}
printf("\n");
return 0;
}
memcpy的模拟实现
void* my_memcpy(void* dest, const void* src, size_t count)
{
void* ret = dest;
assert(dest && src);
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
通过运行结果不难发现,实现了整型的拷贝。
memmove
memmove也可以实现内存拷贝,与memcpy的区别就是可以实现重叠的拷贝,比如说我们要把一个整型数组的第1和第2个元素拷贝到第2个和第3个元素的位置上去,此时memcpy是无法实现这个功能的,但是memmove是可以实现这些功能的。
比如:
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
int i = 0;
for (i = 0; i < 10; i++) {
printf("%d ", arr1[i]);
}
printf("\n");
memmove(arr1+1, arr1, 8);
for (i = 0; i < 10; i++) {
printf("%d ", arr1[i]);
}
printf("\n");
return 0;
}
memcmp
内存比较,与字符串比较,只不过比较的是某个字节的内容:
int main()
{
int arr1[] = { 1,2,3,4,5 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ...
int arr2[] = { 1,2,3,6,6 };//01 00 00 00 02 00 00 00 03 00 00 00 06 00 00 00 ...
int ret = memcmp(arr1, arr2, 13);
printf("%d\n", ret);
return 0;
}
上述代码比较的是第13个字节的内容,4<6,所以返回值应该是一个负数。
结果确实返回了一个负数。
memset
memset的作用是将前所少个字节的内容设置为多少。
int main() {
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", arr1[4]);
memset(arr1,5,20);
printf("%d\n",arr1[4]);
}
上述代码就是将数组的前20个字节全部设置为5
进行调试,截图如下:
我们发现,前20个字节确实被改成了5
总结
以上便是这期的所有内容,当然还有其它的字符串函数和内存函数,这期只是讲到了一些比较重要的函数,我们要知道strcpy和memcpy的区别,strcpy是实现字符串拷贝的,而memcpy可以实现各种类型数据的拷贝,要知道memcpy和memmove的区别,memcpy通常用于不重重叠的拷贝,而memmove通常用于重叠的拷贝,但是memmove也可以用于不重叠的拷贝,也就是说,memmove可以实现memcpy实现的所以功能,一般情况下,只要遇到了内存拷贝的问题,无脑使用memmove就行。
本期内容到此结束^_^