目录
一、长度不受限制的字符串函数
1.strlen函数
字符串以‘\0’作为结束标志,strlen函数返回的是字符串前面出现的字符个数
函数原型:size_t strlen( const char *string );
头 文 件 :<string.h>
函数功能:计算字符串的长度;
注意事项:1.定义的字符串必须要包含'\0'
char arr1[] = "abcd";/*正确*/ char arr2[] = { 'a', 'b', 'c', 'd' };/*错误*/
举例:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "ABCD";//里面包含\0
char str2[] = { 'A','B','C','D' };//里面不包含\0
printf("%d\n", strlen(str1));
printf("%d\n", strlen(str2));
return 0;
}
2.strcpy函数
函数原型:char *strcpy( char *strDestination, const char *strSource );
头 文 件 :<string.h>
函数功能:字符串拷贝;它是连同'\0'一起拷贝过去;
参数解读:
1.char *strDestination --- 目标字符串
2.const char *strSource --- 源字符串(不可被修改)
3.返回类型:char* --- 返回的是拷贝后源字符串的地址
注意事项:
1.拷贝时源字符串中一定要包含\0;
2.拷贝时目标空间要足够大,保证放的下要拷贝过去的字符串;
3.拷贝时目标空间必须可修改(不能被const修饰);
举例:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[20] = "xxxxxxx";//目标空间要足够大
char str2[] = "Hello World";
printf("拷贝前为:%s\n", str1);
strcpy(str1, str2);
printf("拷贝后为:%s\n", str1);
return 0;
}
3.strcat函数
函数原型:char *strcat( char *strDestination, const char *strSource );
头 文 件 :<string.h>
函数功能:字符串连接(追加):它是连同'\0'一起追加过去;
参数解读:
1.char *strDestination --- 目标字符串
2.const char *strSource --- 源字符串(不可被修改)
3.返回类型:char* --- 返回的是拷贝后源字符串的地址
注意事项:
1.追加时源字符串中一定要包含\0
2.追加时目标空间要足够大,保证放的下要追加过去的字符串
3.追加时目标空间必须可修改(不能被const修饰)
4.自己不能给自己追加(需要使用strncat)
举例:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[20] = "Hello ";//目标空间要足够大
char str2[] = "World";
printf("追加前为:%s\n", str1);
strcat(str1, str2);
printf("追加后为:%s\n", str1);
return 0;
}
4.strcmp函数
函数原型:int strcmp( const char *string1, const char *string2 );
头 文 件 :<string.h>
函数功能:字符串比较:比较的是ASSIC码值;比较的是内容而不是长度;
参数解读:
1.string1 --- 被比较的字符串;
2.string2 --- 待比较的字符串;
比较方法:
1.当 str1 < str2 返回负数
2.当 str1 = str2 返回0
3.当 str1 > str2 返回正数
举例:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "ABCD";
char str2[] = "ABCE";
int ret = strcmp(str1, str2);
if (ret > 0)
{
printf("ret=%d:str1>str2\n", ret);
}
else if (ret < 0)
{
printf("ret=%d:str1<str2\n", ret);
}
else
{
printf("ret=%d:str1=str2\n", ret);
}
return 0;
}
二、 长度受限制的字符串函数
1.strncpy函数
函数原型:char *strncpy( char *strDest, const char *strSource, size_t count );
头 文 件 :<string.h>
函数功能:字符串拷贝:可以指定拷贝字符的个数;
参数解读:
1.char *strDest --- 目标字符串
2.const char *strSource --- 源字符串(不可被修改)
3.size_t count --- 指定拷贝多少个字符
4.返回类型:char* --- 返回的是拷贝后源字符串的地址
注意事项:
1.拷贝时:当拷贝的个数大于源字符串长度时(比如源字符串“abcd”,拷贝6个),不够的用\0补(设置个数时要合理)
2.拷贝时目标空间要足够大,保证放的下要拷贝过去的字符串
3.拷贝时目标空间必须可修改(不能被const修饰)
举例:
#include <stdio.h>
#include <string.h>
int main()
{
char dest[20] = "xxxxxxx";
char src[] = "Hello World";
printf("拷贝前为:%s\n", dest);
strncpy(dest, src,5);
printf("拷贝后为:%s\n", dest);
return 0;
}
#include <stdio.h>
#include <string.h>
int main()
{
char dest[20] = "xxxxxxxxxx";
char src[] = "abcd";
printf("拷贝前为:%s\n", dest);
strncpy(dest, src, 6);
printf("拷贝后为:%s\n", dest);
return 0;
}
2.strncat函数
函数原型:char *strncat( char *strDest, const char *strSource, size_t count );
头 文 件 :<string.h>
函数功能:字符串追加:可以指定追加字符的个数;
参数解读:
1.char *strDest --- 目标字符串
2.const char *strSource --- 源字符串(不可被修改)
3.size_t count --- 指定追加多少个字符
4.返回类型:char* --- 返回的是拷贝后源字符串的地址
注意事项:
1.追加时:当追加的个数小于源字符串的个数时,会主动追加'\0'
2.追加时:当追加的个数大于源字符串的个数时,库函数的定义是只追加到'\0'位置,所以个数就算很大并不影响
3.追加时目标空间必须可修改(不能被const修饰)
举例:
#include <stdio.h>
#include <string.h>
int main()
{
char dest[20] = "Hello ";
char src[] = "World";
printf("追加前为:%s\n", dest);
strncat(dest, src, 4);
printf("追加后为:%s\n", dest);
return 0;
}
3.strncmp函数
函数原型:int strncmp( const char *string1, const char *string2, size_t count );
头 文 件 :<string.h>
函数功能:字符串比较:可以指定比较字符的个数;
参数解读:
1.string1 --- 被比较的字符串;
2.string2 --- 待比较的字符串;
3.size_t count --- 指定 比较多少个字符 (从前向后比较)
比较方法:
1.当 str1 < str2 返回负数
2.当 str1 = str2 返回0
3.当 str1 > str2 返回正数
举例:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "ABCD";
char str2[] = "ABCE";
int ret = strncmp(str1, str2,3);
if (ret > 0)
{
printf("ret=%d:str1>str2\n", ret);
}
else if (ret < 0)
{
printf("ret=%d:str1<str2\n", ret);
}
else
{
printf("ret=%d:str1=str2\n", ret);
}
return 0;
}
三、其他字符串函数
1.strstr函数
函数原型:char *strstr( const char *string, const char *strCharSet );
头 文 件:<string.h>
函数功能:字符串查找:在string中查找strCharSet是否存在;
参数解读:
1.string --- 被搜索的以空结尾的字符串;
2.strCharSet --- 要搜索的以空结尾的字符串;
注意事项:
1.当找到时:返回一个指针 strCharSet 在string中第一次出现的那个位置;
2.未找到时:返回一个空指针(NULL);
举例:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "ABCD";
char str2[] = "BC";
char str3[] = "HaHa";
if (strstr(str1, str2) != NULL)
{
printf("找到了\n");
}
else
{
printf("找不到\n");
}
return 0;
}
2.strtok函数
函数原型:char *strtok( char *strToken, const char *strDelimit );
头 文 件:<string.h>
函数功能:字符串切分
功能:
1.sep参数是个字符串,定义了用作分隔符的字符集合
2.第一个参数指定一个字符,它包含0个或多个由sep字符串中一个或多个分隔符分割的标记
3.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
6.如果字符串中不存在更多的标记,则返回 NULL 指针
举例:
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "zhangsan@school.student";
char arr2[100] = { 0 };
char sep[] = "@.";
strcpy(arr2, arr1);
char* ret = NULL;
for (ret = strtok(arr2, sep); ret != NULL;ret=strtok(NULL,sep))
{
printf("%s\n", ret);
}
return 0;
}
四、内存操作函数
1.memcpy函数
函数原型:void *memcpy( void *dest, const void *src, size_t count );
头 文 件:<memory.h>or<string.h>
函数功能:内存拷贝:(适用于内存不重叠的场景)
功能:
1.函数memcpy从src的位置开始向后复制count个字节的数据到dest的内存位置;
2.这个函数在遇到 \0 的时候并不会停下来;
3.如果source和destination有任何重叠,复制的结果都是未定义的;
举例:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr1, arr1 + 4, 16);
//arr1+2是指向5的,从这个位置向后16个字节的数据存到arr1向后16个字节
//也就是把5 6 7 8 拷贝到1 2 3 4 上去
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
return 0;
}
2.memmove 函数
函数原型:void *memmove( void *dest, const void *src, size_t count );
头 文 件:<string.h>
函数功能:内存拷贝:(适用于内存重叠或不重叠的场景)
注意事项:
1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
2.如果源空间和目标空间出现重叠,就得使用memmove函数处理
举例:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1, arr1 + 2, 16);
//arr1+2是指向3的,从这个位置向后16个字节的数据存到arr1向后16个字节
//也就是把3 4 5 6 拷贝到1 2 3 4 上去(这里就是内存重叠了,重叠的位置是3 4)
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
return 0;
}
3.memcmp函数
函数原型:int memcmp( const void *buf1, const void *buf2, size_t count );
头 文 件:<memory.h>or<string.h>
函数功能:内存比较:(比较buf1和buf2指针开始的num个字节)
比较方法:
1.当buf1<buf2时 返回<0
2.当buf1=buf2时 返回=0
3.当buf1>buf2时 返回>0
举例:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,3,6,6 };
int ret = memcmp(arr1, arr2, 12);
//这里向后比较12个字节,就是比较1 2 3
if (ret > 0)
{
printf("ret=%d arr1>arr2\n", ret);
}
else if (ret < 0)
{
printf("ret=%d arr1<arr2\n", ret);
}
else
{
printf("ret=%d arr1=arr2\n", ret);
}
return 0;
}
4.memset函数
函数原型:void *memset( void *dest, int c, size_t count );
头 文 件:<memory.h>or<string.h>
函数功能:内存设置(memset函数将dest的第一个count个字节设置为字符c)
举例:
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "almost every programmer should know memset!";
memset(str, '-', 6);//从起始位置开始向后6个字节的内容改为 '-'
puts(str);
return 0;
}
五、库函数的模拟实现
1.模拟实现strlen函数
①递归实现
#include <stdio.h>
int my_strlen(const char* pa)
{
if (*pa != '\0')
{
return 1 + my_strlen(pa + 1);//1+1+1+1+1+1+0
}
else
{
return 0;
}
}
int main()
{
char arr[] = "abcdef";
int ret = my_strlen(arr);
printf("arr的长度为:%d\n", ret);
return 0;
}
②计数器实现
#include <stdio.h>
int my_strlen(const char* pa)
{
int count = 0;
for (int i = 0; pa[i] != '\0'; i++)
{
count++;//只要不等于 \0 就加一
}
return count;
}
int main()
{
char arr[] = "abcdef";
int ret = my_strlen(arr);
printf("arr的长度为:%d\n", ret);
return 0;
}
③指针 - 指针
#include <stdio.h>
int my_strlen(const char* pa)
{
char* pa1 = pa;//先保存首元素的地址
while (*pa1)
{
pa1++;//去找 \0 的地址
}
return pa1 - pa;//pa1是 \0 的地址,pa是首元素的地址;相减就得到元素个数
}
int main()
{
char arr[] = "abcdef";
int ret = my_strlen(arr);
printf("arr的长度为:%d\n", ret);
return 0;
}
2.模拟实现strcpy函数
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);//断言 --- 判断这两个指针是否为空
char* ret = dest;
while (*dest++ = *src++)//直接赋值,直到遇到'\0'就停下
{
;
}
return ret;
}
int main()
{
char arr1[20] = "xxxxxx";
char arr2[] = "Hello";
printf("拷贝前为:%s\n", arr1);
char* ret = my_strcpy(arr1, arr2);
printf("拷贝后为:%s\n", ret);
return 0;
}
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);//断言 --- 判断这两个指针是否为空
int i = 0;
for (i = 0; src[i] != '\0'; i++)
{
dest[i] = src[i];//赋值,但是没有'\0'结束标志
}
dest[i] = '\0';//末尾添加一个'\0'
}
int main()
{
char arr1[20] = "xxxxxx";
char arr2[] = "Hello";
printf("拷贝前为:%s\n", arr1);
my_strcpy(arr1, arr2);
printf("拷贝后为:%s\n", arr1);
return 0;
}
3.模拟实现strcat函数
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);//断言 --- 判断这两个指针是否为空
while (*dest)
{
//先找到dest所指向的数组中'\0'的位置
dest++;
}
while (*src)
{
*dest++ = *src++;//进行追加
}
}
int main()
{
char arr1[20] = "Hello ";
char arr2[] = "World";
printf("追加前为:%s\n", arr1);
my_strcat(arr1, arr2);
printf("追加后为:%s\n", arr1);
return 0;
}
4.模拟实现strcmp函数
#include <stdio.h>
#include <assert.h>
int my_strcmp(char* str1, const char* str2)
{
assert(str1 && str2);//断言 --- 判断这两个指针是否为空
while (*str1==*str2)
{
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char arr1[] = "ABCDEF";
char arr2[] = "ABCDE";
int ret = my_strcmp(arr1, arr2);
if (ret > 0)
{
printf("ret = %d:arr1>arr2", ret);
}
else if (ret < 0)
{
printf("ret = %d:arr1<arr2", ret);
}
else
{
printf("ret = %d:arr1=arr2", ret);
}
return 0;
}
5.模拟实现strncpy函数
#include <stdio.h>
#include <assert.h>
char* my_strncpy(char *dest, const char *src,size_t count)
{
assert(dest && src);
char *ret = dest;
//1.拷贝字符串的个数
while (count && (*dest++ = *src++))
{
count--;
}
//2.不够的用\0补
if (count)
{
while (--count)
{
*dest++ = '\0';
}
}
return ret;
}
int main()
{
char arr1[20] = "xxxxxxxx";
char arr2[] = "Hello World";
printf("拷贝前为:%s\n", arr1);
char* ret = my_strncpy(arr1, arr2, 5);
printf("拷贝后为:%s\n", ret);
return 0;
}
6.模拟实现strncat函数
#include <stdio.h>
#include <assert.h>
char* my_strncat(char *dest, const char *src, int count)
{
assert(dest && src);
char *ret = dest;
//1.先找到\0的位置
while (*dest++)
{
;
}
dest--;
//2.将源字符串追加进去(根据指定的个数)
while (count--)
{
//3.只要不是\0就一直追加,追加到\0为止
if (!(*dest++ = *src++))
{
return ret;
}
}
*dest = '\0';
return ret;
}
int main()
{
char arr1[20] = "Hello ";
char arr2[] = "World";
printf("追加前的字符串为:%s\n", arr1);
char *ret = my_strncat(arr1, arr2, 8);
printf("追加后的字符串为:%s\n", ret);
return 0;
}
7.模拟实现strncmp函数
#include <stdio.h>
#include <assert.h>
int my_strncmp(char *str1, const char *str2, int count)
{
assert(str1 && str2);
while(count&&(*str1 == *str2))
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
count--;
}
return *str1 - *str2;
}
int main()
{
char arr1[] = "Hello";
char arr2[] = "Helld";
int ret = my_strncmp(arr1, arr2, 5);
if (ret > 0)
{
printf("ret = %d:arr1>arr2", ret);
}
else if (ret < 0)
{
printf("ret = %d:arr1<arr2", ret);
}
else
{
printf("ret = %d:arr1=arr2", ret);
}
return 0;
}
8.模拟实现strstr函数
#include <stdio.h>
#include <assert.h>
char* my_strstr(char* str1, const char* str2)
{
assert(str1 && str2);
char* s1;
char* s2;
char* cp = str1;
//如果传过来的是 \0
if (*str2 == '\0')
{
return str1;
}
//两种情况:
// arr1-- abcdef arr1-- abbbcdef
// 查找 arr2-- bcd arr2-- bbc
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cp;
}
cp++;
}
return NULL;//没有找到的情况
}
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bcd";
char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("找不到\n");
}
else
{
printf("找到了,是:%s\n", ret);
}
return 0;
}
9.模拟实现memcpy函数
#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*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memcpy(arr, arr + 4, 4 * sizeof(int));
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
10.模拟实现memmove函数
#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest, const void* src, size_t count)
{
assert(dest && src);
void* ret = dest;
if (dest < src)
{
//从前向后拷贝
while (count--)
{
//强制转换为char*,是为了让其一次访问一个字节的内容
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//从后向前拷贝
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr, arr + 2, 4 * sizeof(int));
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
11.模拟实现memcmp函数
#include <stdio.h>
#include <assert.h>
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
assert(ptr1 && ptr2);
//void* --- 无具体类型指针
//1.可以接受任意类型的指针
//2.但不能进行运算
//这里进行强制转换后就能够执行了
while (num&&(*(char*)ptr1== *(char*)ptr2))
{
if (*(char*)ptr1 == '\0')
{
return 0;
}
ptr1 = (char*)ptr1+1;
ptr2 = (char*)ptr2+1;
num--;
}
return *(char*)ptr1 - *(char*)ptr2;
}
int main()
{
char buf1[] = "ABCDEF";
char buf2[] = "ABCDGS";
int ret = my_memcmp(buf1, buf2, 4 * sizeof(char));
if (ret > 0)
{
printf("buf1>buf2\n");
}
else if (ret < 0)
{
printf("buf1\<buf2\n");
}
else
{
printf("buf1=buf2\n");
}
return 0;
}
12.模拟实现memset函数
#include <stdio.h>
#include <assert.h>
void* my_memset(void* ptr, int val, size_t num)
{
assert(ptr);
for (int i = 0; i < num; i++)
{
*((char*)ptr + i) = val;
}
return ptr;
}
int main()
{
char str[] = "almost every programmer should know memset!";
char ch = '-';
my_memset(str, ch, 6);
puts(str);
return 0;
}
六、总结
以上的这些库函数大部分使用较多,深入了解并牢牢掌握其功能,对于这方面的解题会得心应手,笔者可能在模拟实现上不一定是最优解,但是可以帮助大家从了解到掌握。