书山有路勤为径,学海无涯苦作舟。 创作不易,宝子们!如果这篇文章对你们有帮助的话,别忘了给个免费的赞哟~
C语言中有一系列的函数是对字符进行分类的,就是对判断一个字符属于什么类型的字符,这类字符函数的使用都要包含一个头文件ctype.h。
这些函数的使用方法非常类似,这里我们就只举一个例子。
int islower ( int c );
在C语言中,islower是一个用于判断字符是否为小写字母的函数。该函数接受一个整数参数c,它应该是无符号字符或EOF(常量)。如果参数c是小写字母,则返回非零值(真);否则返回0(假)。
【示例】将字符串中的小写字母转大写,其他字符不变。
#include<stdio.h>
#include<ctype.h>
int main()
{
char str[] = "Test String.\n";
int i = 0;
char c;
while (str[i])
{
c = str[i];
if (islower(c))
c -= 32; // 小写字母的ASCII码值减去32就等于它对应的大写字母的ASCII码
putchar(c);
i++;
}
return 0;
}
C语言提供了2个字符转换函数:
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写
在上面的示例中,我们将小写转大写,是-32完成的效果,有了转换函数,就可以直接使用 tolower 函 数。
#include<stdio.h>
#include<ctype.h>
int main()
{
char str[] = "Test String.\n";
int i = 0;
char c;
while (str[i])
{
c = str[i];
if (islower(c))
c = toupper(c);
putchar(c);
i++;
}
return 0;
}
函数原型:
size_t strlen ( const char * str );
计算字符串的长度
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "abcdef";
size_t len = strlen(str1);
printf("%zu\n", len);
return 0;
}
方法一:计数器的方式实现
#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str) // const修饰,使其不能被修改
{
int count = 0;
assert(str); // 断言,避免传入空指针
while (*str)
{
count++; // 进入循环,说明不为空
str++;
}
return count;
}
int main()
{
char str1[] = "abcdef";
int len = my_strlen(str1);
printf("%d\n", len);
return 0;
}
方法二:递归实现
#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str1)
{
assert(str1); // 断言,避免传入空指针
if (*str1 == '\0')
return 0; // 等于'\0',说明字符串结束,直接返回
else
return 1 + my_strlen(str1 + 1);
}
int main()
{
char str1[] = "abcdef";
int len = my_strlen(str1);
printf("%d\n", len);
return 0;
}
方法三:指针 - 指针的方式实现
#include<stdio.h>
int my_strlen(char* s)
{
char* p = s;
while (*p != '\0')
p++;
return p - s;
}
int main()
{
int len = my_strlen("abcdef");
printf("%d\n", len);
return 0;
}
函数原型:
char* strcpy(char * destination, const char * source );
将source指向的C字符串复制到destination指向的数组中,包括结束的null字符(并在该点停止)。
将str1中的内容拷贝到str2中去
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "hello world";
char str2[20] = { 0 };
strcpy(str2, str1); // 将str1中的内容拷贝到str2中去
printf("%s\n", str2);
return 0;
}
注意
:这里str2的空间必须得能够装下str1中的内容,也就是str2的空间要足够大
在模拟实现之前,首先我们要了解strcpy的实现原理,只有这样才会更加方便我们去模拟实现。那么,strcpy的实现原理是怎样的呢? 这里我们根据上面的代码进行修改再调试一下:
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "hello world";
char str2[20] = "xxxxxxxxxxxxxxxxxx";
strcpy(str2, str1);
printf("%s\n", str2);
return 0;
}
str1中加上空格和字符串的结束标志 ‘\0’ 一共有12个字符,如果在str2中第12(下标为11)个字符也变成了 ‘\0’,那就说明是把str1中的 ‘\0’ 搬到了str2中。
事实证明strcpy的确是这样实现字符串拷贝的,所以我们在模拟实现时要一直将字符串拿到 ‘\0’ 才能结束。
注意
:
接下来我们来一步一步模拟strcpy函数
void my_strcpy(char* dest, char* src)
{
while (*src != '\0') // 拷贝'\0'之前的内容
{
*dest = *src;
dest++;
src++;
}
*dest = *src; // 拷贝'\0'
}
这样其实也能模拟实现,但这样的代码明显还有很多缺陷,还有很多优化的空间。
char* my_strcpy(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
while (*dest++ = *src++)
;
return ret;
}
这是最终优化后的代码,大家看到这里可能会有点懵,别急,我们慢慢来:
#include<assert.h>
#include<stdio.h>
#include<ctype.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 str1[] = "hello world";
char str2[20] = "xxxxxxxxxxxxxxxxxx";
my_strcpy(str2, str1);
printf("%s\n", str2);
char * ret = my_strcpy(str2, str1);
printf("%s\n", ret);
return 0;
}
函数原型:
char * strcat ( char * destination, const char * source );
连接字符串 将原字符串的副本追加到目标字符串。destination中的结束null字符被source的第一个字符覆盖,并且在destination中由两者串联形成的新字符串的末尾包含一个空字符。
将arr2中的字符串追加到arr2后面去。
#include<stdio.h>
#include<string.h>
int main()
{
// 注意数组空间大小,要足以容纳追加后的字符数量
char arr1[20] = "hello ";
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
注意
:这里arr1的空间必须得能够装下arr2追加到arr1后中的内容,也就是arr1的空间要足够大。
和之前一样,在模拟实现之前我们先要了解strcat函数的实现原理。这里我们同样调试一下看看。
调试之后可以看到,追加的过程是从arr1中的 \0开始追加,但是arr2中的 \0并没有拷贝到arr1中。 根据strcat函数的实现原理我们来进行模拟实现:
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
assert(dest && src); // 断言判断传入的是否为空指针
char* ret = dest; // 记录dest的起始地址
// 找到目标空间的\0
while (*dest != '\0')
dest++;
// 拷贝追加
while (*dest++ = *src++)
;
return ret;
}
int main()
{
// 注意数组空间大小,要足以容纳追加后的字符数量
char arr1[20] = "hello ";
char arr2[] = "world";
// my_strcat(arr1, arr2);
char* ret = my_strcat(arr1, arr2);
printf("%s\n", arr1);
printf("%s\n", ret);
return 0;
}
和上面一样,调试之后我们知道被追加的字符串从 \0开始,但追加的字符串并不会将 \0给追加进来。
函数原型:
int strcmp ( const char * str1, const char * str2 );
比较两个字符串 比较C字符串str1和C字符串str2。这个函数执行字符的二进制比较。 这个函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续执行以下对,直到字符不同或达到终止空字符为止。
比较三个字符串
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abd";
char arr3[] = "abcdef";
int ret1 = strcmp(arr1, arr2);
int ret2 = strcmp(arr1, arr3);
int ret3 = strcmp(arr2, arr3);
printf("%d\n", ret1);
printf("%d\n", ret2);
printf("%d\n", ret3);
return 0;
}
可以看到,标准里面的返回值是一个大于或小于0的数,但VS的编译器直接定为1和-1,其他编译器可能是返回一个大于0或小于0的数。
#include<stdio.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++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abd";
char arr3[] = "abcdef";
int ret1 = my_strcmp(arr1, arr2);
int ret2 = my_strcmp(arr1, arr3);
int ret3 = my_strcmp(arr2, arr3);
printf("%d\n", ret1);
printf("%d\n", ret2);
printf("%d\n", ret3);
return 0;
}
模拟后发现结果是一样的。
注意
:这只是在模拟VS编译器里的结果,模拟其他编译器上的结果更加简单,不相等时直接返回他们对应的ASCII码的差值就行了。
#include<stdio.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 arr1[] = "abcdef";
char arr2[] = "abs";
char arr3[] = "abcdef";
int ret1 = my_strcmp(arr1, arr2);
int ret2 = my_strcmp(arr1, arr3);
int ret3 = my_strcmp(arr2, arr3);
printf("%d\n", ret1);
printf("%d\n", ret2);
printf("%d\n", ret3);
return 0;
}