前言
本篇文章将介绍几种常用的对字符串进行操作的库函数,以及用C语言来实现这几种函数 废话不多说,下面开始
一、strlen
size_t strlen(const char* str);
求字符串的长度,包含头文件string.h
- strlen函数返回的是在字符串中
'\0' 前面出现的字符个数(不包括'\0' ) - 以
'\0' 结束
1.1 strlen的使用
#include <stdio.h>
#include<string.h>
int main()
{
const char*str1 = "abcdef";
const char*str2 = "bbb";
if(strlen(str2)-strlen(str1)>0)
{
printf("str2>str1\n");
}
else
{
printf("srt1>str2\n");
}
return 0;
}
运行结果:
1.2 strlen的实现
#include<stdio.h>
#Include<assert.h>
size_t my_strlen(const char* str)
{
assert(str);
const char* cur = str;
while (*cur++)
{
;
}
return cur - str - 1;
}
int main()
{
char* str = "abcdefg";
unsigned int len = my_strlen(str);
printf("%u\n", len);
return 0;
}
二、strcpy和strncpy
char* strcpy(char* dest , const char* src);
将scr字符串拷贝到dest字符串(包括'\0' ),包含头文件string.h
- dest目标字符串空间必须足够大,以确保能存放源字符串
- dest目标空间必须可变
char* strncpy(char* dest, const char* src,size_t num);
拷贝num个字符从src到dest字符串中,如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
2.1 strcpy和strncpy的使用
#include <stdio.h>
#include<string.h>
int main()
{
char str1[20] = "abcdef";
const char* str2 = "bbb";
char s1[20] = "abcdef";
const char* s2 = "bbb";
strcpy(str1, str2);
strncpy(s1, s2, 2);
printf("%s\n",str1);
printf("%s\n",s1);
return 0;
}
运行结果如下:
2.2 strcpy和strncpy的实现
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);
char* str1 = dest;
while (*dest++ = *src++)
{
;
}
return str1;
}
int main()
{
char str1[20] = "abcdefg";
const char* str2 = "ddd";
my_strcpy(str1,str2);
printf(str1);
return 0;
}
#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* dest,const char* src,size_t num)
{
assert(dest);
char* s1 = dest;
char* s2 = (char*)src;
while (num--)
{
*s1 = *s2;
s1++;
s2++;
}
return dest;
}
int main()
{
char str1[20] = "abcdefg";
const char* str2 = "xyzd";
my_strncpy(str1, str2, 4);
printf(str1);
return 0;
}
三、strcat和strncat
char * strcat ( char * dest, const char * src );
将src字符串追加到dest字符串中(包含src的’\0' ),包含头文件string.h
- dest空间必须足够大
- src是第一个首字符会覆盖掉dest的’\0’
char* strncat ( char * dest, const char* src, size_t num );
将src字符串的num个字节追加到dest字符串中
- 追加的字符不包含’\0’的,后尾补’\0’
- 如果src的长度小于num,则只复制到终止空字符的内容。
3.1 strcat和strncat的使用
#include <stdio.h>
#include <string.h>
int main()
{
char str1[20];
char str2[20];
char s1[20];
char s2[20];
strcpy(str1, "To be ");
strcpy(str2, "or not to be");
strcpy(s1, "To be ");
strcpy(s2, "or not to be");
strcat(str1, str2);
puts(str1);
strncat(s1, s2, 6);
puts(s1);
return 0;
}
运行结果:
3.2 strcat和strncat的实现
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* str1 = dest;
while(*dest)
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return str1;
}
int main()
{
char str1[20] = "abcdefg";
const char* str2 = "ddd";
my_strcat(str1,str2);
printf(str1);
return 0;
}
#include<stdio.h>
#include<assert.h>
char* my_strncat(char* dest, const char* src, size_t num)
{
assert(dest && src);
char* str1 = dest, * str2 = (char*)src;
while (*str1)
{
str1++;
}
while (num-- && *str)
{
*str1 = *str2;
str1++;
str2++;
}
*(str1 + 1) = '\0';
return dest;
}
int main()
{
char str1[20] = "abcdefg";
const char* str2 = "dddxassax";
my_strncat(str1, str2, 5);
printf(str1);
return 0;
}
四、strcmp和strncmp
int strcmp ( const char * str1, const char * str2 );
比较两个字符串的大小,包含头文件string.h
- 两个字符串自左到右逐个字符相比(ASCII值大小比较),直到遇见’\0’结束
- str1大于str2,返回大于0的数字
- str1小于str2,返回小于0的数字
- str1等于str2,返回0
int strncmp ( const char * str1, const char * str2,size_t num);
比较出现的字符大小直到一个字符串结束或者num个字符全部比较完
4.1 strcmp和strncmp的使用
#include <stdio.h>
#include<string.h>
int main()
{
const char* str1= "abcdefa";
const char* str2 = "abcdef";
if(strcmp(str1,str2) == 0)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
if(strncmp(str1,str2,6) == 0)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
return 0;
}
运行结果如下:
4.2 strcmp的实现
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* dest, const char* src)
{
int ret = 0;
assert(dest && src);
while (!(ret = *(unsigned char*)dest - *(unsigned char*)src) && *src
&& *dest)
{
src++;
dest++;
}
if (ret < 0)
return -1;
else if (ret > 0)
return 1;
else
return 0;
}
int main()
{
const char* str1 = "abcdef";
const char* str2 = "ybcdef";
if (my_strcmp(str1, str2) < 0)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
return 0;
}
五、strstr
char* strstr(const char* str1, const char* str2);
如果str2是str1的子串,则返回在str1中字串的首字符开始一直到’\0’,结束,如果不是返回NULL
5.1 strstr的使用
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "This is a simple string";
char* pch;
pch = strstr(str, "simple");
if(pch != NULL)
printf(pch);
return 0;
}
结果如下:
5.2 strstr的实现
#include <stdio.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
char* s1 = (char*)str1;
char* s2 = (char*)str2;
if (*s2 == '\0')
return s1;
while (*s1 != *s2)
{
s1++;
}
char* cp = s1;
while (*s1 && *s2 && !(*s1 - *s2))
{
s1++;
s2++;
}
if (!*s2)
{
return cp;
}
return NULL;
}
int main()
{
char str[] = "This is a simple string";
char* pch;
pch = my_strstr(str, "T");
if (pch != NULL)
printf(pch);
return 0;
}
六、strtok
char* strtok(char* str, const char* sep);
函数的作用是分解字符串,所谓分解,即没有生成新串,只是在str所指向的内容首次出现分界符的位置,将分界符修改成了’/0’,故第一次用strtok()返回第一个子串,包含头文件string.h
- 第一次提取子串完毕之后,继续对源字符串s进行提取,应在其后(第二次,第三次。。。第n次)的调用中将strtok的第一个参数赋为空值NULL(表示函数继续从上
一次调用隐式保存的位置,继续分解字符串;对于前一次次调用来说,第一次调用结束前用一个this指针指向了分界符的下一位 - 当this指针指向“\0” 时,即没有被分割的子串了,此时则返回NULL
- 可以把delim理解为分隔符的集合,delim中的字符均可以作为分隔符
- strtok在调用的时候,如果起始位置即为分隔符,则忽略了起始位置开始的分隔符
6.1 strtok的使用
int main()
{
char str[] = "This is a simple string";
char* pch = "s";
char* pch1 = strtok(str,pch);
while (pch1 != NULL)
{
printf("%s\n",pch1);
pch1 = strtok(NULL, pch);
}
return 0;
}
运行结果如下:
6.2 strtok的实现
char* strtok (char* str, const char* delim)
{
char table[256] = {0};
while (*delim != '\0')
{
table[*delim] = 1;
delim++;
}
static char* pstr = NULL;
if (str != NULL)
{
pstr = str;
}
while (*pstr != '\0' && table[*pstr] == 1)
{
pstr++;
}
char* rst = (*pstr != '\0') ? pstr : NULL;
while (*pstr != '\0')
{
if (table[*pstr] == 1)
{
*pstr++ = '\0';
break;
}
else
{
pstr++;
}
}
return rst;
}
七、strerror
char* strerror(int errnum);
strerror()用来依参数errnum 的错误代码来查询其错误原因的描述字符串, 然后将该字符串指针返回,返回描述错误原因的字符串指针,包含头文件string.h
- 在程序代码中包含 #include <errno.h>,然后每次程序调用失败的时候,系统会自动用用错误代码填充errno这个全局变量,这样你只需要读errno这个全局变量就可以获得失败原因了
- perror函数也是针对errno错误的.
7.1 strerror的使用
#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));
perror("open file failed\n");
}
return 0;
}
运行结果:
八、内存函数memcpy和memmove
void *memcpy( void *dest, const void *src, size_t count );
void *memmove( void *dest, const void *src, size_t count );
都是内存拷贝函数,src的count个字节拷贝到dest中,包含头文件string.h 它们的区别:
- 在拷贝自己时有重复的地方,memcpy不能处理重复地方的拷贝(VC自带的库函数可以)
- memmove可以处理有重复的地方
8.1 memcpy和memmove的实现
void* my_memcpy(void* dest,const void* src,size_t count)
{
void* ret = dest;
assert(dest && src);
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int a[5] = { 1,2,3,4,5 };
int b[] = { 16,7,8,9,10 };
my_memcpy(a+2, a+1, 12);
for (int i = 0; i < 5; i++)
{
printf("%d ", a[i]);
}
return 0;
}
有重复的地方发生了覆盖,正常应该为1,2,2,3,4
#include <stdio.h>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t count)
{
assert(dest && src);
void* ret = dest;
if (src > dest)
{
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
dest = (char*)dest + count - 1;
src = (char*)src + count - 1;
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest - 1;
src = (char*)src - 1;
}
}
return ret;
}
int main()
{
int a[5] = { 1,2,3,4,5 };
int b[] = { 16,7,8,9,10 };
my_memmove(a + 2, a + 1, 12);
for (int i = 0; i < 5; i++)
{
printf("%d ", a[i]);
}
return 0;
}
九、常用字符函数
包含头文件ctype.h
函数 | 如果它的参数符合下列条件就返回真 |
---|
iscntrl | 任何控制字符 | isspace | 空白字符:空格’ ‘,换页’\f’,换行’\n’,回车’\r’,制表符’\t’或者垂直制表符’\v’ | isdigit | 十进制数字0-9 | isxdigit | 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A-F | islower | 小写字母a~z | isupper | 大写字母A~Z | isalpha | 字母a-z或A-Z | isalnum | 字母或者数字,a-z,A-Z,0-9 | ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) | isgraph | 任何图形字符 | isprint | 任何可打印字符,包括图形字符和空白字符 |
|