一、前言
二、实现部分库函数
(1)strlen
(2)strcpy
(3)strcmp
(4)strcat
(5)strstr
(6)memcpy
(7)memmove
一、前言
库函数一般是指编译器提供的可在c源程序中调用的函数。可分为两类,一类是c语言标准规定的库函数,一类是编译器特定的库函数。
由于版权原因,库函数的源代码一般是不可见的,但在头文件中你可以看到它对外的接口库函数简介。
C语言的语句十分简单,如果要使用C语言的语句直接计算sin或cos函数,就需要编写颇为复杂的程序。因为C语言的语句中没有提供直接计算sin或cos函数的语句。又如为了显示一段文字,我们在C语言中也找不到显示语句,只能使用库函数printf。
C语言的库函数并不是C语言本身的一部分,它是由编译程序根据一般用户的需要编制并提供用户使用的一组程序。C的库函数极大地方便了用户,同时也补充了C语言本身的不足。事实上,在编写C语言程序时,应当尽可能多地使用库函数,这样既可以提高程序的运行效率,又可以提高编程的质量。
这里调用的是静态库。
二、实现库函数
注:
这里传过去的是地址,为了以防万一,害怕传过去的是空地址,这里对每个指针进行断言。
1.strlen
(1)从库函数中可以了解到strlen函数是获取字符串的长度的一种方式。它的作用方法是读取字符串,直到读取到‘\0’,才会停止,如果不输入‘\0’或不输入字符串,直接输入几个不含‘\0’的字符,其将会往后继续读取字符,直到读取到‘\0’为止,所以可能会出现错误。
(2)这里实现是将字符串的地址传过去,并用const修饰(传过去的字符串的值不能修改),分别用两个指针指向字符串的地址,一个用于记录初始地址;一个往后读取,直到读取到‘\0’,最后返回往后读取的指针的地址减去初始地址的值。
size_t my_strlen(const char* str)
{
assert(str);
const char* start = str;
const char* end = str;
while (*end != '\0')
{
end++;
}
return end - start;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
2.strcpy
(1)从库函数的可以了解到strcpy是将一个字符串的值拷贝到另一个字符串的一种方式,中间要确保另一个字符串所在的空间大小可以接纳这个字符串,否则可能出现问题。它的作用原理是将对应字符串的每一个字符改为其他的字符串,也要确保传过去的值是否有‘\0’。
(2)这里实现是将这两个字符串的地址都进行传过去,要被拷贝的指针用const进行修饰(因为这个指针指向的值并不需要修改),创建一个临时变量用于保存要修改的地址,将要修改的值进行一一修改,因为读取到后面会读取到‘\0’,所以这里直接使用while循环即可。
char* my_strcpy(char* dest, const char* src)
{
assert(dest);
assert(src);
char* ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[30] = "Yes";
char arr2[] = "No,I don't feel good.";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
3.strcmp
(1)strcmp是将两个字符串的值进行比较的一种方式,如果前一个字符串的值大于后一个字符串,则返回大于0的值;等于则返回0;小于则返回小于0的值。使用这个函数必须保证两个字符串后面有‘\0’以用于停止。
(2)这里实现是将两个字符串的地址分别传过去并用const进行修饰,因为这个指针指向的值不可以修改,这里对这两个字符串的每个一个字符串进行比较,最终返回用前一个指针指向的值减去后一个指针指向的值。
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char arr1[30] = "Yes";
char arr2[] = "No,I don't feel good.";
int ret = my_strcmp(arr1, arr2);
printf("%d\n", ret);
return 0;
}
4.strcat
(1)strcat函数是在一个字符串的末尾即从‘\0’开始往后进行补充另一个字符串的值,这两个字符串都必须要有‘\0’结尾,否则可能出现问题。
(2)这里实现是将两个字符串的地址都传过去并用const修饰,以保证其原始值不会发生改变。先创建一个临时变量保存第一个字符串的起始位置,然后从前向后先读取第一个字符串的值,直至读到‘\0’位置,然后将‘\0’及其后面的值一 一改为另一个字符串的值,知道读取到下一个字符串中‘\0’的位置,最终返回第一个字符串的地址。
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
while (*ret != '\0')
{
ret++;
}
while (*ret++ = *src++)
{
;
}
return dest;
}
int main()
{
char arr1[30] = "No,";
char arr2[] = "I don't feel good.";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
5.strstr
(1)strstr函数是在一个字符串中寻找另一个字符串及找子串,并返回指向 str2 中指定的整个字符序列中 str1 中第一个出现的指针,如果 str1 中不存在该序列,则为空指针。
(2)这里实现是先将两个字符串进行传址调用,这里使用的是c语言版本,未对其进行重载。先对要找的子串的地址分别用两个临时变量进行保存,将要查询的父串进行传参给另一个临时变量,如果要找的子串指向的是‘\0’,则直接返回子串。用子串的第二个临时变量其解引用后的值作为循环的判断条件,然后遍历这两个字符串,如果找到了则直接返回 t 的地址,如果找不到则直接返回空指针。
const char* my_strstr(const char* str1, const char* str2)
{
char* s1 = str1;
char* s2 = str2;
char* t = str1;
if (*s1 == '\0')
{
return str1;
}
while (*t)
{
s1 = t;
s2 = str2;
while (s1 != '\0' && s1 == s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return (char*)t;//找到了
}
t++;
}
return NULL;//找不到子串
}
int main()
{
char arr1[30] = "No,";
char arr2[] = "I don't feel good.";
char* t = my_strstr(arr1,arr2);
if (t == NULL)
{
printf("不存在\n");
}
else
{
printf("%s\n", t);
}
return 0;
return 0;
}
6.memcpy
(1)memcpy函数是将数字字节的值从源指向的位置直接复制到目标所指向的内存块,并且可以传输字符串以外的值,并不用读取到空字符串,才会停止,而是给予相应的值判断到某个位置进行停止。
(2)这里实现是将两个整形数组进行传址,并创建一个临时变量保存要改变的值的地址,这里传一个无符号整形变量的值,并将其作为循环的条件,直到其变为0,然后将要改变的值一 一进行改变,最终返回要改变的数组的起始地址。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
void* my_memcpy(void* dest, void* src, size_t num)
{
void* a = dest;
assert(dest);
assert(src);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return a;
}
int main()
{
int arr1[20] = { 1,2,3,4,5,6 };
int arr2[] = { 2,3,4,5,6,7,8 };
int n = 0;
scanf("%d", &n);
my_memcpy(arr1, arr2, n);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
7.memmove
(1)memmove函数主要是实现将数字字节的值从源指向的位置复制到目标所指向的内存块。复制就像使用了中间缓冲区一样进行,从而允许目标和源重叠。
(2)这里实现是直接将一个数组的两个地址传输,然后创建一个临时变量用于保存要改变的量的起始地址,然后判断这两个地址的大小,要是要改变的地址小于要拷贝的地址,则直接进行memcpy的操作即可,要是大于,则要先改变指针指向部分后面的值,以防止修改前面部分的值,而导致后面要拷贝的值发生改变即不能完成正确的拷贝。
void* my_memmove(void* dest, void* src, size_t num)
{
char* ret = dest;
assert(dest);
assert(src);
if (dest < src)
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)dest + 1;
}
}
else
{
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int n = 0;
scanf("%d", &n);
my_memmove(arr + 3, arr, n);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}