你知道strcmp和strncmp的区别吗?你知道strcpy和strncpy的区别吗?你知道什么是strstr函数吗?你知道什么是strerror函数吗?你知道什么是内存函数吗?
如果你不知道,以下知识可能会给你一定的帮助!
一、字符串函数
1、strlen函数
作用:计算字符串的长度
三种满分实现方法:
方法一(指针减指针):
//注意:size_t的类型是无符号整形
size_t my_strlen1(const char *p)
{
assert(p);
const char *end = p;
while (*end)
{
end++;
}
return end - p;
}
方法二(直接算count):
//方法二(直接算count):
size_t my_strlen2(const char *p)
{
assert(p);
int count = 0;
while(*p++)
{
count++;
}
return count;
}
方法三(递归方法):
//方法三(递归方法):
size_t my_strlen3(const char *p)
{
assert(p);
if (*p != '\0')
{
return 1 + my_strlen3(p + 1);
}
else
return 0;
}
int main()
{
char a[] = "ab cdefg";
printf("%d\n",(int)my_strlen1(a));
printf("%d\n", (int)my_strlen2(a));
printf("%d\n", (int)my_strlen3(a));
}
2、strcpy函数
原型:char* strcpy(char *e1,const char *e2)
作用:将字符串e2的内容拷贝到字符串e1中去。
注意:要求目标数组应该大于等于源数组的长度,不然空间不够,strcpy还把源数组的'\0'也一并拷贝过来了
char * my_strcpy(char *e1, const char* e2)
{
//写具体一点 assert(e1!==NULL&&e2!==NULL)
assert(e1&&e2);
char *sta = e1;
while (*e1++ = *e2++)
{
}
return sta;
}
int main()
{
char a[] = "hello world";
char b[] = "hello";
printf("%s\n", my_strcpy(a, b));
return 0;
}
3、strcmp函数
原型:int strcmp(const char *e1,const char *e2)
作用:比较两个字符串函数的大小
如果第一个字符串大于第二个,则返回大于0的数
如果第一个字符串小于第二个,则返回小于0的数
如果第一个字符串等于第二个,则返回等于0的数
int my_strcmp(const char *e1, const char *e2)
{
assert(e1&&e1);
while (*e1 == *e2&&*e1)
{
e1++;
e2++;
}
return *e1 - *e2;
}
int main()
{
char arr1[] = "hello world";
char arr2[] = "hello my dear";
int ret = my_strcmp(arr1, arr2);
if (ret > 0)
printf(">\n");
else if (ret < 0)
printf("<\n");
else
printf("=\n");
return 0;
}
4、strncmp函数
原型:int strcmp(const char * str1,const char *str2,size_t num)
作用:比较str1和str2前num个字符的大小,如果比较到比num个小的字符时已经有结果了,就可以停止比较了
#include<stdio.h>
#include<string.h>
int main()
{
char str1[10]="strncmp";
char str2[10]="strnc";
int ret = strncmp(str1,str2,3);//返回值为0
ret=strncmp(str1,str2,7);//返回值为大于0的数,并且只比较前6个字符就会返回
return 0;
}
5、strncpy函数
原型:char* strcpy(char * str1,const char *str2,size_t num)
返回的是str1的地址
作用:将str2前num个字符拷贝到str1的前num个字符中,如果str1字符串长度小于num,则拷贝完str1后,在目标的后边追加0,知道num个。
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "str";
char str2[] = "strstrstrncpy";
printf("%s", strncpy(str2, str1, 5));
return 0;
}
输出:
6、strncat函数
原型:char* strncat(char * str1,const char *str2,size_t num)
作用:(1)把str2中前num个字符和'\0'都传过去
(2)str2字符串不足num个会在后面补'\0'
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "str";
char str2[] = "strs\0XXXX";
printf("%s", strncat(str2, str1, 5));
return 0;
}
输出:
7、strcat函数
原型:char * my_strcat(char* e1,const char* e2)
作用:将e2的内容连接到e1的内容后面
思路:找到目标字符串中的第一个'\0',如何让*e2覆盖,把arr2字符串的所有内容都赋值过来(包括'\0')
注意 : arr1的长度要内容纳下原内容再加上arr2的内容.
char * my_strcat(char *e1, const char*e2)
{
assert(e1&&e2);
char * start = e1;
while (*e1)
{
e1++;
}
while (*e2)
{
*e1 = *e2;
e1++;
e2++;
}
return start;
}
int main()
{
char arr1[10] = "abcd";
char arr2[] = " efg";
printf("%s", my_strcat(arr1, arr2));
}
8、strstr函数
原型:char * strstr(const char * e1,const char *e2)
strstr函数的作用:从字符串arr1中找到有没有字符串arr2
且返回arr2中第一个arr1数组的首地址
char * my_strstr(const char * e1, const char *e2)
{
assert(e1&&e2);
const char *valid = e1;
const char *start = e2;
while (*valid)
{
while (*e1 == *e2&&*e1&&*e2)
{
e1++;
e2++;
}
//找到了子串的位置
if (*e2 == '\0')
{
//valid是const char *,因此要注意转换成char*
return (char*)valid;
}
valid++;
e2 = start;
e1 = valid;
}
return NULL;
}
int main()
{
char arr1[] = "abbcdbbddefexdbbdd";
char arr2[] = "bbdd";
if (my_strstr(arr1, arr2) != NULL)
{
printf("%s", my_strstr(arr1, arr2));
}
else
printf("不是它的子串\n");
}
9、strtok函数
原型:char *strtok( char * str, const char*sep)
sep 参数的作用:sep参数是个字符串,定义了用作分隔符的字符集合
规则:(1)当str不是NULL时,函数将找到str中第一个标记(找到sep中的内容),如果strtok 函数将保存它在字符串的位置,下一次调用就会从这个位置开始查找
(2)当str是NULL时,函数将在同一个字符串中被保存的位置开始,查找下一个标记
(3)如果字符串中还存在标记,则返回这一次开始查找时的地址
(4)如果字符串中不存在更多的标记,则返回NULL的指针
int main()
{
char a[] = "who: yaki what:will be more and more excellent!";
char b[100];
strcpy(b, a);//strtok函数会改变被操作的字符串,所以在使用strtok函数切分的函数一般都是临时拷贝的内容
const char *sep = ": "; //sep的内容有':'和' '还有'\0',但'\0'不是标记,但但但是'\0'作为字符串结束的标志,所以遇到它就会停止
char *str = NULL;
for (str = strtok(b, sep); str != NULL; str = strtok(NULL, sep))
{
printf("%s\n", str);
}
return 0;
}
10、strerror和perror函数
strerror
原型:char * strerror (int errnum)
作用:返回错误码所对应的错误信息
perror(strerror的好兄弟)
原型:void perror(const char *str)
因此,你如果想要用他得到错误信息,那么你就得传一个常量字符串,这个常量字符串是什么都可以
#include<stdio.h>
#include<errno.h> //全局变量errno的头文件,errno是一个专门存储错误信息的全局变量
#include<stdlib.h>//perror的头文件
#include<string.h>//strerror的头文件
#include<limits.h>//INT_MAX的头文件
int main()
{
printf("%s\n", strerror(0));
printf("%s\n", strerror(1));
//都会打印出错误码对应的错误信息,strerror这个函数会返回错误信息的首元素地址
int *p = (int *)malloc(INT_MAX);//向堆区申请内存,INt_MAX代表整形最大值;CHAR_MAX代表字符型最大值,127
if(p==NULL)
{
printf("%s\n", strerror(errno));//errno这是一个全局变量,用来存储错误码的变量,使用时要引用头文件:#include<errno.h>
}
if (p ==NULL)
{
perror("haha");//这个“”里面可以不是haha,可以输入任意字符串
}
return 0;
}
输出:
二、内存函数
内存函数有什么特别之处呢?它们是以字节为单位处理数据的。
1、memcpy函数
原型:void * memcpy(void * destination , const void * source , size_t num )
作用:(1)函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存 位置这个函数遇到'\0'不会停下来
(2)如果source和destination有任何重叠,复制的结果都是未定义的
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void *dest, const void * src, size_t num)
{
assert(dest&&src);
void * ret = dest;
while(num--)
{
*(char *)dest= *(char *)src;
((char *)dest)++;
((char *)src)++;
}
return ret;//注意函数的定义,是返回void* 指针,而非函数是void型
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
my_memcpy(arr2, arr1, 20);//把前五个数字copy到arr2中
return 0;
}
memcpy 有个小不足,就是destination和source不能有重叠的部分,那么此时我们就要用另一个函数来实现
2、memmove函数
原型:void * memmove(void *dest,const void *src,size_t num);
作用:不仅能实现memcpy的功能,还允许destination和source能够重叠
#include<stdio.h>
#include<assert.h>
void* my_memmove(void *dest, const void * src, size_t num)
{
assert(dest&&src);
void *ret = dest;
if (dest < src)
{
while (num--)
{
/*从前往后改变*/
*(char *)dest = *(char *)src;
++(char *)dest;
++(char *)src;
}
}
else
{
while (num--)
{
/*从后往前改变*/
*((char *)dest+num) = *((char *)src+num);
/*注意是+num,而非num-1,此时程序已经执行了num--了*/
}
}
return ret;
}
int main()
{
int arr1[10] = { 1, 2, 3, 4, 5, 6,7,8,9,10 };
my_memmove(arr1+3, arr1, 12);
return 0;
}
3、memset函数
原型:void * memset(void * dest,int c,size_t num);
作用:一个一个字节的改变
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[10] = { 1, 2, 3, 4, 5, 6,7,8,9,10 };
memset(arr1, 6, 12);
注意这个地方不是把前三个数都改成6,而是把它们都改成0x06060606
}