strlen
此函数接收一个char*类型参数,返回字符串\0前字符数,注意返回类型是size_t型的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//关于strlen返回值的一个易错点
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;
}
|
strlen模拟实现
法一
使用计数器
1
2
3
4
5
6
7
8
9
10
|
size_t my_strlen1( const char * str)
{
assert (str);
int count = 0;
while (*str++)
{
count++;
}
return count;
}
|
法二
指针相减
1
2
3
4
5
6
7
8
9
10
|
size_t my_strlen2( const char * str)
{
assert (str);
char * start = str;
while (*str!= '\0' ) //注意这种写法不能写*str++;这里要先判断再++;*str++的写法在'\0'的地方也+1了
{
str++;
}
return str - start; //\0与起始位置的差就是字符数
}
|
法三
递归,不适用临时变量
1
2
3
4
5
6
7
|
size_t my_strlen3( const char * str)
{
if ( '\0' == *str)
return 0;
else
return 1 + my_strlen3(str + 1);
}
|
strcpy
此函数接收两个char*类型参数,把后一个字符串拷贝到前一个字符串中,包括\0,注意前一个指针指向的数组空间要足够大,被拷贝的内容必须包含\0
strcpy的模拟实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
char * my_strcpy( char * dest, const char * src)
{
assert (dest && src);
char * ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello underworld" ; //注意写成数组
char arr2[20] = "hello world" ;
printf ( "%s\n" , arr2);
printf ( "%s\n" , my_strcpy(arr2, arr1));
return 0;
}
|
strcat
此函数接收两个char*参数,在前一个字符串\0的位置开始拷贝后一个字符串,直到后一个字符串的\0,返回前一个字符串首地址。注意要保证前一个指针指向的空间足够大
strcat的模拟实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
char * my_strcat( char * dest, const char * src)
{
char * ret = dest;
assert (dest && src);
while (*dest) //让dest到达str1的\0位置
{
dest++;
}
while (*dest++ = *src++) //这一部分和strcpy同
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello " ;
char arr2[20] = "underworld" ;
printf ( "%s\n" , my_strcat(arr1, arr2));
return 0;
}
|
strcmp
接收两个char*参数,依次比较每个字符,在第一个不相等的字符处比较他们的编码值,前者大则返回一个大于0的数,前者小则返回一个小于0的数,字符串完全相等则返回0
strcmp模拟实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
int my_strcmp( const char * str1, const char * str2)
{
while (*str1 == *str2)
{
if (*str1 == '\0' ) //说明两个字符串同时到达结束标记
return 0;
str1++;
str2++;
}
return *str1 - *str2; //如果不是在循环内部返回,就一定不相等,而字符相减可以反映大小
}
int main()
{
char *str1 = "hello world" ;
char *str2 = "hello underworld" ;
printf ( "%d\n" , my_strcmp(str1, str2)); //w比u大
return 0;
}
|
strstr
接收两个char*参数,返回第二个字符串在第一个字符串第一次出现的首位置指针
strstr模拟实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
char * my_strstr( const char * str1, const char * str2)
{
assert (str1 && str2);
char * s1; //s1维护str1
char * s2; //s2维护str2
char * cp = str1; //cp用来记录比较开始的位置
if (*str2 == '\0' ) //特殊情况
return str1;
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2) //其实*s1='\0'且*s2!='\0'时已经没有比较下去的必要了
//*s1==*s2就让两个维护指针分别+1;不等就让cp+1,s1和s2分别重置
{
s1++;
s2++;
}
if (*s2 == '\0' ) //*s2=='\0'说明找到了
{
return cp;
}
cp++;
}
return NULL;
}
|
应用KMP算法的strstr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
void get_next( char * str, int * next)
{
int i, k;
i = 0;
k = -1;
next[0] = -1; //这个值没用;或者说是为了使i增加而j不增加
int len = strlen (str);
while (i < len - 1) //next数组最大下标是字符串长度减1,数组长度和字符串长度相同
{
if (k == -1 || *(str + i) == *(str + k))
{
++i;
++k;
next[i] = k;
}
else
k = next[k];
}
//测试打印next
int z;
printf ( "next:" );
for (z = 0; z < len; z++)
{
printf ( "%d " , next[z]);
}
printf ( "\n" );
}
int Index_KMP( char * str1, char * str2, int pos)
{
int i = pos;
int j = 0;
int next[255];
get_next(str2, next);
int len1 = strlen (str1);
int len2 = strlen (str2);
int count = 0;
while (i < len1 && j < len2) //i从0到10(len1=11),共11次,但是考虑到走else的回溯,单字符查找一共循环22次
{
count++;
if (j == -1 || *(str1 + i) == *(str2 + j)) //先判断,再把下标加1
{
++i;
++j;
}
else
{
j = next[j];
}
}
printf ( "i=%d\n" , i);
printf ( "j=%d\n" , j);
printf ( "count=%d\n" , count); //是存在回溯的,那么这个函数的时间复杂度还是O(m)吗?
//if ((len2!=1) && (j >=(len2-1)))//有缺陷,对于len2=1的情况无法处理
if (j >= (len2 - 1)) //单字符查找情形,while结束时j=0,而len2-1也=0,故不能作为找到了的标志
//对于单字符查找以外的情形,len2-1一定大于0,len2-1代表的就是目标串最后一个字符的下标,既然j
//到达了这个位置,就说明完全匹配了
return i - len2; //由于字符串长度与数组下标的差异造成len2=1时
else
return 0;
}
int main()
{
char * str1 = "hello underworld!" ;
char * str2 = "under" ;
printf ( "%s\n" , my_strstr(str1, str2));
printf ( "%s\n" , *(str1+Index_KMP(str1, str2, 0)));
return 0;
}
|
strncpy
比strcpy多一个参数,描述拷贝的字节数,如果多于str2的长度,则会补0
1
2
3
4
5
6
7
8
9
10
11
12
13
|
int main()
{
char arr1[20] = "abcdefghi" ;
char arr2[] = "xxxx" ;
//strncpy(arr1, arr2, 6);//从arr2拷贝6个字符给arr1?如果arr2长度不够,则补0
//strncpy(arr1, arr2, 3);//长度不够不拷贝\0
//strncpy(arr1, arr2, 4);
strncpy (arr1, arr2, 5);
printf ( "%s\n" , arr1);
return 0;
}
|
strncat
比strcat多一个参数,最多只拷贝完整的str2(包括\0)
1
2
3
4
5
6
7
8
9
10
11
12
|
int main()
{
char arr1[20] = "abc\0xxxxxxx" ;
char arr2[] = "def" ;
//strncat(arr1, arr2, 6);//在arr1后面接上arr2的六个字符?最多只接arr2这么长的字符串,包括\0
//strncat(arr1, arr2, 3);//自己会加上\0
strncat (arr1, arr2, 2);
printf ( "%s\n" , arr1);
return 0;
}
|
strncmp
比strcmp多一个参数,描述比较的字节数
1
2
3
4
5
6
7
8
9
10
|
int main()
{
char arr1[] = "abcdew" ;
char arr2[] = "abcdeqj" ;
printf( "%d\n" ,strncmp(arr1, arr2, 5));
printf( "%d\n" ,strncmp(arr1, arr2, 6));
return 0;
}
|
strtok
字符串分割函数,接收两个char*参数,第一个是要被分割的字符串,第二个是分割符,分割符顺序不重要;第一个参数不为NULL时,返回分割的第一段;第一个参数为NULL,将从上个位置开始查找下一段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
int main()
{
char arr1[] = "cjh@scu.edu" ;
char arr2[100] = { 0 }; //保存临时数据
char sep[] = "@." ;
char * ret = NULL; //接收strtok的返回值
strcpy (arr2, arr1);
for (ret = strtok (arr2, sep); ret != NULL; ret = strtok (NULL, sep))
{
printf ( "%s\n" , ret);
}
return 0;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
int main()
{
char str[] = "- This, a sample string." ;
char * pch;
printf ( "Splitting string \"%s\" into tokens:\n" , str);
pch = strtok (str, ", .-" ); //分隔标记的位置不重要
while (pch != NULL)
{
printf ( "%s\n" , pch);
pch = strtok (NULL, " ,.-" ); //注意这里有空格
}
return 0;
}
|
memcpy
接收三个参数,第一个是char的目标位置,第二个是被拷贝的char的数据源,最后一个是size_t的拷贝字节数。注意标准未定义把自己的内容拷贝被自己的结果。
memcpy模拟实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
void * my_memcpy( void * dest, 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;
}
//printf("%d\n", count);//count=-1
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
my_memcpy(arr2, arr1, 10 * sizeof ( int ));
int i;
for (i = 0; i < 20; i++)
{
printf ( "%d " , arr2[i]);
}
return 0;
|
memmove
此函数原型和memcpy一样,包含额memcpy的功能,且可以处理把自己的内容拷贝给自己的情景
1
2
3
4
5
6
7
8
9
10
11
12
|
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "memmove can be very useful......" ;
printf ( "%c\n" , *(str + 15));
printf ( "%c\n" , *(str + 20));
memmove (str + 20, str + 15, 11); //注意memmove和memcpy不会遇到\0停下来,什么时候停取决于第三个参数
puts (str);
return 0;
}
|
memmove模拟实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
void * my_memmove( void * dest, void * src, size_t count) //关键在于拷贝之前先判断是否会出现overlap
{
void * ret = dest;
if (dest <= src || ( char *)dest >= (( char *)src + count))
{
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 arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr + 2, arr, 4 * sizeof ( int )); //1 2 1 2 3 4 7 8 9 10
//my_memcpy(arr + 2, arr, 4 * sizeof(int));//1 2 1 2 1 2 7 8 9 10
int i;
for (i = 0; i < 10; i++)
{
printf ( "%d " , arr[i]);
}
return 0;
}
|
memcmp
接收三个参数,前两个是void*型,指向被比较的两块内容,最后一个size_t的参数表示要比较多少字节
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#include <stdio.h>
#include <string.h>
int main()
{
char buffer1[] = "DWgaOtP12df0" ;
char buffer2[] = "DWGAOTP12DF0" ;
int n;
n = memcmp (buffer1, buffer2, sizeof (buffer1));
if (n > 0) printf ( "'%s' is greater than '%s'.\n" , buffer1, buffer2);
else if (n < 0) printf ( "'%s' is less than '%s'.\n" , buffer1, buffer2);
else printf ( "'%s' is the same as '%s'.\n" , buffer1, buffer2);
return 0;
}
|
字符分类函数
函数 如果他的参数符合下列条件就返回真
- iscntrl 任何控制字符
- isspace 空白字符:空格‘ ',换页‘\f',换行'\n',回车‘\r',制表符'\t'或者垂直制表符'\v'
- isdigit 十进制数字 0~9
- isxdigit 十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
- islower 小写字母a~z
- isupper 大写字母A~Z
- isalpha 字母az或AZ
- isalnum 字母或者数字,az,AZ,0~9
- ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
- isgraph 任何图形字符
- isprint 任何可打印字符,包括图形字符和空白字符
字符串换函数
- tolower()
- toupper()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#include <stdio.h>
int main ()
{
int i=0;
char str[]= "Test String.\n" ;
char c;
while (str[i])
{
c=str[i];
if ( isupper (c))
c= tolower (c);
putchar (c);
i++;
}
return 0; }
|
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注服务器之家的更多内容!
原文链接:https://blog.csdn.net/m0_56611833/article/details/120315753