字符函数
一般需要包含ctype.h,用于字符操作。
字符分类函数
函数名 | 符合条件就返回真 |
---|---|
iscntrl | 任何控制字符 |
isspace | 空白字符,包括空格,换页,换行,回车,制表符等 |
isdigit | 十进制0~9 |
isxdigit | 包括十进制数字、小写字母a-f, 大写字母A-F |
islower | 小写字母a~z |
isupper | 大写字母A~Z |
isalpha | 字母 |
isalnum | 字母或者数字 |
ispunct | 标点符号 |
isgraph | 图形字符 |
isprint | 可打印字符,包括图形字符和空白字符 |
这类函数使用比较简单,仅举例说明:
写一段代码,将字符串中的小写字母转为大写,其余不变。思路很简单,判断一下字符串中的字符是否是小写,如果是,就转换为大写。
int main()
{
char str[] = "i am a Student";
int i = 0;
int len = strlen(str);
for (i=0;i<len;i++)
{
if (islower(str[i]))
{
str[i] -= 32;
}
}
printf("%s\n", str);
return 0;
}
字符串分类函数
包括两个:
int tolower ( int c ); //将参数传进去的小写字母转大写
int toupper ( int c ); //将参数传进去的大写字母转小写
功能就是将小写转大写或者大写转小写。有了这两个函数,可以对上述代码改造:
int main()
{
char str[] = "i am a Student";
int i = 0;
int len = strlen(str);
for (i=0;i<len;i++)
{
if (islower(str[i]))
{
str[i] = toupper(str[i]);
}
}
printf("%s\n", str);
return 0;
}
字符串函数
strlen的模拟实现
strlen
有以下几个特点需要注意:
- 字符串以
\0
作为结束标志,strlen
返回字符串中\0
之前的字符个数,不包括\0
; - 参数指向的字符串必须以
\0
结束 - 函数的返回值是size_t类型,是无符号的
看一下代码:
int main()
{
if (strlen("abc") - strlen("abcdef") > 0)
printf(">\n");
else
printf("<=\n");
return 0;
}
这里打印的是>
。因为-3作为一个无符号整型是一个非常大的数字。
想模拟实现strlen,一定注意上述的几个要点。想简单捋一下思路。strlen需要遍历字符串,碰到\0停止,遍历过程中需要有一个计数器来存储字符数量。那么简单写个代码:
版本1-easy way
size_t my_strlen(const char* str)
{
int count = 0;
assert(str != NULL);
while (*str != '\0')
{
count++;
str++;
}
return count;
}
版本2-pointer way
想到指针做差返回的是指针之间元素的个数:
size_t my_strlen(const char* str)
{
char* start = str;
while (*str != '\0')
{
str++;
}
return str -start;
}
版本3-recursion way
那么能不能不使用中间变量实现strlen
呢?其实是可以的,思路如下:
- 假设需要求
my_strlen("abcdef")
; - 可以简单拆分一下,
my_strlen("abcdef") = 1+ my_strlen(“bcdef”)
; - 继续这样拆分下去,直到碰到
\0
有了上述思路,就可以写代码了:
size_t my_strlen(const char* str)
{
assert(str != NULL);
if (*str != '\0')
return 1 + my_strlen(str+1);
else
return 0;
}
版本3是面试题。这里一定注意不要写成:
return 1 + my_strlen(str++);
后置++会先传str再++,str没有移动,所以会是死递归。
strcpy的模拟实现
先明确一下strcpy的功能和要点:
- 源字符串中必须包含
\0
,\0
也会被拷贝到目标空间 - 保证目标空间要足够大,能放得下源数据
- 保证目标空间可以修改。
然后想想思路:
- 遍历源字符串,判断是否为
\0
; - 如果不为
\0
,则将源字符串的当前遍历值赋值给目标字符串; - 最后将\0拷贝过去。
有了思路,就可以写代码了:
版本1-easy way
void my_strcpy(char* dest, char* src)
{
// \0之前的字符
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}
// \0拷贝
*dest = *src;
}
版本2-refine way
上述的代码比较冗余,很多东西都可以在循环判断里完成,而且可以加入断言和const关键字来保证函数的健壮性:
void my_strcpy(char* dest, const char* src)
{
assert(dest && src);
while (*dest++ = *src++)
{
;
}
}
版本3-final
这里回到库函数里的strcpy,它的返回值是起始地址,这样就可以直接用了:
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
while (*dest++ = *src++)
{
;
}
return ret;
}
strcat的模拟实现
strcat是将源字符串拼接到目标字符串上:
int main()
{
char arr1[20] = "hello ";
char* p = "world";
strcat(arr1, p);
printf("%s\n", arr1);
return 0;
}
这个代码执行的结果会打印hello world
。
注意几个要点:
- 源字符串中必须有\0;
- 目标字符串也需要有\0;
- 目标空间需要足够大;
- 目标空间可以修改。
有这些条件,思路就很简单了。首先找到源字符串里的\0,然后从这个位置开始拷贝,直到目标字符串的\0结束。有了上面strcpy的实现,strcat实现如下:
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
//1. 找到目标空间中的\0;
//2. copy
while (*dest != '\0')
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}