这里鄃鳕推荐一个可以查找函数的具体细节的网站 ,以便后续学习https://legacy.cplusplus.com/reference/cstring/strlen/?kw=strlen
字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包
含 ‘\0’ )
注意函数的返回值为size_t,是无符号的(很重要)
int my_strlen( const char* str)
{
int count = 0;
assert(str!=NULL);
while (*str != '\0')
{
str++;
count++;
}
return count;
}
int main()
{
char arr[] = "abc";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
看下面一道题:
int main()
{
if (my_strlen("abc") - my_strlen("abcdef") > 0)
{
printf(">\n");
}
else
{
printf("<=\n");
}
return 0;
}
答案是> ,为什么呢? strlen的返回类型是size_t ,是unsigned int ,是无符号数,3-6 得到的-3 在内存中被解读成非常大的正数
自然结果大于0
int main()
{
char arr[] = "###########";
char* p = "hello";
strcpy(arr, p);
printf("%s", arr);
return 0;
}
源字符串必须以 ‘\0’ 结束。
会将源字符串中的 ‘\0’ 拷贝到目标空间
目标空间必须足够大,以确保能存放源字符串
目标空间必须可变,所以不加const ,源字符串不用改变,加个const 更加安全
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
当strcpy 目标空间没有足够大而导致出现问题,而strncpy 相对于strcpy来说 ,多了一个参数 ,相对比较安全。
int main()
{
char arr1[20] = "abcdefghi";
char arr2[] = "qwer";
strncpy(arr1, arr2, 6);
printf("%s\n", arr1);
return 0;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s", arr1);
return 0;
}
源字符串必须以 ‘\0’ 结束。
目标空间必须有足够的大,能容纳下源字符串的内容
目标空间必须可变,所以不加const ,源字符串不用改变,加个const 更加安全
char * my_strcat(char* dest, const char* src)
{
// 找到目标空间的\0
char* ret = dest;
assert(dest && src);
while (*dest)
{
dest++;
}
//追加
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
printf("%s", my_strcat(arr1, arr2));
return 0;
}
那么字符串自己给自己追加,这样做行吗?
int main()
{
char arr[20] = "abcd";
strcat(arr, arr);
printf("%s\n", arr);
return 0;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
strncat(arr1, arr2, 10);
printf("%s\n", arr1);
return 0;
}
strncat相比较strcat多了一个参数 ,相对而言更安全
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
可以都加上const ,让代码更安全
int main()
{
int ret = strcmp("abbb", "abq");
printf("%d", ret);
return 0;
}
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;
}
int main()
{
char* p = "abcdef";
char* q = "abcdef";
int ret = my_strcmp(p, q);
if (ret > 0)
{
printf("p>q\n");
}
else if( ret < 0)
{
printf("p);
}
else
{
printf("p==q\n");
}
return 0;
}
int main()
{
char* p = "aqcdef";
char* q = "abcqwert";
int ret = strncmp(p, q, 4);
printf("%d\n", ret);
return 0;
}
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
char * ret = strstr(arr1, arr2);
if (ret == NULL)
{
printf("没找到\n");
}
else
{
printf("找到了:%s\n", ret);
}
return 0;
}
char * my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = NULL;
const char* s2=NULL;
const char* cp = str1;
if (* str2 == '\0')//str2是空字符串
{
return (char *)str1;
}
while (*cp)//查找
{
s1 = cp;
s2 = str2;
while (*s1 && *s2 && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return(char * ) cp;
}
cp++;
}
return NULL;//找不到
}
int main()
{
//在arr1中查找是否包含arr2数组
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
char * ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("没找到\n");
}
else
{
printf("找到了:%s\n", ret);
}
return 0;
}
int main()
{
char arr[] = "[email protected]";
char* p = "@. ";
char tmp[30] = { 0 };
strcpy(tmp, arr);
char* ret = NULL;
for (ret = strtok(tmp, p); ret != NULL; ret = strtok(NULL, p))
{
printf("%s\n", ret);
}
return 0;
}
- sep参数是个字符串,定义了用作分隔符的字符集合
- 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标
记。- strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。)- strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串
中的位置。- strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
记。- 如果字符串中不存在更多的标记,则返回 NULL 指针。
strerror 函数 (返回错误码,所对应的错误信息)
使用库函数的时候
调用库函数失败的是,都会设置错误码
全局的错误码
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
fclose(pf);
pf = NULL;
return 0;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memcpy(arr2, arr1, 20);
return 0;
}
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
- 这个函数在遇到 ‘\0’ 的时候并不会停下来。
- 如果source和destination有任何的重叠,复制的结果都是未定义的。
- memcpy函数应该拷贝不重叠的内存(在vs2019memcpy可以拷贝重叠的内存,但是正常情况下memcpy是不能拷贝重叠的内存)
void * my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
while (num--)
{
*(char*)dest = *(char* )src;
src = (char*)src + 1;
dest = (char*)dest + 1;
}
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
my_memcpy(arr2, arr1, 20);
return 0;
}
void* 是无具体类型的指针 ,解引用不知道访问几个字节 ,+1 也不知道跳过几个字节,强制类型转换为char* 就是一个很好的解决办法
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memmove(arr1, arr1+2, 20);
return 0;
}
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
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;
src = (char*)src + 1;
dest = (char*)dest + 1;
}
}
else
{
//后——>前
while (num--)
{
* ( (char *) dest + num) = *( (char *)src + num);
}
}
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
my_memmove(arr1, arr1 + 2, 20);
return 0;
}
从后向前拷贝:
如果你觉得这篇文章对你有帮助,不妨动动手指给点赞收藏加转发,给鄃鳕一个大大的关注
你们的每一次支持都将转化为我前进的动力!!!