目录
一、strlen
//strlen的函数声明
size_t strlen(const char *str)
我们知道strlen函数用来计算字符串 str 的长度的,但是有些细节我们需要注意:
1:字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )。
2:参数指向的字符串必须要以 '\0' 结束;没有 '\0' 结束的话strlen会接着往下计算,直至内存中某处出现'\0'(这时strlen返回的值是随机值)。
3:注意函数的返回值为size_t,是无符号的。
strlen的模拟实现:
#define _CRT_SECURE_NO_WARNINGS
//模拟实现strlen
#include <stdio.h>
//当我们不需要改变指针指向的字符串内容时,最好在指针前加const
size_t my_strlen(const char* str)
{
int count = 0;
while (*str != '\0')//当指针指向'\0'就会停止计算
{
str++;
count++;
}
return count;
}
int main()
{
char ch[100] = { 0 };//不写下标则会报错——这会导致指针访问数组时越界
//ERR:Run-Time Check Failure #2 - Stack around the variable 'xxx' was corrupted
scanf("%s", ch);
int ret = my_strlen(ch);
printf("%d", ret);
return 0;
}
运行结果:
二、strcpy
//strcpy的声明
char *strcpy(char *dest, const char *src);
C 库函数strcpy把 src 指针所指向的字符串复制到 dest 数组。
需要注意的是:
1、如果目标数组 dest 不够大,而src字符串的长度又太长,可能会造成缓冲溢出的情况。
2、src字符串必须以 '\0' 结束,且strcpy会将src字符串中的 '\0' 拷贝到目标空间。
3、目标空间必须可变,若目标空间为常量就没办法实现strcpy。
模拟实现strcpy:
//模拟实现strcpy
char* my_strcpy(char* ch, const char* ch2)
{
char* ret = ch;
while (*ch2 != '\0')
{
*ch = *ch2;
ch++;
ch2++;
}
return ret;
}
int main()
{
char ch[100] = { 0 };
char ch2[20] = { 0 };
printf("请输入拷贝内容:\n");
scanf("%s", &ch2);
my_strcpy(ch, ch2);
printf("拷贝内容为:\n");
printf("%s", ch);
return 0;
}
运行结果:
三、strcmp
//strcmp的声明
int strcmp(const char *str1, const char *str2);
C 库函数strcmp把 str1 所指向的字符串和 str2 所指向的字符串进行比较,并返回某一数值。
其中有两个参数str1和str2 :str1 -- 要进行比较的第一个字符串。str2 -- 要进行比较的第二个字符串。
该函数返回值如下:
- 如果返回值小于 0,则表示 str1 小于 str2。
- 如果返回值大于 0,则表示 str1 大于 str2。
- 如果返回值等于 0,则表示 str1 等于 str2。
那它是如何比较两个字符串的?
两个字符串自左向右逐个字符相比(按 ASCII 值大小相比较),直到出现不同的字符或遇 '\0' 为止; 以"abcdef" 和 "ABCDEF" 两个字符串为例比较,显然左边字符串的ASCII值是大于右边的ASCII值,最后strcmp会返回正值以表示左边字符串比右边字符串大。
模拟实现strcmp:
//
//模拟实现strcmp
int my_strcmp(const char* str1, const char* str2)
{
while (*str1 == *str2)//若指向的字符相等则继续往下读,直到出现指向不同的字符
{
if (*str1 == '\0')
break;
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char str1[] = "ab";
char str2[] = "abc";
int ret = my_strcmp(str1, str2);
printf("%d", ret);//正数表示str1大于str2,负数表示str1小于str2,0表示两者相等
return 0;
}
运行结果:
四、strcat
//strcat的声明
char *strcat(char *dest, const char *src);
C 库函数strcat把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,其中有两个参数dest和src:dest -- 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串;src -- 指向要追加的字符串,该字符串不会覆盖目标字符串。最后strcat会返回一个指向最终的目标字符串 dest 的指针。
这里需要注意的是:
1、src字符串必须以 '\0' 结束。
2、目标空间必须有足够的大,能容纳下源字符串的内容。
3、目标空间必须可修改。
4、不可用strcat使字符串自己给自己追加内容,会陷入死循环。
模拟实现strcat:
//模拟实现strcat
char* my_strcat(char* ch1, const char* ch2)
{
char* ret = ch1;
while (*ch1)
{
ch1++;
}
while (*ch1++ = *ch2++)
{
;
}
return ret;
}
int main()
{
char ch1[100] = "xxxx";
char ch2[100] = "abc";
//不写下标则会报错——这会导致指针访问数组时越界
//ERR:Run-Time Check Failure #2 - Stack around the variable 'xxx' was corrupted
my_strcat(ch1, ch2);
printf("%s", ch1);
return 0;
}
运行结果:
五、strstr
//strstr的声明
char *strstr(const char *haystack, const char *needle);
C 库函数strstr可在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。其中有两个参数——haystack -- 要被检索的 C 字符串,needle -- 在 haystack 字符串内要搜索的小字符串。
若函数strstr在字符串 haystack 中找到第一次出现字符串 needle 的位置,则该函数会返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 null。
模拟实现strstr:
//模拟实现strstr
char* my_strstr(const char* str1, const char* str2)
{
const char* cur = str1;
const char* ch1 = str1;
const char* ch2 = str2;
if (*ch1 == '\0' || *ch2 == '\0')
{
return ch1;
}
while (*ch1 != '\0' && *ch2 != '\0' && (*ch1 == *ch2))
{
ch1++;
ch2++;
if (*ch2 == '\0')
{
return (char*)cur;
}
}
return NULL;
}
int main()
{
char ch1[100] = "abcdef";
char ch2[100] = "abcd";
char* p = my_strstr(ch1, ch2);
if (*p != NULL)
printf("%s", my_strstr(ch1, ch2));//找到了
else
printf("不存在\n");//没找到
return 0;
}
运行结果:
六、memcpy
//memcpy的声明
void *memcpy(void *str1, const void *str2, size_t n);
C 库函数memcpy从存储区 str2 复制 n 个字节到存储区 str1。最后该函数将会返回一个指向目标存储区 str1 的指针。
这其中有三个参数:str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针;str2 -- 指向要复制的数据源,类型强制转换为 void* 指针;n -- 要被复制的字节数。
这里需要注意的是:
1、这个函数在遇到 '\0' 的时候并不会停下来。
2、如果source和destination有任何的重叠,复制的结果都是未定义的。
模拟实现memcpy:
//模拟实现memcpy
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest);
assert(src);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
char ch1[100] = { 0 };
char ch2[] = "abcdef";
my_memcpy(ch1, ch2, strlen(ch2)+1);
printf("%s", ch1);
return 0;
}
运行结果:
七、memmove
//memmove的声明
void *memmove(void *str1, const void *str2, size_t n);
C 库函数memmove从 str2 复制 n 个字符到 str1;虽然功能与memcpy相似,但是如果源空间和目标空间出现重叠,就得使用memmove函数处理。也就是说它和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
//模拟实现memmove
#include <assert.h>
#include <string.h>
void* my_memmove(void* dest, const void* src,size_t num)
{
void* cur = dest;
assert(dest);
assert(src);
if(dest>src)
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return cur;
}
int main()
{
char ch1[100] = "you are XXXX beautiful!lol";
char ch2[] = "very";
my_memmove(ch1+8, ch2, 4);
printf("%s", ch1);
return 0;
}
运行结果