9.1 字符串基础
字符串就是一串零个或多个字符,并且以一个位模式为全0的NUL字节结尾。
头文件string.h包含了使用字符串函数所需的原型和声明。
9.2 字符串长度
我们可以直接用库函数strlen来计算字符串长度。当然,我们也可以自己编写一个strlen函数:
#include <stdio.h> size_t strlen( char const *string ) { size_t len = 0; while ( *string++ != '\0' ){ len++; } return len; } int main(void) { char *str = "hello"; printf("%d\n", strlen( str ) ); return 0; }注意:strlen返回的是size_t类型,所以
strlen( x ) - strlen( y )永远大于等于0;
9.3 不受限制的字符串函数
9.3.1 复制字符串
char *strcpy( char *dst, char const *src );这个函数把参数src字符串复制到dst参数。如果参数src和dst在内存中出现重叠,其结果是未定义的。由于dst参数将进行修改,所以它必须是个字符数组或者是一个指向动态分配内存的数组的指针,不能使用字符串常量。
目标参数的以前内容将被覆盖并丢失。
我们可以自己编写类似strcpy的函数:
#include <stdio.h> void strcpy( char *dst, char const *src ) { while ( ( *dst++ = *src++ ) != '\0' ) ; } int main(void) { char dst[] = "i love this world"; char src[] = "hello world"; strcpy( dst, src ); printf("%s\n", dst ); return 0; }程序输出:
9.3.2 连接字符串
#include <stdio.h> void strcat( char *dst, char const *src ) { while ( *dst++ != '\0' ){ ; } dst--; while ( ( *dst++ = *src++ ) != '\0' ){ ; } } int main(void) { char *message = "fzyz.abc"; char result[1000] = ""; //要记得初始化 strcat( result, "hello " ); strcat( result, message ); strcat( result, ". how are you!" ); printf("%s\n", result ); return 0; }程序输出:
9.3.3 函数的返回值
strcpy和strcat都返回它们第一个参数的一份拷贝(我自己编写的返回void),就是指向目标字符数组的指针。但我们经常可以忽略这个返回值。
9.3.4 字符串比较
#include <stdio.h> int strcmp( char const *s1, char const *s2 ) { while ( ( *s1 != '\0' ) && ( *s2 != '\0' ) ){ if ( *s1 > *s2 ){ return 1; } else if ( *s1 < *s2 ){ return -1; } s1++; s2++; } if ( ( *s1 == '\0' ) && ( *s2 == '\0' ) ){ return 0; } if ( *s1 == '\0' ){ return -1; } return 1; } int main(void) { char *str1 = "hello"; char *str2 = "world"; char *str3 = "helloworld"; printf("%d\n", strcmp( str1, str2 ) ); printf("%d\n", strcmp( str2, str1 ) ); printf("%d\n", strcmp( str1, str3 ) ); return 0; }程序输出:
9.4 长度受限的字符串函数
1. strncpy
#include <stdio.h> char *strncpy( char *dst, char const *src, size_t len ) { char *temp = dst; while ( len && ( *dst++ = *src++ ) != '\0' ){ len--; //之所以把--放在代码块内而不是放在判断式中,是因为放在判断式中len将变成-1,而len为size_t型,故称为一个很大的正数 } while ( len > 0 ){ *dst++ = '\0'; len--; } return temp; } int main(void) { char dst[] = "i love python"; char *src = "hello"; // printf("%s\n", strncpy( dst, src, 6 ) ); printf("%s\n", strncpy( dst, src, 4 ) ); return 0; }程序输出:
2. strncat
#include <stdio.h> char *strncat( char *dst, char const *src, size_t len ) { char *temp = dst; while ( *dst++ != '\0' ){ ; } dst--; while ( len && ( *dst++ = *src++ ) != '\0' ){ len--; } while ( len > 0 ){ *dst++ = '\0'; len--; } return temp; } int main(void) { char dst[1000] = "hello "; char *src = " world "; printf("%s\n", strncat( dst, src, 4 ) ); printf("%s\n", strncat( dst, src, 6 ) ); return 0; }程序输出:
3. strncmp
#include <stdio.h> int strncmp( char const *s1, char const *s2, size_t len ) { while ( len && ( *s1 != '\0' ) && ( *s2 != '\0' ) ){ if ( *s1 > *s2 ){ return 1; } else if ( *s1 < *s2 ){ return -1; } s1++; s2++; len--; } if ( ( ( *s1 == '\0' ) && ( *s2 == '\0' ) ) || ( 0 == len ) ){ return 0; } if ( *s1 == '\0' ){ return -1; } return 1; } int main(void) { char *str1 = "hello"; char *str2 = "world"; char *str3 = "helloworld"; printf("%d\n", strncmp( str1, str2 , 4 ) ); printf("%d\n", strncmp( str2, str1 , 6 ) ); printf("%d\n", strncmp( str1, str3 , 5 ) ); return 0; }程序输出:
9.5字符串查找基础
9.5.1 查找一个字符
#include <stdio.h> char *strchr( char const *str, int ch ) { while ( *str != '\0' ){ if ( ch == *str ){ return str; } str++; } return NULL; } char *strrchr( char const *str, int ch ) { char *temp = str; while ( *temp != '\0' ){ temp++; } temp--; //这里不要尝试执行*( temp - 1 ) = '\0'; 因为str不可被修改的 while ( temp > str ){ if ( ch == *temp ){ return temp; } temp--; } return NULL; } int main(void) { char string[] = "hello there, honey"; printf("%s\n", strchr( string, 'h' ) ); printf("%s\n", strrchr( string, 'h' ) ); return 0; }
程序输出:
9.5.2 查找任何几个字符
#include <stdio.h> char *strpbrk( char const *str, char const *group ) { char *temp = str; while ( *group != '\0' ){ str = temp; while ( *str != '\0' ){ if ( *group == *str ){ return str; } str++; } group++; } return NULL; } int main(void) { char string[] = "hello there, honey"; char *ans; ans = strpbrk( string, "aeiou" ); printf("%s\n", ans ); return 0; }程序输出:
9.5.3 查找一个子串
#include <stdio.h> char const *strstr( char const *s1, char const *s2 ) { char const *temps1 = s1; char const *temps2 = s2; if ( "" == s2 ){ return s1; } while ( *s1 != '\0' ){ temps1 = s1; while ( *s1 == *s2 && *s1 != '\0' ){ s1++; s2++; } if ( *s2 == '\0' ){ return temps1; } else{ s2 = temps2; s1++; } } return NULL; } int main(void) { char s1[] = "hello world i love python"; printf("%s\n", strstr( s1, "i" ) ); printf("%s\n", strstr( s1, "LISP" ) ); printf("%s\n", strstr( s1, "" ) ); return 0; }程序输出:
我们也可以实现类似strrchr的strrstr:
#include <stdio.h> char const *strstr( char const *s1, char const *s2 ) { char const *temps1 = s1; char const *temps2 = s2; if ( "" == s2 ){ return s1; } while ( *s1 != '\0' ){ temps1 = s1; while ( *s1 == *s2 && *s1 != '\0' ){ s1++; s2++; } if ( *s2 == '\0' ){ return temps1; } else{ s2 = temps2; s1++; } } return NULL; } char const *strrstr( char const *s1, char const *s2 ) { char *last; char *current; last = NULL; if ( *s2 != '\0' ){ current = strstr( s1, s2 ); while ( current != NULL ){ last = current; current = strstr( last + 1, s2 ); } } return last; } int main(void) { char s1[] = "hello world i love this world and i love c,python too"; char *s2 = "world"; printf("%s\n", strrstr( s1, s2 ) ); return 0; }程序输出:
9.6 高级字符串查找
9.6.1 查找一个字符串前缀
#include <stdio.h> size_t strspn( char const *str, char const *group ) { size_t count = 0; char *temp = group; while ( *str != '\0' ){ group = temp; while ( *group != '\0' ){ if ( *str == *group ){ count++; break; } group++; } if ( *group == '\0' ){ break; } str++; } return count; } size_t strcspn( char const *str, char const *group ) { size_t count = 0; char *temp = group; while ( *str != '\0' ){ group = temp; while ( *group != '\0' ){ if ( *str == *group ){ return count; } group++; } if ( *group == '\0' ){ count++; } str++; } return count; } int main(void) { int len1; int len2; char buffer[] = "25,142,330,Smith,J,239-4123"; len1 = strspn( buffer, "0123456789" ); len2 = strspn( buffer, ",0123456789" ); printf("%d\n", len1 ); printf("%d\n", len2 ); len1 = strcspn( buffer, ",Smith"); len2 = strcspn( buffer, "Smith"); printf("%d\n", len1 ); printf("%d\n", len2 ); return 0; }程序输出:
9.6.2 查找标记
这是书上的例子,但是我不理解为什么strtok会保存状态呢?
#include <stdio.h> #include <string.h> int main(void) { char line[] = "hello\nworld i love"; static char whitespace[] = " \t\f\r\v\n"; char *token; for ( token = strtok( line, whitespace ); token != NULL; token = strtok( NULL, whitespace ) ){ printf("%s\n", token ); } return 0; }程序输出:
9.8 字符操作
9.8.1 字符分类
iscntrl 任何控制字符 isspace 空白字符 isdigit 十进制数 isxdigit 十六进制数 islower 小写字母 isupper 大写字母 isalpha 字母 isalnum 字母或数字 ispunct 标点符号 isgraph 任何图形文字 isprint 任何可打印字符9.8.2 字符转换
tolower----转换为大写
toupper----转换为小写
9.9 内存操作
void *memcpy( void *dst, void const *src, size_t length );和strcpy类似,只是遇到NUL不会停止
void *memmove( void *dst, void const *src, size_t length );和memcpy类似,但dst和src内存重叠时照样成功复制(先复制到临时内存中)
void *memcmp( void const *a, void const *b, size_t length );和strcmp类似
void *memchr( void const *a, int ch, size_t length );和strchr类似
void *memset( void *a, int ch, size_t length );将a中的前length数据初始化为ch。
习题:
1.
#include <stdio.h> #include <ctype.h> #include <string.h> int main(void) { int controlNum = 0; int spaceNum = 0; int digitNum = 0; int lowerNum = 0; int upperNum = 0; int punctNum = 0; int noPrintNum = 0; char *str = "^c hello1234WORLD,.?\\sa"; int len = strlen( str ); while ( *str != '\0' ){ if ( iscntrl( *str ) ){ controlNum++; } else if ( isspace( *str ) ){ spaceNum++; } else if ( isdigit( *str ) ){ digitNum++; } else if ( islower( *str ) ){ lowerNum++; } else if ( isupper( *str ) ){ upperNum++; } else if ( ispunct( *str ) ){ punctNum++; } else if ( !isprint( *str ) ){ noPrintNum++; } str++; } printf("control:%.2f%%\n", controlNum * 100.0 / len ); printf("space:%.2f%%\n", spaceNum * 100.0 / len ); printf("digit:%.2f%%\n", digitNum * 100.0 / len ); printf("lower:%.2f%%\n", lowerNum * 100.0 / len ); printf("upper:%.2f%%\n", upperNum * 100.0 / len ); printf("punct:%.2f%%\n", punctNum * 100.0 / len ); printf("noprint:%.2f%%\n", noPrintNum * 100.0 / len ); return 0; }
程序输出:
2.
size_t my_strlen( char const *str, size_t len ) { int length = 0; for ( length = 0; length < len; length++ ){ if ( *str++ == '\0'){ break; } } return length; }
3.
#include <stdio.h> char *my_strcpy( char *dst, char const *src ) { char *temp = dst; while ( *dst != '\0' ){ if ( ( *dst = *src++ ) != '\0' ){ dst++; } } return temp; } int main(void) { char dst[] = "hello world"; char *src = "i love this world"; printf("%s\n", my_strcpy( dst, src ) ); return 0; }
程序输出:
4. 如何保证不溢出??如果不传递数组的长度进去的话。
5.
#include <stdio.h> #include <string.h> char *my_strcat( char *dst, char const *src, int len ) { char *temp = dst; int subLen = strlen( dst ); while ( subLen < len ){ while ( *dst++ != '\0' ){ ; } dst--; while ( subLen < len ){ *dst++ = *src++; subLen++; } } dst--; *dst = '\0'; return temp; } int main(void) { char dst[30] = ""; printf("%s\n", my_strcat( dst, "hello wrold" , 30 ) ); printf("%s\n", my_strcat( dst, "i love this world" , 30 ) ); printf("%s\n", my_strcat( dst, "and i love c, python too" , 30 ) ); return 0; }程序输出:
6.
#include <stdio.h> char *my_strcpy_end( char *dst, char const *src ) { while ( ( *dst++ = *src++ ) != '\0' ){ ; } dst--; return dst; } int main(void) { char dst[] = "hello world"; char *src = "python"; printf("%s\n", my_strcpy_end( dst, src ) ); return 0; }
程序输出为空:
如果想判断真的返回NUL,只要把代码中dst--注释掉,则程序应该输出没被覆盖的字符串:
7.
#include <stdio.h> char *my_strrchr( char const *str, int ch ) { char *temp = str; while ( *temp != '\0'){ temp++; } while ( temp > str ){ if ( ch == *temp ){ return temp; } temp--; } return NULL; } int main(void) { char *src = "hello world i love this world"; printf("%s\n", my_strrchr( src, 'w' ) ); return 0; }
程序输出:
8.
#include <stdio.h> char *my_strnchr( char const *str, int ch, int which ) { while ( ( which ) && ( *str != '\0' ) ){ while ( *str++ != '\0' ){ if ( ch == *str ){ which--; break; } } } if ( !which ){ return str; } return NULL; } int main(void) { char *str = "hello world i love this wrold"; printf("%s\n", my_strnchr( str, 'l', 4 ) ); return 0; }
程序输出:
9.
#include <stdio.h> int count_chars( char const *str, char const *chars ) { size_t count = 0; char *temp = chars; while ( *str != '\0' ){ chars = temp; while ( *str == *chars ){ str++; chars++; } if ( *chars == '\0' ){ count++; continue; } str++; } return count; } int main(void) { char *str = "hello world i love this world and i love c, python too"; printf("%d\n", count_chars( str, "world" ) ); return 0; }
程序输出:
10.
#include <stdio.h> int palindrome( char *string ) { char *temp = string; while ( *temp != '\0' ){ temp++; } temp--; while ( temp > string ){ if ( tolower( *temp ) != tolower( *string ) ){ return 0; } temp--; string++; } return 1; } int main(void) { printf("%d\n", palindrome( "helloLLEH" ) ); printf("%d\n", palindrome( "hellooLEH" ) ); return 0; }
程序输出:
11.
#include <stdio.h> #include <string.h> int count_chars( char *src, char const *str ) { char *temp = str; char *startStr = src; //用于判断第一个就匹配并且不是以空格开始的字符串 int count = 0; int len = strlen( str ); while ( *src != '\0' ){ str = temp; while ( *src == *str ){ src++; str++; } if ( *str == '\0' && *src == ' ' && ( *(src - len - 1 ) == ' ' || ( src - startStr == len ) ) ){ count++; continue; } src++; } return count; } int main(void) { char src[100]; char *temp = src; while ( gets( src ) != NULL ){ printf("%d\n", count_chars( src, "the" ) ); } return 0; }
程序输出:
12.
#include <stdio.h> #include <ctype.h> void delSame( char *key ){ char *temp = key; char arr[27] = ""; int i = 0; while ( *key != '\0' ){ for ( i = 0; arr[i] != '\0'; i++ ){ if ( *key == arr[i] ){ break; } } if ( arr[i] == '\0' ){ arr[i] = *key; arr[i + 1] = '\0'; } key++; } for ( i = 0; arr[i] != '\0'; i++ ){ //C语言中由于数组名是指针常量,所以你无法一下子将一个数组复制给另一个数组,必须一一复制,字符串理解为字符数组 *temp++ = arr[i]; } *temp = '\0'; } int prepare_key( char *key ){ char ch; char alpha[26]; for ( ch = 'A'; ch != 'Z'; ch++ ){ alpha[ch - 'A'] = ch; } delSame( key ); while ( *key != '\0' ){ if ( !isalpha( *key ) ){ return 0; } *key = toupper( *key ); //千万不要写成*key++ = toupper( *key++ ) alpha[*key - 'A'] = ' '; key++; } for ( ch = 'A'; ch != 'Z'; ch++ ){ if ( alpha[ch - 'A'] == ' ' ){ continue; } *key++ = alpha[ch - 'A']; } return 1; } int main(void) { char key[27] = "TRAILBLAZERS"; prepare_key( key ); printf("%s\n", key ); return 0; }
程序输出:
13.
#include <stdio.h> #include <ctype.h> void delSame( char *key ){ char *temp = key; char arr[27] = ""; int i = 0; while ( *key != '\0' ){ for ( i = 0; arr[i] != '\0'; i++ ){ if ( *key == arr[i] ){ break; } } if ( arr[i] == '\0' ){ arr[i] = *key; arr[i + 1] = '\0'; } key++; } for ( i = 0; arr[i] != '\0'; i++ ){ //C语言中由于数组名是指针常量,所以你无法一下子将一个数组复制给另一个数组,必须一一复制,字符串理解为字符数组 *temp++ = arr[i]; } *temp = '\0'; } int prepare_key( char *key ){ char ch; char alpha[26]; for ( ch = 'A'; ch != 'Z'; ch++ ){ alpha[ch - 'A'] = ch; } delSame( key ); while ( *key != '\0' ){ if ( !isalpha( *key ) ){ return 0; } *key = toupper( *key ); //千万不要写成*key++ = toupper( *key++ ) alpha[*key - 'A'] = ' '; key++; } for ( ch = 'A'; ch != 'Z'; ch++ ){ if ( alpha[ch - 'A'] == ' ' ){ continue; } *key++ = alpha[ch - 'A']; } return 1; } void encrypt( char *data, char const *key ){ while ( *data != '\0' ){ if ( isupper( *data ) ){ *data = key[*data - 'A']; } else if ( islower( *data ) ){ *data = tolower( key[*data - 'a'] ); } data++; } } int main(void) { char key[27] = "TRAILBLAZERS"; char data[] = "ATTACK at DAwn"; prepare_key( key ); encrypt( data, key ); printf("%s\n", data ); return 0; }
程序输出:
14.
#include <stdio.h> #include <ctype.h> void delSame( char *key ){ char *temp = key; char arr[27] = ""; int i = 0; while ( *key != '\0' ){ for ( i = 0; arr[i] != '\0'; i++ ){ if ( *key == arr[i] ){ break; } } if ( arr[i] == '\0' ){ arr[i] = *key; arr[i + 1] = '\0'; } key++; } for ( i = 0; arr[i] != '\0'; i++ ){ //C语言中由于数组名是指针常量,所以你无法一下子将一个数组复制给另一个数组,必须一一复制,字符串理解为字符数组 *temp++ = arr[i]; } *temp = '\0'; } int prepare_key( char *key ){ char ch; char alpha[26]; for ( ch = 'A'; ch <= 'Z'; ch++ ){ alpha[ch - 'A'] = ch; } delSame( key ); while ( *key != '\0' ){ if ( !isalpha( *key ) ){ return 0; } *key = toupper( *key ); //千万不要写成*key++ = toupper( *key++ ) alpha[*key - 'A'] = ' '; key++; } for ( ch = 'A'; ch != 'Z'; ch++ ){ if ( alpha[ch - 'A'] == ' ' ){ continue; } *key++ = alpha[ch - 'A']; } return 1; } void encrypt( char *data, char const *key ){ while ( *data != '\0' ){ if ( isupper( *data ) ){ *data = key[*data - 'A']; } else if ( islower( *data ) ){ *data = tolower( key[*data - 'a'] ); } data++; } } void decrypt( char *data, char const *key ) { char alpha[26]; int i = 0; char ch; for ( ch = 'A'; ch <= 'Z'; ch++ ){ alpha[ch - 'A'] = ch; } while ( *data != '\0' ){ if ( isupper( *data ) ){ for ( i = 0; i < 26; i++ ){ if ( key[i] == *data ){ *data = alpha[i]; break; } } } else if ( islower( *data ) ){ for ( i = 0; i < 26; i++ ){ if ( key[i] == toupper( *data ) ){ *data = tolower( alpha[i] ); break; } } } data++; } } int main(void) { char key[27] = "TRAILBLAZERS"; char data[] = "ATTACK at DAwn"; prepare_key( key ); encrypt( data, key ); printf("%s\n", data ); decrypt( data, key ); printf("%s\n", data ); return 0; }
程序输出:
15.
#include <stdio.h> #include <string.h> void dollars( char *dest, char const *src ) { char *temp = src; char *tempDest = dest; int count = 0; //用于判断显示符号'.'和','。 while ( *temp != '\0' ){ temp++; } temp--; while ( temp >= src ){ if ( count == 2 ){ *dest = '.'; dest++; } else if ( ( count - 2 ) % 3 == 0 ){ *dest = ','; dest++; } *dest++ = *temp; temp--; count++; } *dest++ = '$'; *dest = '\0'; dest--; //不要把'\0'也放进去倒序 //对dest进行倒序 while ( tempDest < dest ){ char tempValue; tempValue = *tempDest; *tempDest++ = *dest; *dest-- = tempValue; } } int main(void) { char dest[20] = ""; char *src = "12345678"; dollars( dest, src ); printf("%s\n", dest ); return 0; }
程序输出:
16.
#include <stdio.h> #include <string.h> int format( char *format_string, char const *digit_string ) { int isDot = 0; char *temp_format_string = format_string; char *temp_digit_string = digit_string; char *temp_for_dot; //判断数字字符串为空 if ( "" == digit_string ){ return 0; } //进行倒序操作 while ( *temp_format_string != '\0' ){ temp_format_string++; } while ( *temp_digit_string != '\0' ){ temp_digit_string++; } temp_format_string--; temp_digit_string--; while ( ( temp_format_string >= format_string ) && ( temp_digit_string >= digit_string ) ){ if ( '#' == *temp_format_string ){ *temp_format_string = *temp_digit_string; } else if ( ',' == *temp_format_string ){ *temp_format_string = ','; temp_format_string--; continue; //保证copy','和'.'的时候数字字符串并为进行移位 } else if ( '.' == *temp_format_string ){ *temp_format_string = '.'; temp_format_string--; continue; } temp_format_string--; temp_digit_string--; } //数字个数大于格式化个数 if ( temp_digit_string >= digit_string ){ return 0; } temp_for_dot = temp_format_string; while ( temp_format_string >= format_string ){ if ( *temp_format_string == '.' ){ isDot = 1; break; } *temp_format_string--; } if ( isDot ){ while ( temp_for_dot >= format_string ){ if ( *temp_for_dot != '.' ){ *temp_for_dot = '0'; } else{ temp_for_dot--; *temp_for_dot = '0'; temp_for_dot--; while ( temp_for_dot >= format_string ){ *temp_for_dot = ' '; temp_for_dot--; } break; } temp_for_dot--; } } else{ while (temp_for_dot >= format_string ){ *temp_for_dot-- = ' '; } } } int main(void) { char format_string1[] = "#####"; char format_string2[] = "#####"; char format_string3[] = "##,###"; char format_string4[] = "##,###"; char format_string5[] = "##,###"; char format_string6[] = "#,###,###.##"; char format_string7[] = "#,###,###.##"; char format_string8[] = "#,###,###.##"; char format_string9[] = "#,###,###.##"; char format_string10[] = "#####.#####"; format( format_string1, "12345" ); format( format_string2, "123" ); format( format_string3, "1234" ); format( format_string4, "123" ); format( format_string5, "1234567" ); format( format_string6, "123456789" ); format( format_string7, "1234567" ); format( format_string8, "123" ); format( format_string9, "1" ); format( format_string10, "1" ); printf("%s\n", format_string1); printf("%s\n", format_string2); printf("%s\n", format_string3); printf("%s\n", format_string4); printf("%s\n", format_string5); printf("%s\n", format_string6); printf("%s\n", format_string7); printf("%s\n", format_string8); printf("%s\n", format_string9); printf("%s\n", format_string10); return 0; }
程序输出:
17.