1.字符函数
1.1字符分类函数
C语言有一系列用于分类字符的函数,需要包含头文件 ctype.h 展示如下
#include<ctype.h>
int main()
{
int ret = 0;
ret = iscntrl('\n');//任何控制字符
ret = isspace('\t');//空白字符,空格' ',制表符'\t',换行符'\n'等
ret = isdigit('9');//十进制数字0~9
ret = isxdigit('a');//十六进制数字0~9,a~f,A~F
ret = islower('c');//小写字母
ret = isupper('C');//大写字母
ret = isalpha('B');//所有大小写字母
ret = isalnum('8');//所有大小写字母和十进制数字
ret = ispunct('?');//标点符号(不属于字母数字的可打印的)
ret = isgraph('&');//任何图形字符
ret = isprint(' ');//任何可以打印的字符
return 0;
}
当参数部分符合要求时,会返回“真”。

1.2字符转换函数
C语言提供了两个字符转换函数:
int tolower(int c);//将字母大写转换为小写
int toupper(int c);//将字母小写转换为大写
具体的使用如下:
int main()
{
char arr2[] = "CIRNO";
int i = 0;
//把大写转化为小写
while (arr2[i]!='\0')
{
if (isupper(arr2[i]) )
{
arr2[i] = tolower(arr2[i]);
}
i++;
}
//打印
printf("%s\n", arr2);
return 0;
}
int main()
{
char arr1[] = "MineCraft";
int i = 0;
//把小写转化为大写
while (arr1[i] != '\0')
{
if (islower(arr1[i]))
{
arr1[i] = toupper(arr1[i]);
}
i++;
}
//打印
printf("%s\n", arr1);
return 0;
}
打印结果分别为
cirno
MINECRAFT
2.字符串函数
该类函数需要包含头文件string.h
2.1strlen的使用和模拟实现
size_t strlen(const char*str);
函数统计字符串中'\0'前的字符个数.
#include<string.h>
int main()
{
char arr[] = "minecraft";
printf("%zd", strlen(arr));
return 0;
}
最终打印结果为9.
需要注意的是返回的是无符号整型,创建变量接收和打印时需要注意变量类型。
以下是模拟实现,
size_t my_strlen(const char* str)
{
int count = 0;
while (*str++ != '\0')
{
count++;
}
return count;
}
2.2strcpy的使用和模拟实现
char* strcpy(char* destination,const char* source);
函数作用是复制一份字符串,返回值是目标函数的首地址。使用如下,
int main()
{
char arr1[] = "try to copy";
char arr2[20] = { 0 };
strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
使用时要注意目标函数是否有足够的空间来放置字符串。
以下是模拟实现,
char* my_strcpy(char* dest, const char* srce)
{
char* ret = dest;
while (*dest++=*srce++)
{
;
}
return ret;
}
int main()
{
char arr1[] = "minecraft";
char arr2[] = "xxxxxxxxxxxxxxxxxx";
char* ret = my_strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
需要注意的一点是,复制过来的字符串带了一个'\0'作为结尾,所以在打印时,只会出现minecraft不会出现额外的x.
2.3strcat的使用和模拟实现
char* strcpy(char* destination,const char* source);
函数将来源的字符串接到目标字符串后。
需要注意目标数组是否有足够的空间,返回的是目标函数的首地址.使用如下,
int main()
{
char arr1[20] = "hello ";
char arr2[20] = "world!";
strcat(arr1, arr2);
printf("%s\n", arr1);
reiturn 0;
}
结果如下:
hello world!
模拟实现时需要先让目标地址取到'\0',在进行类似strcpy的赋值操作.
char* my_strcat(char* dest, const char* srce)
{
char* ret = dest;
while (*dest != '\0')
dest++;
while (*dest++ = *srce++)
{
;
}
return ret;
}
2.4strcmp的使用和模拟实现
char* strcpy(char* destination,const char* source);
函数将两个字符串中的字符的ASCII的值分别进行比较,直到比出大小,返回值的正、负、0分别表示>、<、=,使用如下,
int main()
{
char arr1[20] = "abc";
char arr2[20] = "abd";
int ret = strcmp(arr1, arr2);
//打印值为一负数
printf("%d\n", ret);
return 0;
}
模拟实现如下,
int my_strcmp(const char* p1, const char* p2)
{
assert(p1 && p2);
//保护传来的指针
char* str1 = p1;
char* str2 = p2;
//跳过字符相同且不为字符'\0'的地址
while (*str1!='\0' && *str2!='\0' && * str1 == *str2)
{
str1++;
str2++;
}
//字符相同时相减得到对应的返回值
return *str1 - *str2;
}
2.5strncpy的使用和模拟实现
char* strcpy(char* destination,const char* source);
函数是从来源空间中取num个字符拷贝到目标空间中,返回值为目标空间的首地址.其中strncpy中的n可以记为为num,使用如下,
int main()
{
char arr1[] = "hello world!";
char arr2[20] = "minecraft";
strncpy(arr2, arr1, 5);
// 将会打印出helloraft
printf("%s\n", arr2);
return 0;
}
num限制了拷贝的字符个数,某种意义上增强了函数的安全性。
模拟实现类似strcpy,
char* my_strncpy(char* dest, const char* srce, size_t n)
{
//防止指针为空指针
assert(dest && srce);
char* ret = dest;
int i = 0;
//循环n次拷贝n个字符
for (i = 0; i < n; i++)
{
*dest = *srce;
dest++;
srce++;
}
return ret;
}
2.6strncat的使用和模拟实现
char* strcpy(char* destination,const char* source);
函数同理增加了一个衔接字符的个数限制,返回值为目标空间的首地址,使用如下,
int main()
{
char arr1[20] = "hello ";
char arr2[20] = "world";
strncat(arr1, arr2, 3);
//将会打印hello wor
printf("%s\n", arr1);
return 0;
}
模拟实现如下,
char* my_strncat(char* dest, const char* srce, size_t num)
{
assert(dest && srce);
char* ret = dest;
//使目标指针指向'\0'
while (*dest != '\0')
{
dest++;
}
//循环num次,拷贝num个字符到目标空间中
int i = 0;
for (i = 0; i < num; i++)
{
*dest++ = *srce++;
}
return ret;
}
2.7strncmp的使用
char* strcpy(char* destination,const char* source);
函数分别比较两个空间中的num个字符数,返回值体现大小,使用如下,
int main()
{
char arr1[] = "abcef";
char arr2[] = "abcdf";
int ret = strncmp(arr1, arr2, 3);//ret=0
ret = strncmp(arr1, arr2, 4);//ret>0
return 0;
}
2.8strstr的使用和模拟实现
char * strstr ( const char * str1, const char * str2);
函数将在指针str1指向的空间中寻找str指针指向空间的内容,找到了返回str1指向空间里找到的内容的起始指针,否则返回空指针。
int main()
{
char arr1[20] = "abbbcdef";
char arr2[] = "bbc";
char* ret = strstr(arr1, arr2);
//将会输出bbcdef
printf("%s", ret);
return 0;
}
模拟实现如下,
char* my_strstr(const char* dest, const char* sele)
{
//验证指针有效性
assert(dest && sele);
//保护目标指针,同时作为一个匹配基准点,用于移动
const char* cur = dest;
//当*cur为'\0'时结束循环
while (*cur)
{
const char* str1 = cur;
const char* str2 = sele;
//不相等时跳过匹配
if (*str1 != *str2)
{
str1++;
cur++;
}
//相等且不为空时进行匹配
while (*str1 == *str2 && *str1 != '\0' && *str2 != '\0')
{
str1++;
str2++;
}
//找到相同内容时指针指向'\0',此时返回目标指针现在指向的地址
if (*str2 == '\0')
{
return (char*) cur;
}
//否则匹配失败,目标指针++,继续寻找
else
{
cur++;
}
}
//结束循环的时候仍未返回值,说明未能找到,且此时*cur为空
return (char*)cur;
}
2.9strtok的使用
char * strtok ( char * str, const char * sep);
函数的作用是在一串字符串中去掉选择的分隔符(如@等)其中str是目标空间,sep是分隔符组成的字符或者字符串,函数一次只能去除一个分隔符(即在第一个分隔符位置放一个'\0',且返回值指向这个'\0'),若要再次去除只需要给str传入一个空指针(同样是删除一个),如果不存在分隔符,则返回NULL。看上去去除分隔符需要多次操作,但是我们可以有如下解法。
int main()
{
char arr[] = "114514.1919810.com";
char *sep = ".";
char* str = NULL;
for (str = strtok(arr, sep); str != NULL;str=strtok(NULL,sep))
{
//分别输出 114514 1919810 com
printf("%s\n", str);
}
return 0;
}
3.内存函数
3.1memcpy的使用和模拟实现
void * memcpy ( void * destination, const void * source, size_t num );
该函数功能和strncpy功能类似但是不在局限于字符数组,而且在拷贝时是一个字节一个字节进行拷贝。使用如下,
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
memcpy(arr2, arr1, 20);
int i = 0;
//最终打印结果是1 2 3 4 5 0 0 0 0 0
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
模拟实现如下,
void* my_memcpy(void* dest, const void* srce, size_t num)
{
assert(dest && srce);
//保存地址
void* ret = dest;
int i = 0;
while (num--)
{
//强制类型转换为char* 保证一次空间权限只有一个字节
*(char*)dest = *(char*)srce;
(char*)dest = (char*)dest + 1;
(char*)srce = (char*)srce + 1;
}
return ret;
}
这时候有人就要问了,如果在使用memcpy的时候传参的两个空间有重叠会发生什么。答案是不确定,因为编译器的实现的memcpy的方法不同,导致有的可以正常重叠,有些反之。但实际上,有一个专门用于实现重叠拷贝的函数——memmove.
3.2memmove的使用和模拟实现
void * memmove ( void * destination, const void * source, size_t num );
同样是拷贝内容,同样是逐字节拷贝,但它拷贝的是重叠空间以下是它的使用。
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
//将arr1开始的五个数拷贝到arr1+2开始的五个数处
memmove(arr1 + 2, arr1, 20);
//将arr2+2开始的五个数拷贝到arr2开始的五个数处
memmove(arr2, arr2 + 2, 20);
int i = 0;
//打印结果是1 2 1 2 3 4 5 8 9 10
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
//打印结果是3 4 5 6 7 6 7 8 9 10
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
模拟实现如下,
void* my_memmove(void* dest, const void* srce, size_t num)
{
assert(dest && srce);
void* ret = dest;
//当源空间地址小于目标空间的地址时,需要从后往前拷贝
if (*(char*)srce <= *(char*)dest)
{
while (num--)
{
*((char*)dest + num) = *((char*)srce + num);
}
}
//当源空间的地址大于目标空间的地址时,需要从前往后拷贝
else
{
while (num--)
{
*(char*)dest = *(char*)srce;
(char*)dest = (char*)dest + 1;
(char*)srce = (char*)srce + 1;
}
}
}
3.3memset的使用
void * memset ( void * ptr, int value, size_t num );
函数的作用是将num个字节在ptr指向的空间中改成value,如下
int main()
{
char arr[] = "hello world!";
memset(arr, 'x', 5);
//将会打印出 xxxxx world!
printf("%s\n", arr);
return 0;
}
3.4memcmp的使用
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
和strncmp类似,比较从ptr1和ptr2指向开始,向后的num个字节,返回值表示大小.
int main()
{
int a[5] = { 1,2,3,4,5 };
int b[10] = { 256,5,6,7,8 };
int ret=memcmp(a, b, 1);
//比较一个字节a为1,b为0;所以返回值>0
printf("%d\n", ret);
return 0;
}
最后的最后,咱才发现可以直接贴代码
1004

被折叠的 条评论
为什么被折叠?



