字符串函数总结及模拟实现
1. 字符串函数总结
📖1.1 strlen
size_t strlen(const char* str);
- 字符串已
'\0'
作为结束标志,strlen
函数返回的是在字符串中'\0'
前面出现的字符个数(不包含'\0'
) - 参数指向的字符串必须要以’\0’结束
- 函数的返回值为
size_t
(无符号)
#include<stdio.h>
#include<string.h>
int main()
{
const char* str1 = "abcd";
const char* str2 = "aq";
if(strlen(str1) > strlen(str2))
{
printf("str1 bigger than str2\n");
}
else
{
printf("str2 bigger than str1\n");
}
return 0;
}
📖1.2 strcpy
char* strcpy(char* destination, const char* source);
- 源字符串必须以’\0’结束
- 会将源字符串的’\0’拷贝到目标空间
- 目标空间必须足够大,以确保能存放源字符串
- 目标空间必须可变
#include<stdio.h>
#include<string.h>
int main()
{
char str1[10] = "abcdef";
char str2[5] = "aaaa";
strcpy(str1, str2);
printf("%s\n", str1);
return 0;
}
📖1.3 strcat
char* strcat(char* destination, const char* source);
- 源字符串必须以’\0’结束
- 目标空间必须足够的大,能容纳下源字符串的内容
- 目标空间必须可修改
📖1.4 strcmp
int strcmp(const char* str1, const char* str2);
- 第一个字符串大于第二个字符串,则返回大于0的数字
- 第一个字符串等于第二个字符串,返回0
- 第一个字符串小于第二个字符串,则返回小于0的数字
#include<stdio.h>
#include<string.h>
int main()
{
char str1[10] = "abcde";
char str2[5] = "aaaa";
int ret = strcmp(str1, str2);
if(ret > 0)
{
printf("str1 > str2\n");
}
else if(ret == 0)
{
printf("str1 = str2\n");
}
else
{
printf("str1 < str2\n");
}
return 0;
}
📖1.5 strncpy
char* strncpy(char* destination, const char* source, size_t num);
- 拷贝
num
个字符从源字符串到目标空间 - 如果源字符串的长度小于
num
,则拷贝完源字符串后,在目标的后面追加'\0'
,直到num
个
#include<stdio.h>
#include<string.h>
int main()
{
char str1[10] = "abcde";
char str2[5] = "aaaa";
strncpy(str1, str2, 3);
printf("%s\n", str1);
return 0;
}
📖1.6 strncat
char* strncat(char* destination, const char* source, size_t num);
#include<stdio.h>
#include<string.h>
int main()
{
char str1[20] = "abcde";
char str2[5] = "aaaa";
strncat(str1, str2, 3);
printf("%s\n", str1);
return 0;
}
📖1.7 strncmp
#include<stdio.h>
#include<string.h>
int main()
{
char str1[20] = "abcde";
char str2[5] = "abcdf";
int ret = strncmp(str1, str2, 4);
printf("%d\n", ret);
return 0;
}
📖1.8 strstr
char* strstr(const char* str2, const char* str1);
#include<stdio.h>
#include<string.h>
int main()
{
char str1[20] = "abcd";
char str2[10] = "abcdf";
char* p = strstr(str2, str1);
printf("%s\n", p);
return 0;
}
📖1.9 strtok
char* strtok(char* str, const char* sep);
sep
是个字符串,定义了用作分隔符的字符集合- 第一个参数指定一个字符串,它包含了
0
个或者多个由sep
字符串中一个或多个分隔符分隔的标记 strtok
函数找到str
中的下一个标记,并将其用'\0'
结尾,返回一个指向这个标记的指针strtok
函数的第一个参数不为NULL
,函数将找到str
中的第一个标记,strtok
函数将保存它在字符串中的位置.strtok
函数的第一个参数为空NULL
,函数将在同一个字符串中被保存的位置开始,查找下一个标记- 如果字符串中不存在更多的标记,则返回空指针.
#include<stdio.h>
#include<string.h>
int main()
{
char* pstr = "2893992451@qq.com";
char arr[30];
const char* sep = "@.";
strcpy(arr, pstr);
char* str = NULL;
for(str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
{
printf("%s\n", str);
}
return 0;
}
📖1.10 strerror
char* strerror(int errnum);
功能:该函数返回错误码所对应的错误信息.
#include <stdio.h>
#include <string.h>
#include <errno.h>//必须包含的头文件
int main ()
{
FILE * pFile;
pFile = fopen ("unexist.ent","r");
if (pFile == NULL)
printf ("Error opening file unexist.ent: %s\n",strerror(errno));
//errno: Last error number
return 0;
}
📖1.11 memcpy
void* memcpy(void* destination, const void* source, size_t num)
- 函数
memcpy
从source
的位置开始向后复制num
个字节的数据到destination
的位置 - 这个函数在遇到
'\0'
的时候并不会停下来 - 如果
destination
和source
有任何的重叠,复制的结果都是未定义的
struct person
{
char name[20];
int age;
};
int main()
{
//拷贝字符串
struct person LiHua;
char name[] = "LiHua";
memcpy(LiHua.name, name, strlen(name) + 1);
LiHua.age = 10;
printf("%s %d\n", LiHua.name, LiHua.age);
//拷贝结构体
struct person copyPerson;
memcpy(©Person, &LiHua, sizeof(LiHua));
printf("%s %d\n", copyPerson.name, copyPerson.age);
return 0;
}
📖1.12 memmove
void* memmove(void* destination, const char* source, size_t num);
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
📖1.13 memcmp
int memcmp(const char* ptr1, const char* ptr2, size_t num);
- 比较从
ptr1
和ptr2
指针开始的num
个字节
int main()
{
char s1[] = "abcdefg";
char s2[] = "adcefg";
int ret = memcmp(s1, s2, 4);
if(ret > 0)
printf("s1 > s2\n");
else if(ret < 0)
printf("s1 < s2\n");
else
printf("s1 = s2\n");
return 0;
}
2. 字符分类函数总结
函数 | 如果它的参数符合下列条件就返回真 |
---|---|
iscntrl | 任何控制字符 |
isspace | 空白字符:空格' ' ,换页'\f' ,换行'\n' ,回车'\r' ,制表符'\t' ,或者垂直制表符'\v' |
isdigit | 十进制数字0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母a~ f,大写字母A~Z |
islower | 小写字母a~z |
isupper | 大写字母A~Z |
isalpha | 字母a~z 或A~Z |
isalnum | 所有字母或者数字 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
字符转换:
int tolower(int c);
int toupper(int c);
3. 字符串函数模拟实现
📖3.1 模拟实现strlen
第一种方式:
//计数器方式
int mystrlen(const char* str)
{
int count = 0;
while(*str)
{
count++;
str++;
}
return count;
}
第二种方式:
//使用递归
int mystrlen(const char* str)
{
if(*str == '\0')
return 0;
else
return mystrlen(str + 1) + 1;
}
第三种方式:
int mystrlen(const char* str)
{
const char* pstr = str;
while(*pstr != '\0')
pstr++;
return pstr - str;
}
📖3.2 模拟实现strcpy
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
assert(dest != NULL);
assert(src != NULL);
while(*dest++ = *src++)
;
return ret;
}
📖3.3 模拟实现strcat
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest != NULL);
assert(src != NULL);
while(*dest)
dest++;
while((*dest++ = *src++))
;
return ret;
}
📖3.4 模拟实现strstr
char* my_strstr(const char* str1, const char* str2)
{
char* cp = (char*)str1;
if(!*str2)
return (char*)str1;
char* s1, *s2;
while(*cp)
{
s1 = cp;
s2 = (char*)str2;
while(*s1 && *s2 && !(*s1 - *s2))
s1++, s2++;
if(!*s2)
return cp;
cp++;
}
return NULL;
}
📖3.5 模拟实现strcmp
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);
int ret = 0;
while(!(ret = *(unsigned char*)str1 - *(unsigned char*)str2) && *str1)
++str1, ++str2;
if(ret > 0)
ret = 1;
else if(ret < 0)
ret = -1;
return ret;
}
📖3.6 模拟实现memcpy
void* my_memcpy(void* dst, const void* src, size_t num)
{
assert(dst != NULL);
assert(src != NULL);
void* ret = dst;
while(num--)
{
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
return ret;
}
📖3.7 模拟实现memmove
void* my_memmove(void* dst, const void* src, size_t num)
{
assert(dst != NULL);
assert(src != NULL);
void* ret = dst;
if(dst <= src || (char*)dst >= (char*)src + num)
{
while(num--)
{
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
}
else
{
dst = (char*)dst + num - 1;
src = (char*)src + num - 1;
while(num--)
{
*(char*)dst = *(char*)src;
dst = (char*)dst - 1;
src = (char*)src - 1;
}
}
return ret;
}