文章目录
一.字符函数
1.长度不受限制函数的介绍即个别函数的模拟
1.1strlen
1.1.2函数的介绍
size_t strlen ( const char * str );
1.字符串已经‘\0’作为结束标志,strlen函数返回的是字符串中’\0‘前面出现的字符数;(不包括’\0‘)
2.参数指向的字符串必须以’\0‘结束;
3.注意函数的返回值是size_t类型(无符号整形);
原因:就算算出来的数是负数,它的补码不变,而因为是无符号类型所以;
补码将认为是一个很大的数;
1.1.2模拟该函数的方法
1.2strcpy
char* strcpy(char * destination, const char * source );
1.2.1函数的原理:
把原字符串的’\0’之前的字符及’\0’复制到目标字符串上;返回值是目标字符串的首地址
所以源字符串必须以”\0"结束
;
字符串变量数组的拷贝只可以使用strcpy而不可以使用“赋值”(不合法)
目标空间必须足够的大,以保证存放源字符窜;
目标空间可变:
1.2.2模拟实现函数:
1.3strcat
1.3.1函数原理:
char * strcat ( char * destination, const char * source );
由上图可以看出: 后加是从目标字符串的“\0"开始(”\0"将被覆盖)到加数的“\0"结束;
注意
两个字符串必须有”\0"(两者风别是开始标志和结束标志)
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。**
这个函数无法实现字符串的自己追加; 想要实现可以使用strncat函数;
1.3.2模拟函数的实现:
char* my_strcpy(char*rr,const char* arr1)
{
char* sub =rr;
while (*rr!= '\0')
{
rr++;
}
while (*rr++=*arr1++)
{
;
}
return sub;
}
int main()
{
char arr[20] = { "bit" };
char arr1[] = { "dibsjk" };
printf("%s", my_strcpy(arr, arr1));
return 0;
}
1.3.3 特例
数组自己想自己追加;
这个函数无法自己加自己的字符;可以使用下面的函数strncat。
*注意:const限定的是不让使用src解引用来访问;*但可以使用dest来访问空间;
1.4strcmp
1.4.1函数的定义
int strcmp ( const char * str1, const char * str2 );
对于字符窜的比较怎么办呢?
答:只可以使用strcmp而不可以使用“==”
如果前面的字符大于后面的字符那么返回值是一个大于0的数,反之是一个小于0的数,全部相等则是返回“0”。
1.4.2函数的模拟
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int my_strcmp(char* arr1, char* arr2)
{
while (*arr1 == *arr2)
{
if (*arr1 = *arr2)
{
return 0;
}
arr1++;
arr2++;
}
return *arr1 - *arr2;
}
int main()
{
char arr1[] = "abq";
char arr2[] = "abq";
printf("%d",my_strcmp(arr1, arr2));
return 0;
}
1.5长度不受限的函数终结
上面的几个函数:strcpy函数,strcat函数,strcmp函数,strlen函数。
除了strcmp函数都是只看”\0"的;他们的长度都不受限制所以在超过目标数组的大小会输出但是会报警报就像scanf一样,警报危险;
下面我们就介绍一下长度受限函数;
2.长度受限制函数(可以让你思考一下从长度是否超过)
下面的考虑都是在目标数组足够大的情况下考虑的;
2.1strncpy
char * strncpy ( char * destination, const char * source, size_t num );
复制的个数小于原数组个数不考虑”\0"
而当复制的个数大于原数组的个数,需要考虑在“\0"后面补加”\0"
strcpy和strncpy的区别
strcpy函数是将原数组全部复制到被接受数组“考虑”\0"“.
strncpy函数是将原数组的部分复制到被接受数组,当个数超过原数组时,“考虑”\0”
用“\0”补齐;
2.2strncat
char * strncat ( char * destination, const char * source, size_t num );
后加是将部分的原数组的部分数加到后数组的第一个”\0"后面;且后补“\0",
因为strcat函数是在原函数的“\0"停止,所以当限制的数字大于原数组的大小也不会后补”\0".
** 注:**
strncat函数是可以自己给自己追加的;
2.3 strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
将部分字符串进行比较;比较的Min版
3.其他字符(串)函数
3.1strstr
3.1.1函数的定义:
char * strstr ( const char *str1, const char * str2);
该函数是在arr中找arr1找到后返回找到的(第一个出现的)首地址;
类似的函数:
strchr
用来查找前一个字符串中的一个字符第一次出现的位置;
strrchr
用来查找字符串中一个字符的最后一次的位置;
3.1.2函数的模拟:
1.BF算法
即:Brute Force(暴力)算法
char* my_strstr(char* str, char* str1)
{
char* s1 = NULL;//定义这几个变量是为了使str和str1不变使循环可以回到起点;
char* s2 = NULL;
char* cp = str;
while (*cp)//这个循环是为了第一个字符串比较找起点//记得加*
{
s1 = cp;//回到起点
s2 = str1;
while (*s1&&*s2&&*s1 == *s2)//比较两字符串是否相同;前面单独加变量是为了加快处里速度;
{
s1++;
s2++;
}
if (*s2 == '\0')//s2='\0'是找到的标志
{
return cp;
}
cp++;
}
return 0;//循环结束是没找到的标志;
}
int main()
{
char arr1[] = "abcdebcdf";
char arr2[] = "bc";
char* p = my_strstr(arr1, arr2);
if (p == NULL)
{
printf("找不到\n");
}
else
{
printf("%s\n", p);
}
return 0;
}
2.kmp算法(网址)
kmp算法更加复杂,但更高效;大家可以打开链接了解,后面我会出详细讲解
3.2strtok
3.2.1函数定义
char * strtok ( char * str, const char * sep );
该函数的功能是将字符串进行分割,并返回分割段的首地址;
str:是被分割的字符串;(因为会被改变,所以需要使用字符数组)
sep:是分割的断点字符的字符串字符串(它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。(因为函数数组不发生改变,所以可以使用字符指针)的首地址;
函数的规则
strtok第一次找字符串的分割字符后会将被分割的分割字符改变为“\0"
并记录该分割字符的地址;所以第二次进行切割第二段字符串时可以不写被切割的原数组,而是写NULL;
3.2.2函数的使用方法
普通法
进阶法
3.3strerror
3.3.1函数定义
char * strerror ( int errnum );
strerror是把库函数调用错误的错误码变量(errno)翻译为错误信息函数;
使用例子
1.理论的使用方法:
2.实践的使用方法:
(打开文件)
3.3.2函数的扩展:
1.errno变量的用法:
发生一次错误变量将变赋值一次;当下一次发生库函数错误后error变量将发生变化;所以该变量需要及时使用;
2.perror函数
将括号里的文字进行打印再加之打印":"+"错误码的字符表示“**。
正确的使用方法是将错误中文进行输出再由函数自己输出”:"和调用库函数错误的英文解释;
二.内存函数
1.memcpy
1.1函数定义
num是限制复制内容的大小;(num是以字节为单位);
1.函数解释:函数memcpy从source的位置开始向后复制num个字节的数据destination的内存位置。
2.这个函数在遇到 ‘\0’ 的时候并不会停下来。
3.返回值是目标地址,但是平常不使用返回的目标地址;因为目标地址在原函数上是有的;
1.2例子:
1.3函数的模拟实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void* my_memcpy(void* str, const void* dtr,size_t num)
{
void* ret = str;
for (int i = 0; i<num; i++)
{
*(char*)str = *(char*)dtr;
((char*)str)++;
((char*)dtr)++;
}
return ret;
}
void text1()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[8] = { 0 };
int* p = my_memcpy(arr2, arr1, 20);
for (int i = 0; i < 5; i++)
{
printf("%d\n", *(arr2 + i));
}
}
int main()
{
text1();
return 0;
}
改进版
2.memmove
2.1函数的定义:
void * memmove ( void* destination, const void * source, size_t num );
1.与memcpy函数相同都是将内存中的内容拷贝到目标内存;
2.和mecpy函数的区别是该函数可以处理原内存和目标内存重叠的情况;
3.当原内存和目标内存不重合时两个函数都可以使用;当原内存和目标内存重合时只可以使用memmove函数处理;
2.2函数的模拟实现
原理:
即:目标内存的首地址在原内存的首地址前面就使用前传后,目标内存的首地址在原内存的首地址后面就使用后传前。
代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void* my_memmove(void* dest, void* src, size_t num)
{
void* ret = dest;
if (src > dest)
{
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 arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = (int*)my_memmove(arr1, arr1 + 2, 20);
for (int i = 0; i < 10; i++)
{
printf("%d\n", *(arr1 + i));
}
return 0;
}
3.memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
该函数和strcmp函数相同都是以一个字节一个字节的进行比较;所以比较整型时可以将整形改为二进制逐一字节进行比较;
**功能:**比较从ptr1和ptr2指针开始的num个字节。
返回值:
当ptr1<ptr2时,返回值<0
当ptr1=ptr2时,返回值=0
当ptr1>ptr2时,返回值>0
应用:
4.memset
void * memset ( void * ptr, int value, size_t num );
ptr是目标内存的首地址;value是将内存改变的目标字符;num是改变的字节数;
应用:
函数是一个字节一个字改变;
三.字符分类函数(包含在头文件ctype.h)
这些函数没必要背过需要时在库函数中找就好了;
这些函数都有通用性;参数满足条件即返回一个不为0的值;而当参数不满足条件时返回’0’;