大纲 求字符串长度 strlen长度不受限制的字符串函数 strcpy strcat strcmp长度受限制的字符串函数介绍 strncpy strncat strncmp字符串查找 strstr strtok错误信息报告 strerror字符操作 内存操作函数 memcpy memmove memset memcmp
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型
的,字符串通常放在常量字符串
中 或者字符数组中。 字符串常量适用于那些对它不做修改
的字符串函数.
字符串类函数 strlen 1 size_t strlen ( const char * str ) ;
字符串以’\0’ 作为结束标志,strlen函数返回的是在字符串中’\0’ 前面出现的字符个数(不包含’\0’ )。
参数指向的字符串必须要以’\0’ 结束。
注意函数的返回值为size_t,是无符号的(易错)
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 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <assert.h> int my_strlen (const char * str) { int count = 0 ; assert(str != NULL ); while (*str != '\0' ) { count++; str++; } return count; }int main () { int len = my_strlen("abcdef" ); printf ("%d\n" , len); return 0 ; }
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 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> size_t my_strlen (const char * str) { int count = 0 ; assert(str != NULL ); while (*str != '\0' ) { count++; str++; } return count; }int main () { if (my_strlen("abc" ) - my_strlen("abcdef" ) > 0 ) { printf ("大于0\n" ); } else { printf ("小于0\n" ); } return 0 ; }
strcpy
字符串复制
strcpy把含有‘\0’ 结束符的字符串复制到另一个地址空间
1 char * strcpy (char * destination, const char * source ) ;
Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point)
源字符串必须以’\0’ 结束。
会将源字符串中的’\0’ 拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
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 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <assert.h> char * my_strcpy (char * dest, const char *src) { assert(dest != NULL ); assert(src != NULL ); char * ret = dest; while (*dest++ = *src++) { ; } return ret; }int main () { char arr1[] = "abcdefghi" ; char arr2[] = "bit" ; my_strcpy(arr1, arr2); printf ("%s\n" , arr1); return 0 ; }
strcat
将两个字符串连接(拼接)起来。
1 char * strcat ( char * destination, const char * source ) ;
Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
源字符串必须以’\0’ 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
1 2 3 4 5 6 7 8 9 10 11 12 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> int main () { char arr1[30 ] = "hel\0lo" ; char arr2[] = "world" ; strcat (arr1, arr2); printf ("%s\n" , arr1); return 0 ; }
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 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <assert.h> char * my_strcat (char *dest, const char *src) { char * ret = dest; assert(dest != NULL ); assert(src); while (*dest != '\0' ) { dest++; } while (*dest++ = *src++) { ; } return ret; }int main () { char arr1[30 ] = "hello" ; char arr2[] = "world" ; my_strcat(arr1, arr2); printf ("%s\n" , arr1); return 0 ; }
strcmp
两个字符串自左向右逐个字符相比(按 ASCII 值大小相比较),直到出现不同的字符或遇 \0 为止。
1 int strcmp ( const char * str1, const char * str2 ) ;
This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached.
标准规定: 第一个字符串大于第二个字符串,则返回大于0的数字 第一个字符串等于第二个字符串,则返回0 第一个字符串小于第二个字符串,则返回小于0的数字
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 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> int main () { char * p1 = "qbc" ; char * p2 = "abc" ; if (strcmp (p1, p2)>0 ) { printf ("p1>p2\n" ); } else if (strcmp (p1, p2) == 0 ) { printf ("pa == p2\n" ); } else if (strcmp (p1, p2)<0 ) { printf ("p1<p2\n" ); } return 0 ; }
strcmp实现 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 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <assert.h> int my_strcmp (const char * str1, const char * str2) { assert(str1 && str2); while (*str1 == *str2) { if (*str1 == '\0' ) { return 0 ; } str1++; str2++; } return (*str1 - *str2); }int main () { char * p1 = "abcdef" ; char * p2 = "abcd" ; int ret = my_strcmp(p1, p2); printf ("ret = %d\n" , ret); return 0 ; }
strncpy
strncpy()用来复制字符串的前n个字符
1 char * strncpy ( char * destination, const char * source, size_t num ) ;
Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
1 2 3 4 5 6 7 8 9 10 11 12 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> int main () { char arr1[10 ] = "abcdefgh" ; char arr2[] = "bit" ; strncpy (arr1, arr2, 6 ); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 char *my_strncpy (char *dest, const char *src, int count) { assert(dest&&src); while (count) { *dest++ = *src++; count--; } if (*(dest) != '\0' ) *(dest + 1 ) = '\0' ; return dest; }
🌐strcpy()与strncpy()的区别
strncat
在字符串的结尾追加n个字符。
1 char * strncat ( char * destination, const char * source, size_t num ) ;
将源的前num个字符附加到目标,再加上一个终止的空字符\0
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> int main () { char arr1[30 ] = "hello\0xxxxxxxxxxxxx" ; char arr2[] = "world" ; strncat (arr1, arr2, 3 ); printf ("%s\n" , arr1); return 0 ; }
如果source中的C字符串的长度小于num,则仅返回到终止空字符为止的内容已复制。
1 2 3 4 5 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h>
strncmp
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
1 int strncmp ( const char * str1, const char * str2, size_t num ) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> int main () { const char * p1 = "abczdef" ; char * p2 = "abcqwer" ; int ret = strncmp (p1, p2, 4 ); printf ("%d\n" , ret); return 0 ; }
strstr
在字符串中查找第一次出现字符串的位置,不包含终止符 ‘\0’。
1 char * strstr ( const char *, const char * ) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> int main () { char *p1 = "abcdef" ; char *p2 = "abc" ; char * ret = strstr (p1, p2); if (ret == NULL ) { printf ("字符串不存在\n" ); } else { printf ("%s\n" , ret); } return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main () { char *p1 = "abcdefabcdef" ; char *p2 = "def" ; char * ret = strstr (p1, p2); if (ret == NULL ) { printf ("字符串不存在\n" ); } else { printf ("%s\n" , ret); } return 0 ; }
自定义实现
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 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> #include <assert.h> char * my_strstr (const char * p1, const char * p2) { assert(p1 != NULL ); assert(p2 != NULL ); char *s1 = NULL ; char *s2 = NULL ; char *cur = (char *)p1; if (*p2 == '\0' ) { return (char *)p1; } while (*cur) { s1 = cur; s2 = (char *)p2; while (*s1 && *s2 && (*s1 == *s2)) { s1++; s2++; } if (*s2 == '\0' ) { return cur; } if (*s1 == '\0' ) { return NULL ; } cur++; } return NULL ; }int main () { char *p1 = "abcccdcdef" ; char *p2 = "ccd" ; char * ret = my_strstr(p1, p2); if (ret == NULL ) { printf ("子串不存在\n" ); } else { printf ("%s\n" , ret); } return 0 ; }
strtok
将字符串分割成一个个片段。
1 char * strtok ( char * str, const char * sep ) ;
sep参数是个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
strtok函数找到str中的下一个标记,并将其用\0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回NULL 指针。
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 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> int main () { char arr[] = "zpw@bitedu.tech" ; char *p = "@." ; char buf[1024 ] = { 0 }; strcpy (buf, arr); char *ret = strtok(arr, p); printf ("%s\n" , ret); ret = strtok(NULL , p); printf ("%s\n" , ret); ret = strtok(NULL , p); printf ("%s\n" , ret); return 0 ; }
改进 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 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> int main () { char arr[] = "zpw@bitedu.tech" ; char *p = "@." ; char buf[1024 ] = { 0 }; strcpy (buf, arr); char * ret = NULL ; for (ret = strtok(arr, p); ret != NULL ; ret=strtok(NULL , p)) { printf ("%s " , ret); } return 0 ; }
strerror
返回错误码,所对应的错误信息。
1 char * strerror ( int errnum ) ;
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 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> #include <errno.h> int main () { FILE* pf = fopen("test.txt" , "r" ); if (pf == NULL ) { printf ("%s\n" , strerror(errno)); } else { printf ("open file success\n" ); } 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
任何可打印字符,包括图形字符和空白字符
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 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> #include <ctype.h> int main () { char arr[] = "I Am A Student" ; int i = 0 ; while (arr[i]) { if (isupper (arr[i])) { arr[i] = tolower (arr[i]); } i++; } printf ("%s\n" , arr); return 0 ; }
内存操作函数 不局限于前面只能操作字符串的函数,还能处理浮点型,整型等等
memcpy
内存拷贝
1 void * memcpy ( void * destination, const void * source, size_t num ) ;
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到’\0’ 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
1 2 3 4 5 6 7 8 9 10 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> int main () { int arr1[] = { 1 , 2 , 3 , 4 , 5 }; int arr2[5 ] = { 0 }; memcpy (arr2, arr1, sizeof (arr1)); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> int main () { int arr1[] = { 1 , 2 , 3 , 4 , 5 }; int arr2[5 ] = { 0 }; struct S arr3 [] = { { "张三" , 20 }, { "李四" , 30 } }; struct S arr4 [3] = {0 }; memcpy (arr4, arr3, sizeof (arr3)); return 0 ; }
自定义实现 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 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> #include <assert.h> struct S { char name[20 ]; int age; };void * my_memcpy (void * dest, const void * src, size_t num) { void * ret = dest; assert(dest != NULL ); assert(src != NULL ); while (num--) { *(char *)dest = *(char *)src; ++(char *)dest; ++(char *)src; } return ret; }int main () { int arr1[] = { 1 , 2 , 3 , 4 , 5 }; int arr2[5 ] = { 0 }; struct S arr3 [] = { { "张三" , 20 }, { "李四" , 30 } }; struct S arr4 [3] = {0 }; my_memcpy(arr2, arr1, sizeof (arr1)); return 0 ; }
memmove
内存拷贝
1 void * memmove ( void * destination, const void * source, size_t num ) ;
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> int main () { int arr3[] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; memmove(arr3+2 , arr3, 20 ); memcpy (arr3+2 , arr3, 20 ); return 0 ; }
自定义实现 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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> #include <assert.h> void * my_memmove (void * dest, const void *src, size_t count) { void * ret = dest; assert(dest != NULL ); assert(src != NULL ); if (dest < src) { while (count--) { *(char *)dest = *(char *)src; ++(char *)dest; ++(char *)src; } } else { while (count--) { *((char *)dest + count) = *((char *)src + count); } } return ret; }int main () { int arr3[] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; my_memmove(arr3, arr3 + 2 , 20 ); return 0 ; }
memcmp
内存大小比较
1 int memcmp ( const void * ptr1, const void * ptr2, size_t num ) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #define _CRT_SECURE_NO_WARNINGS 1 #include <string.h> #include <stdio.h> int main () { int arr1[] = { 1 , 2 , 3 , 4 , 5 }; int arr2[] = { 1 , 2 , 5 , 4 , 3 }; int ret = memcmp (arr1, arr2, 9 ); printf ("%d\n" , ret); return 0 ; }
memset
内存设置 初始化内存
1 void *memset (void *str, int c, size_t n)
将指针变量 s 所指向的前 n 字节的内存单元用一个“整数” c 替换,注意 c 是 int 型。s 是 void* 型的指针变量,所以它可以为任何类型的数据进行初始化。
参数
str – 指向要填充的内存块。
c – 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
n – 要被设置为该值的字符数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #define _CRT_SECURE_NO_WARNINGS 1 #include <string.h> int main () { int arr[10 ] = { 0 }; memset (arr, 1 , 10 ); return 0 ; }