前言:
一、字符分类函数
在C语言中,有一些常用的字符分类函数可以帮助我们对字符进行分类和判断。这些函数属于C标准库中的ctype.h头文件,并提供了对字符进行分类的功能。
(使用以下函数时都需要包含ctype.h头文件)
这些函数使用方法都大同小异,所以我就只举一个函数的使用例子来说明一下:
int islower(int c)
islower函数通过判断这里的c是否为小写字母而返回真值
下面来写一个代码排查一串大写字符中的小写字目母并将其改为大写字母:
#include<stdio.h>
#include<ctype.h>
//islower函数的使用举例
//islower函数可以判断是否为小写字符而返回真
int main()
{
char arr[] = "Hehe";
int i = 0;
char c = 0;
while (arr[i])
{
c = arr[i];
putchar(c);
i++;
}
printf("\n");
i = 0;
while(arr[i])
{
if (islower(arr[i]))//若为真,代表为小写字符,返回非零值,if条件满足进入if语句
{
arr[i]-=32;//减去32使小写字母变成大写字母
}
c = arr[i];
putchar(c);
i++;
}
return 0;
}
输出结果为:
Hehe
HEHE
二、字符转换函数
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写
在上面我们写了一串代码将小写字符转换为大写,有了这两个函数后,我们就可以直接转换了:
#include<stdio.h>
#include<ctype.h>
//islower函数的使用举例
//islower函数可以判断是否为小写字符而返回真
int main()
{
char arr[] = "Hehe";
int i = 0;
char c = 0;
while (arr[i])
{
c = arr[i];
if (islower(c))//若为真,代表为小写字符,返回非零值,if条件满足进入if语句
{
c = toupper(c);
}
putchar(c);
i++;
}
return 0;
}
三、常见字符函数
1、strlen的使用与模拟实现
size_t strlen( const char *string );
strlen的使用需要包含头文件string.h,且它使用时,所指向的的字符串必须包含结束标识'\0',返回一个size_t类型的整形.
strlen统计string指针所指向的字符串第一个结束标识'\0'前字符的数量,倘若一个字符串不包含'\0’,那strlen将会继续往后统计直到找到结束标识并返回统计的个数:
下面是一个简单举例:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "hello";
char arr2[] = { 'h','e','l','l','0' };
size_t a, b;//strlen函数返回值类型为size_t类型,最好用同类型来接收
a = strlen(arr1);
b = strlen(arr2);
printf("a=%zu,b=%zu", a, b);//size_t类型用%zu来转义
return 0;
}
arr1数组最后包含了结束标识'\0',于是统计出来时5,但arr2中并不包含,于是统计出来是一个大于等于5的随机值
a=5,b=37
接下来我们就可以用多个简单的c语言知识来模拟实现一下strlen函数,探究其怎么实现的内容:
size_t my_strlen(const char* p)
{
size_t count = 0;
while (*p)
{
count++;
*p++;
}
return count;
}
int main()
{
char arr1[] = "hello";
char arr2[] = { 'h','e','l','l','0' };
size_t a, b;
a = my_strlen(arr1);
b = my_strlen(arr2);
printf("a=%zu,b=%zu", a, b);
return 0;
}
这是一种普遍的模拟方式,当然为了函数的安全,也可以在函数定义里加上assert断言来判断形参指针p所指向的空间。
当然,也可以不创建临时变量,采用迭代的方式来模拟实现:
size_t my_strlen(const char* p)
{
if (*p == '\0')
return 0;
else
return 1 + my_strlen(p + 1);//采用迭代,数据量上去了可能会崩溃
}
2、strcpy的使用与模拟实现
char* strcpy(char * destination, const char * source );
在C语言中,strcpy是一个常用的字符串操作函数,用于将一个字符串复制到另一个字符串中。使用strcpy函数时需要注意以下几点:
1、源字符串必须以 '\0' 结束,在拷贝的时候,strcpy会将源字符串的'\0’一起拷贝到目标字符串。
2、⽬标空间必须足够大,以确保能存放源字符串,且目标空间必须可修改。
以下举个例子看看strcpy函数的使用,与strlen一样,使用前也需要包含头文件string.h.
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "hello";
char arr2[10] = { 0 };
strcpy(arr2, arr1);
int i = 0;
while (arr2[i])
{
printf("%c", arr2[i]);
i++;
}
return 0;
}
上述示例中,我们首先定义了一个源字符串arr1和一个目标字符串arr2。然后调用strcpy
函数将源字符串复制到目标字符串中。最后输出目标字符串的内容。
运行上述代码,输出结果为
hello
下面我们来实现一个类似于strcpy
函数的函数,名为my_strcpy:
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* str)
{
char* p = dest;//这一步尤其关键,因为该函数会返回一个地址,我们定义
//一个指针指向我们需要返回的地址
assert(dest != NULL);
assert(str != NULL);//p判断是否为空指针,要先声明头文件assert.h
while (*dest++ = *str++)//*的优先级大于++,每次给*dest赋值后向后移动
//直到*str变成'\0'条件为假
{
;
}
return p;//改地址指向原dest的首元素的地址
}
int main()
{
char arr1[] = "hello";
char arr2[10] = { 0 };
my_strcpy(arr2, arr1);
int i = 0;
while (arr2[i])
{
printf("%c", arr2[i]);
i++;
}
return 0;
}
运行上述代码,输出结果与前面的示例相同:
hello
3、strcat的使用与模拟实现
char* strcat(char* destination, const char* source);
strcat
函数接受两个参数:目标字符串destination
和源字符串source
。它将源字符串的内容追加到目标字符串的末尾,并返回指向目标字符串的指针。
在使用strcat时,必须注意以下几点:
1、源字符串必须以'\0’结尾,目标字符串也必须以'\0'结尾。
2、目标字符串的空间必须足够大,能够容纳源字符串,且目标字符串必须可以被改变。
3、不能让字符串自己追加自己。
以下我们来举个简单的例子来使用一下strcat:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[30] = "hello ";
char arr2[] = "world!";
strcat(arr1, arr2);
int i = 0;
while (arr1[i])
{
printf("%c", arr1[i]);
i++;
}
return 0;
}
在上面的代码中,我们调用strcat
函数将源字符串追加到目标字符串的末尾。最后输出目标字符串的内容。
hello world!
下面我们来实现一个类似于strcat
函数的函数,名为my_strcat
。这个函数的功能与strcat
相同,都是将源字符串追加到目标字符串的末尾:
char* my_strcat(char* dest, const char* sour)
{
char* str = dest;
while (*dest)
{
dest++;
}
while (*dest++ = *sour++)
{
;
}
return str;
}
int main()
{
char arr1[30] = "hello ";
char arr2[] = "world!";
my_strcat(arr1, arr2);
int i = 0;
while (arr1[i])
{
printf("%c", arr1[i]);
i++;
}
return 0;
}
在上述代码中,我们定义了一个my_strcat
函数,在第一个while
循环中找到目标字符串的末尾位置,然后使用指针遍历源字符串,将每个字符复制到目标字符串的末尾,并确保目标字符串正确终止。
运行代码,结果为:
hello world!
4、strcmp 的使用和模拟实现
int strcmp( const char *string1, const char *string2 );
strcmp比较两个字符串的长度,并根据不同的情况返回不同的值。会按照字典序比较两个字符串的大小,如果string1小于string2
,则返回一个负整数;如果string1
大于string2
,则返回一个正整数;如果两个字符串相等,则返回0。
#include<string.h>
int main()
{
char arr1[] = "abcd";
char arr2[] = "abcde";
char arr3[] = "abcb";
int a = strcmp(arr1, arr2);
if (a > 0)
{
printf("arr1大于arr2\n");
}
else if (a < 0)
{
printf("arr1小于arr2\n");
}
else
{
printf("arr1等于arr2\n");
}
int b = strcmp(arr1, arr3);
if (b > 0)
{
printf("arr1大于arr3\n");
}
else if (b < 0)
{
printf("arr1小于arr3\n");
}
else
{
printf("arr1等于arr3\n");
}
return 0;
}
运行结果为:
arr1小于arr2
arr1大于arr3
说明比较的原理确实是比较两个字符串中对应位置上字符ASCII码值的⼤⼩。
下面我们来实现一个类似于strcmp
函数的函数,名为my_strcmp
。这个函数的功能与strcmp
相同,都是比较两个字符串的大小关系:
#include<stido.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)//两个参数都用const修饰防止被修改
{
assert(str1 != NULL);
assert(str2 != NULL);
while (*str1 == *str2)
{
if (*str1 == '\0')//此时str2其实与str1相同
{
return 0;//一直到取到'\0'都相同,直接返回0
}
str1++;
str2++;
}
return *str1 - *str2;//直接相减,返回值若为正,则说明str1大于str2
}
int main()
{
char arr1[] = "abcd";
char arr2[] = "abcde";
int a = my_strcmp(arr1, arr2);
if (a > 0)
{
printf("arr1大于arr2\n");
}
else if (a < 0)
{
printf("arr1小于arr2\n");
}
else
{
printf("arr1等于arr2\n");
}
return 0;
}
运行上述代码,输出结果与前面的示例相同:
arr1小于arr2
5、strncpy的使用与模拟实现
在c语言中,strncpy是一个常见的字符串操作函数,用于将一个字符串的部分内容复制到另一个字符串中,它的使用与strcpy有相同之处,但不完全一样。
char * strncpy ( char * destination, const char * source, size_t num );
strncpy函数接受三个参数:目标字符串destination
、源字符串source
和要复制的字符数num
。它将source
字符串的最多num
个字符复制到destination
字符串中,并返回指向目标字符串的指针。
使用时要注意以下几点:
1、该函数是从source中拷贝num个字符到destination字符串中
2、如果源字符串的⻓度⼩于num,则拷贝完源字符串之后,在⽬标的后边追加0,直到num个。
3、目标字符串空间要足够大。
下面是一个strncpy函数的事例:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "hello worldwide";
char arr2[14];
char* str = strncpy(arr2, arr1, 11);
str[11] = '\0';//因为当num小于source的字符数时,不会复制'\0’到dest字符串中
//这里是手动给一个'\0'方便打印的时候打印结束
int i = 0;
while (str[i])
{
printf("%c", str[i]);
i++;
}
return 0;
}
运行上述代码,输出结果为:
hello world
下面我们来实现一个类似于strncpy
函数的函数,名为my_strncpy
。这个函数的功能与strncpy
相同,都是将源字符串的部分内容复制到目标字符串中。
char* my_strncpy(char* dest, const char* sour, size_t num)
{
char* str = dest;
while (*dest != '\0' && num > 0)
{
*dest++ = *sour++;
num--;
}//当num还未等于0时,还要继续赋值0
while (num > 0)
{
*dest = '\0';
dest++;
num--;
}
return str;
}
int main()
{
char arr1[] = "hello worldwide";
char arr2[14];
char* str = my_strncpy(arr2, arr1, 11);
str[11] = '\0';
int i = 0;
while (str[i])
{
printf("%c", str[i]);
i++;
}
return 0;
}
在上述代码中,我们定义了一个my_strncpy函数,使用指针遍历源字符串和目标字符串,并逐个字符进行复制,直到达到指定的字符数num
或源字符串结束。如果num
大于源字符串的长度,我们会在目标字符串中填充'\0'直到达到num个字符。
运行程序,结果一样:
hello world
6、strncat函数的使用与模拟实现
char * strncat ( char * destination, const char * source, size_t num );
strncat接受三个参数:目标字符串destination,源字符串source,与要追加的最大字符数num。它将source字符串中最多num个字符追加到destination的末尾,并返回指向目标字符串的指针。
使用时要注意以下几点:
1、strncat将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加⼀个 ‘\0’字符。
2、如果source 指向的字符串的⻓度⼩于num的时候,只会将字符串中到 '\0' 的内容追加到destination指向的字符串末尾。
下面是一个使用strncat函数的事例:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "hello";
char arr2[] = ",world!";
char* str = strncat(arr1, arr2, 7);
int i = 0;
while (str[i])
{
printf("%c", str[i]);
i++;
}
return 0;
运行程序:
hello,world!
下面我们来实现一个类似于strncat
函数的函数,名为my_strncat
。这个函数的功能与strncat
相同,都是将源字符串的部分内容追加到目标字符串的末尾。
char* my_strncat(char* dest, const char* sour, size_t num)
{
char* str = dest;
while (*dest != '\0')//找到dest字符串的末尾
{
dest++;
}
while (*sour != '\0' && num > 0)
{
*dest = *sour;
dest++;
sour++;
num--;
}
*dest = '\0';//手动赋予结束标志
return str;
}
int main()
{
char arr1[20] = "hello";
char arr2[] = ",world!";
char* str = my_strncat(arr1, arr2,8);
int i = 0;
while (str[i])
{
printf("%c", str[i]);
i++;
}
return 0;
}
在上述代码中,我们定义了一个my_strncat
函数,首先使用指针遍历目标字符串到末尾位置,然后使用指针遍历源字符串,并逐个字符进行追加,直到达到指定的字符数num
或源字符串结束。最后手动添加结束符\0
。
运行上述代码,输出结果与前面的示例相同:
hello,world!
7、strstr的使用与模拟实现
char * strstr ( const char * str1, const char * str2);
strstr函数接收两个参数str1,str2,它会在str1字符串中查找第一次str2字符串出现的位置,并返回一个指针指向该位置,若没有找到str2字符串,则会返回NULL指针。
下面是一个使用strstr
函数的示例:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "my name is Jack,What is your name?";
char arr2[] = "name";
char* str = strstr(arr1, arr2);
int i = 0;
while (str[i])
{
printf("%c", str[i]);
i++;
}
return 0;
}
运行上述代码,输出结果为:
name is Jack,What is your name?
需要注意的是,strstr
函数返回的指针指向源字符串中第一次出现子字符串的位置。
面我们来实现一个类似于strstr
函数的函数,名为my_strstr
。这个函数的功能与strstr
相同,都是在一个字符串中查找子字符串的位置。
char* my_strstr(const char* str1, const char* str2)
{
while (*str1 != '\0')//当str1遍历一遍后还未找到,就说明没有,直接返回NULL
{
const char* p1 = str1;
const char* p2 = str2;//
while (*str2 != '\0' && *p1 == *p2)
{
p1++;
p2++;
}
if (*p2 == '\0')
{
return (char*)str1;//当全部满足时返回此时str1的地址,由于返回应该是char*类型,所以还需要强制类型转化为char*
}
*str1++;//说明从这个地址出发找不到相同字符串,于是向后移动地址
}
return NULL;
}
int main()
{
char arr1[] = "my name is Jack,What is your name?";
char arr2[] = "name";
char* str = my_strstr(arr1, arr2);
int i = 0;
while (str[i])
{
printf("%c", str[i]);
i++;
}
return 0;
}
在上述代码中,我们定义了一个my_strstr函数,使用指针遍历源字符串,并逐个字符的开始比较。当查找到第一个相符合的字符时,内部循环开始了进一步的完全比较,如果完全匹配成功,就返回此时查找成功的首字符的地址,若一直没有成功,就返回NULL。
运行上述代码,输出结果与前面的示例相同:
name is Jack,What is your name?
接下里的函数,大多大同小异,我们就只是简单介绍一下这些函数使用实例:
8、strncmp函数的使用
int strncmp ( const char * str1, const char * str2, size_t num );
比较str1与str2的前num个字符,如果提前发现不相等,就提前结束。如果num个字符全部相同,则返回0。
#include<string.h>
int main()
{
char arr1[] = "abcdefgeg";
char arr2[] = "abcdefghi";
char arr3[] = "abcb";
int a = strncmp(arr1, arr2, 8);
if (a > 0)
{
printf("arr1大于arr2\n");
}
else if (a < 0)
{
printf("arr1小于arr2\n");
}
else
{
printf("arr1等于arr2\n");
}
int b = strncmp(arr1, arr3, 3);
if (b > 0)
{
printf("arr1大于arr3\n");
}
else if (b < 0)
{
printf("arr1小于arr3\n");
}
else
{
printf("arr1等于arr3\n");
}
return 0;
}
运行程序,结果如下:
arr1小于arr2
arr1等于arr3
9、strtok函数的使用
char * strtok ( char * str, const char * sep);
strtok函数的接收两个参数:被分割的字符串str,与分隔符sep。他会将str根据sep分隔符进行分割,并返回指向第一个字符串的指针,当再次调用strtok函数的时候,就会将NULL指针当做str参数,就可以获取下一个字符串。
使用该函数的时候需要注意以下几点:
1、sep参数指向了一个字符串,定义了用作分隔符的字符集合。
2、str指向一个字符串,包含了零个或多个包含了sep分隔符的字符
3、strtok找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串⼀般都是临时拷贝的内容 并且可修改。)
4、strtok的str参数不为NULL,strtok将会找到str中的第一个标记,strtok函数将会保存它在这个字符串的位置。
5、strtok的str参数为NULL,strtok将会从保存的位置开始,并查找下一个标记。
6、若字符串中不存在更多的标记,将会返回NULL指针。
我们举个例子来说明:
int main()
{
char arr1[] = "Hello, World! Nice to meet you.";
char* arr2 = strtok(arr1, " ,!.");
while (arr2 != NULL)
{
printf("%s\n", arr2);
arr2 = strtok(NULL, " ,!.");
}
return 0;
}
上述示例中,我们定义了一个字符串str
,其中包含了一些词汇和标点符号。然后通过多次调用strtok
函数来分割字符串。首先调用一次strtok
函数,传入要分割的字符串和分隔符,获取第一个子字符串的指针。然后使用循环和printf
函数输出每个子字符串的内容。在循环内部,通过再次调用strtok
函数并传入NULL来获取下一个子字符串。(注意,这里的sep字符串包含空格,逗号,感叹号,句号)
运行上述代码,结果为:
Hello
World
Nice
to
meet
you
需要注意的是,strtok
函数会修改原始字符串,并将分隔符替换成\0
,因此在后续调用时要传入NULL作为参数。
由于strtok函数是一个有状态的函数,它会记住上一次调用结束的位置,所以在多线程环境中使用时要小心。