C语言中对字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串或字符数组中。
C函数库中提供了一些专门处理字符串的函数,使用方便。几乎所有版本的C语言编译系统都提供这些函数。
字符串函数
strlen
size_t strlen ( const char * str );
参数:
str:指向的必须是C风格字符串,否则会出错。
返回值:size_t无符号长整型。返回结果为字符串中字符的个数,不包含'\0'。
模拟实现
#include <stdio.h>
size_t myStrlen(const char* str){
if(str == NULL || *str == '\0'){
return 0;
}
return 1 + myStrlen(str + 1);
}
int main(){
char* str = "hello, world!";
printf("The length of str is: %lu\n", myStrlen(str));
return 0;
}
运行结果
[[email protected] string]$ gcc my_strlen.c -o my_strlen
[[email protected] string]$ ./my_strlen
The length of str is: 13
strcpy
char * strcpy ( char * destination, const char * source );
参数:
destination:目标。
source:源。
返回值:destination。
注意:目标空间必须足够大。会将'\0'拷贝到目标空间。
模拟实现
#include <stdio.h>
char* myStrcpy(char* dest, const char* src){
if(src == NULL || *src == '\0'){
return dest;
}
char* temp = dest;
while(*src != '\0'){
*temp++ = *src++;
}
*temp = '\0';
return dest;
}
int main(){
char str[1024];
printf("str: %s\n", myStrcpy(str, "hello, world!"));
return 0;
}
运行结果
[[email protected] string]$ !gcc
gcc my_strcpy.c -o my_strcpy
[[email protected] string]$ ./my_strcpy
str: hello, world!
strcat
char * strcat ( char * destination, const char * source );
参数:
destination:目标。
source:源。
返回值:destination。
注意:目标空间必须足够大。字符串不能自己追加自己(会把'\0'覆盖掉,陷入死循环)。
模拟实现
#include <stdio.h>
char* myStrcat(char* dest, const char* src){
if(src == NULL || *src == '\0'){
return dest;
}
char* temp = dest;
while(*temp){
++temp;
}
while(*src){
*temp++ = *src++;
}
*temp = '\0';
return dest;
}
int main(){
char str[1024] = "hello, ";
printf("str: %s\n", myStrcat(str, "world!"));
return 0;
}
运行结果
[[email protected] string]$ gcc my_strcat.c -o my_strcat
[[email protected] string]$ ./my_strcat
str: hello, world!
strcmp
int strcmp ( const char * str1, const char * str2 );
参数:
str1:字符串1。
str2:字符串2。
返回值:str1 > str2,返回值大于0。str1 < str2,返回值小于0。str1 == str2,返回值等于0。
模拟实现
#include <stdio.h>
int myStrcmp(const char* str1, const char* str2){
while(*str1 == *str2 && *str1 != '\0'){
++str1;
++str2;
}
return *str1 - *str2;
}
int main(){
char str1[] = "hello";
char str2[] = "hello";
int flag = myStrcmp(str1, str2);
if(flag > 0){
printf("%s > %s\n", str1, str2);
}
else if(flag < 0){
printf("%s < %s\n", str1, str2);
}
else{
printf("%s == %s\n", str1, str2);
}
return 0;
}
运行结果
[[email protected] string]$ !gcc
gcc my_strcmp.c -o my_strcmp
[[email protected] string]$ ./my_strcmp
hello == hello
strncpy
char * strncpy ( char * destination, const char * source, size_t num );
参数:
destination:目标。
source:源。
num:字符个数。
返回值:destination。
注意:如果源字符串长度小于num,则拷贝完源字符串之后,在目标后面追加'\0',直到num个。
模拟实现
#include <stdio.h>
char* myStrncpy(char* dest, const char* src, size_t num){
if(src == NULL || *src == '\0'){
return dest;
}
char* temp = dest;
while(num && *src != '\0'){
*temp++ = *src++;
--num;
}
*temp = '\0';
return dest;
}
int main(){
char str[1024] = "hello, ";
printf("str: %s\n", myStrncpy(str, "world!", 6));
return 0;
}
运行结果
[[email protected] string]$ gcc my_strncpy.c -o my_strncpy
[[email protected] string]$ ./my_strncpy
str: world!
strncat
char * strncat ( char * destination, const char * source, size_t num );
参数:
destination:目标。
source:源。
num:字符个数。
返回值:destination被返回。
模拟实现
#include <stdio.h>
char* myStrncat(char* dest, const char* src, size_t num){
if(src == NULL || *src == '\0' || num == 0){
return dest;
}
char* temp = dest;
while(*temp){
++temp;
}
while(*src && num){
*temp++ = *src++;
--num;
}
*temp = '\0';
return dest;
}
int main(){
char str[1024] = "hello, ";
printf("str: %s\n", myStrncat(str, "world!", 6));
return 0;
}
运行结果
[[email protected] string]$ !gcc
gcc my_strncat.c -o my_strncat
[[email protected] string]$ ./my_strncat
str: hello, world!
strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
参数:
str1:字符串1。
str2:字符串2。
num:字符个数。
返回值:str1 > str2,返回值大于0;str1 < str2,返回值小于0;str1 == str2,返回值等于0。
模拟实现
#include <stdio.h>
int myStrncmp(const char* str1, const char* str2, size_t num){
while(*str1 == *str2 && *str1 && --num){
++str1;
++str2;
}
return *str1 - *str2;
}
int main(){
char str1[] = "hello";
char str2[] = "hello, world!";
int flag = myStrncmp(str1, str2, 5);
if(flag > 0){
printf("%s > %s\n", str1, str2);
}
else if(flag < 0){
printf("%s < %s\n", str1, str2);
}
else{
printf("%s = %s\n", str1, str2);
}
return 0;
}
运行结果
[[email protected] string]$ !gcc
gcc my_strncmp.c -o my_strncmp
[[email protected] string]$ ./my_strncmp
hello = hello, world!
strstr
const char * strstr ( const char * str1, const char * str2 );
char * strstr ( char * str1, const char * str2 );
参数:
str1:字符串1。
str2:字符串2。
返回值:str2第一次出现在str1中的位置。
模拟实现
#include <stdio.h>
const char* myStrstr(const char* str1, const char* str2){
while(*str1){
const char* temp1 = str1;
const char* temp2 = str2;
while(*temp1 == *temp2 && *temp1){
++temp1;
++temp2;
}
if(!*temp2){
return str1;
}
++str1;
}
return NULL;
}
int main(){
char str1[] = "hello, world!";
char str2[] = "world";
printf("%s\n", myStrstr(str1, str2));
return 0;
}
运行结果
[[email protected] string]$ !gcc
gcc my_strstr.c -o my_strstr
[[email protected] string]$ ./my_strstr
world!
strtok
char * strtok ( char * str, const char * delimiters );
参数:
str:字符串。
delimiters:分隔符集合。
用法:
- strtok函数第一个参数指定一个字符串,它包含了0个或者多个由delimiters字符串中一个或者多个分割符分割的标记。
-
strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
- strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
- 如果字符串中不存在更多的标记,则返回NULL指针。
代码演示
#include <stdio.h>
#include <string.h>
int main(){
char str[] = "- This, is .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;
}
运行结果
[[email protected] string]$ gcc strtok.c -o strtok
[[email protected] string]$ ./strtok
Splitting string "- This, is .a -sample string." into tokens:
This
is
a
sample
string
strerror
char * strerror ( int errnum );
参数:
errnum:错误码。
返回值:错误码所对应的错误信息。
代码演示
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(){
FILE* fp = fopen("unexist.txt", "r");
if(fp == NULL){
printf("fopen error: %s\n", strerror(errno));
}
return 0;
}
运行结果
[[email protected] string]$ gcc strerror.c -o strerror
[[email protected] string]$ ./strerror
fopen error: No such file or directory
字符分类函数
函数 | 参数符合下列条件返回真 |
---|---|
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 | 任何可打印字符,包括图形字符和空白字符 |
字符转换
int tolower ( int c );
int toupper ( int c );
代码演示
#include <stdio.h>
#include <ctype.h>
int main(){
char low, up;
printf("Please input the lower and upper character: \n");
scanf("%c %c", &low, &up);
printf("toupper: %c\n", toupper(low));
printf("tolower: %c\n", tolower(up));
return 0;
}
运行结果
[[email protected] string]$ !gcc
gcc low_up.c -o low_up
[[email protected] string]$ ./low_up
Please input the lower and upper character:
c A
toupper: C
tolower: a
内存函数
memcpy
void * memcpy ( void * destination, const void * source, size_t num );
参数:
destination:目标。
source:源。
num:字节数。
返回值:destination。
注意:遇到'\0'不会停下来。如果source和destination右任何的重叠,复制的结果是未定义的。
模拟实现
#include <stdio.h>
#define N 5
void* myMemcpy(void* dest, void* src, size_t num){
char* temp_dest = (char*)dest;
char* temp_src = (char*)src;
while(num){
*temp_dest++ = *temp_src++;
--num;
}
return dest;
}
int main(){
int arr[N] = {
0, 1, 2, 3, 4
};
int dest[N] = {0};
myMemcpy(dest, arr, N * sizeof(int));
int i;
for(i = 0; i < N; ++i){
printf("%d ", dest[i]);
}
printf("\n");
return 0;
}
运行结果
[[email protected] string]$ !gcc
gcc memcpy.c -o memcpy
[[email protected] string]$ ./memcpy
0 1 2 3 4
memmove
void * memmove ( void * destination, const void * source, size_t num );
参数:
destination:目标。
source:源。
num:字节数。
返回值:destination。
注意:destination和source空间可以出现重叠。
模拟实现
#include <stdio.h>
#define N 5
void* myMemcpy(void* dest, void* src, size_t num){
char* temp_dest = (char*)dest;
char* temp_src = (char*)src;
while(num){
*temp_dest++ = *temp_src++;
--num;
}
return dest;
}
void* myMemmove(void* dest, void* src, size_t num){
if(dest >= src && dest <= src + num){
char* temp_dest = (char*)dest;
char* temp_src = (char*)src;
int i = num - 1;
for(i = num; i >= 0; --i){
temp_dest[i] = temp_src[i];
}
}
else{
myMemcpy(dest, src, num);
}
return dest;
}
int main(){
int arr[N] = {
0, 1, 2, 3, 4
};
int dest[N] = {0};
myMemmove(dest, arr, N * sizeof(int));
int i = 0;
for(; i < N; ++i){
printf("%d ", dest[i]);
}
printf("\n");
return 0;
}
运行结果
[[email protected] string]$ gcc memmove.c -o memmove
[[email protected] string]$ ./memmove
0 1 2 3 4