重点介绍处理内存函数、字符和字符串的库函数的使用和注意事项
介绍的函数有:
1.strlen的使用和模拟实现
2.strcpy的使用和模拟实现
3.strcat的使用和模拟实现
4.strcmp的使用和模拟实现
5.strncpy函数的使用
6.strncat函数的使用
7.strncmp函数的使用
9.strtok函数的使用
10.strerror函数的使用
11.内存函数memmove的使用和模拟实现
12.内存函数memcmp函数的使用
13.内存函数memset函数的使用
1.strlen的使用和模拟实现
size_t strlen(const char* str);
关于strlen的使用规则:
1.字符串以‘\0’作为结束标志,strlen函数返回的是在字符串中‘\0’前面出现的字符个数(不包含‘\0’)
2.参数指向的字符串必须要以‘\0’结束
3.函数的返回值是size_t,是无符号的(易错点)
如图所示,字符串的返回值互减依旧是一个无符号数
模拟实现strlen函数有两种方法
一种是递归还有一种是指针
/*递归模拟实现*/
int mystrlen(char* x)
{
if (*x != '\0')
{
return 1 + mystrlen(x + 1);
}
else
{
return 0;
}
}
int main()
{
char a[] = "abc";
int b = mystrlen(a);
printf("%d", b);
}
/*指针模拟实现*/
int strleng(char* x)
{
int count = 0;
while(*x != '\0')
{
count++;
x++;
}
return count;
}
int main()
{
char a[] = "bit";
int b = strleng(a);
printf("%d", b);
}
2.strcpy的使用和模拟实现
char* strcpy(char* destination,const char* source);
strcpy的注意事项:
1.原字符串必须以‘\0’结束
2.会将原字符串中的‘\0’拷贝到目标空间
3.目标空间必须足够大,已确保能存放源字符串。
4.目标空间必须可变
举例说明这几个注意事项
第一点:
原字符串没有‘\0’,函数读取的时候停不下来,就会造成内存的越界访问
第二点:
会将原字符串中的‘\0’拷贝到目标空间
第三点:
可以通过改变地址来拷贝原函数到目标函数的任意合法位置
模拟实现strcpy函数:
/*模拟实现strcpy函数*/
char* my_strcpy(char* dest, const char * src)
{
char* ret = dest;
assert(dest != NULL);/*断言(要是dest或者src为空指针,程序会反馈这个信息,会提示assert这一行的代码出错)*/
assert(src != NULL);
while (*dest++ = *src++)
;//空语句
return ret;
}
int main()
{
char arr1[] = "hello bit";
char arr2[20] = "xxxxxxxxxxxxx";
char* p = NULL;
my_strcpy(arr2, arr1);
printf("%s\n", arr2);
printf("%s\n", my_strcpy(arr2, arr1));
return 0;
}
3.strcat的使用和模拟实现
char* strcat(char* destination,const char* source)
功能:在destination后面追加一个source
注意事项:
1.源字符串必须以‘\0’结束
2.目标空间必须足够大,已确保能存放源字符串。
3.目标空间必须可修改
4.strcat是在目标函数‘\0’的位置上,追加源字符串,其中‘\0’会被替换上源自符串上的字符
5.这个函数不能字节给自己追加字符串
功能示例:
注意事项第四点与第五点示例:
字符串最后的‘\0’会因为assert的拷贝而变成a,然后arr就会变成abcdefabcdefabcd.....一直拷贝下去陷入了死循环,造成了内存越界。
模拟实现assert函数
char* my_strcat(char* desk, const char* str)
{
assert(desk);
assert(str);/*利用断言判断desk和str是否为空指针*/
char* p = desk;
while (*desk)/*搜索目标函数‘\0’的位置,当位置为‘\0’的时候循环结束*/
{
desk++;
}
while (*desk++ = *str++)/*先等于然后用++进行下一个字符的改变,所以用后置++*/
{
;
}
return p;/*返回起始地址*/
}
int main()
{
char arr[100] = "abcdef";
char arr1[100] = "hijklmn";
my_strcat(arr, arr1);
printf("%s", arr);
}
4.strcmp的使用和模拟实现
int strcmp(const char* str1,const char* str2)
两个字符串自左向右逐个字符相比(按ascll值大小相比较),直到出现不同的字符或者遇到‘\0’为止
标准规定:
在检索的位置相同的情况下,第一个字符串中字符的ascll大于第二个字符串中字符的ascll,则返回大于0的数字
在检索的位置相同的情况下,第一个字符串中字符的ascll等于第二个字符串中字符的ascll,则返回等于0的数字
在检索的位置相同的情况下,第一个字符串中字符的ascll小于第二个字符串中字符的ascll,则返回小于0的数字
功能示例:
如上图所示
其中arr1与arr2相比返回值为-1,是因为arr1末尾为‘\0’会与arr2中的字符d相比较ascll码,‘\0’的ascll码值会比d小,所以arr1会比arr2小,返回值为-1。
模拟实现strcmp函数
int my_strcmp(const char* dest, const char* str)
{
while (*dest == *str)
{
if (*dest == '\0')
{
return 0;
}
dest++;
str++;
}
if (*dest > *str)
{
return 1;
}
else
return -1;
/*return *dest - *str;*//*也可以写成这种形式,因为在vs中只要是正数返回值就是1,负数返回值为-1,0返回值为0*/
}
int main()
{
char arr[] = "abc";
char arr2[] = "abcd";
printf("%d\n", my_strcmp(arr, arr2));
}
5.strncpy函数的使用
char* strncpy(char* destination,const char* souce,size_ t num)
本质与strcpy函数一样,但是多了一个num参数
功能:
1.拷贝num个字符从源字符串到目标空间。
2.如果源自符串的长度小于num,则拷贝完源自符串之后,在目标的后面追加0,直到num个。
功能的第一点.如图示例:
功能的第二点.如图示例
6.strncat函数的使用
char* strncat(char* destination,const char* source,size_t num);
功能与strcat差不多,但是多了个num的参数
功能:
在source中截取num个字节追加到destination后面
注意:
1.num在strncat函数中只是限制追加字符串的个数,并且追加完后会补充‘\0’
2.strncat是在目标函数‘\0’的位置上,追加源字符串,其中‘\0’会被替换上源自符串上的字符
注意事项第一点以及第二点的示例:
7.strncmp函数的使用
int strncmp(const char* str1,const char* str2,size_t num)
功能与strcmp函数差不多,只不过多了一个num参数
功能:比较到出现另一个字符不一样或者一个字符串结束或者num个字符全部比较完。
8.strstr的使用和模拟实现
char* strstr(const char* str1,const char* str2)
在字符串str1中找第一次出现的字符串str2,如果找到则返回字符串str1中第一次出现字符串str2的地址,如果找不到则返回空指针
功能示例:
模拟实现strstr函数:
my_strstr( char* p1, char* p2)
{
char* p = p1;/*多设一个指针变量p*/
while (*p)/*p会循环到arr的末尾字符串位'\0'为止*/
{
p1 = p;
while (*p1 && *p2 && *p1 == *p2)/*万一p1的字符与p2一直相等,则会循环到p2的末位字符‘\0’为止*/
{
p1++;
p2++;
if (*p2 =='\0')
{
return p;/*返回字符串arr中第一次出现字符串arr1的地址*/
}
}
p++;/*找不到就会让p++,由于最开头的时候p=p1,所以此刻会进入p1访问的字符串arr的下一个字符*/
}
return NULL;
}
int main()
{
char arr[] = "abcdef";
char arr1[] = "bcd";
char* p = my_strstr(arr, arr1);
if (*p != NULL)
{
printf("%s",p);
}
else
{
printf("字符串中寻找不到这串字符");
}
}
9.strtok函数的使用
char* srtok(cahr* str,const char* sep)
1.sep参数是一个字符串,定义了用作分隔符的字符集合
2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记
3.strtok函数在str找到一个分隔符,将str中的分隔符用‘\0’代替,返回一个指向这个标记的指针
4.strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
5.strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存他在字符串中的位置
6.如果字符串中不存在更多的标记,则返回NULL指针。
注意事项:
1.strtok函数会改变被操作的字符串,所以在使用strtok函数,切分的字符串的时候一般都是用其他变量临时拷贝原先字符串的内容
注意事项示例:
如上图所示,可以看到arr的内容被修改了。
使用示例:
10.strerror函数的使用
char* strerror(int errnum)
功能:返回错误码所对应的错误信息
注意:库函数在执行的时候,发生了错误时会将一个错误码存放在errno这个变量中,errno是c语言提供的全局变量。
使用示例:
11.内存函数memmove的使用和模拟实现
void* memmove(void* destination,const void * source,size_t num)
1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存空间。
2.这个函数在遇到'\0'的时候并不会停下来
3.这个函数可实现自我拷贝。
使用示例:
如图所示,memmove函数可以实现自我拷贝
模拟实现memmove函数思路:
由于这个函数可以实现自我拷贝,实现自我拷贝的时候有两种具体的情况。如下图所示:
如上图所示,当des>str的时候依旧从前向后拷贝,就会把更改后的内容拷贝到字符串上,造成最终输出的结果与程序输出的不一样。所以实现自我拷贝应该着重考虑源字符串和目标字符串位置之间的关系,然后通过它们的位置关系判断应该用那种方式拷贝内容上去。
模拟实现memmove函数:
void* my_memmove(void* dest, const void* str, size_t num)
{
if (dest > str)
{
while (num--)
{
*((char*)dest + num) = *((char*)str + num);/*因为num的单位是字节,所以也将dest和num强制转换成char*类型,单位也是一个字节*/
}
}
else
while (num--)
{
*(char*)dest = *(char*)str;
((char*)dest)++;
((char*)str)++;
}
}
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
my_memmove(arr+2, arr,20);
for (int i = 0; i < 10;i++)
{
printf("%d ", arr[i]);
}
}
12.内存函数memcmp函数的使用
int memcmp(const void* ptr1,const void* ptr2,size_t num)
功能
1.比较从ptr1和ptr2指针开始的num个字节
2.ptr1>ptr2返回1,ptr1=ptr2返回0,ptr1<ptr2返回-1
功能示例:
13.内存函数memset函数的使用
void* memset(void* ptr,int value,size_t num)
功能:访问ptr的内容,并将其num个字节的内容修改成value
功能示例:
创作不易!希望大家给个一键三连