目录
一、字符函数
1. 字符分类函数
用于判断一个字符是否属于某种字符类型
这些函数的使用都需要包含头文件 ctype.h
| 函数 | 其参数符合下列条件就返回非零整数,否则返回0 |
|---|---|
| iscntrl | 任何控制字符如:整数输出控制字符%d、%-5d;字符串输出控制字符%s等 |
| isspace | 空格字符:空格“ ”,换页‘\f’,换行‘\n’,回车’\r,水平制表符’\t’,垂直制表符‘\v’ |
| isdigit | 十进制数字0~9 |
| isxdigit | 十六进制数字,包含所有十进制数字,小写字母a~f ,大写字母A~F |
| islower | 小写字母 |
| isupper | 大写字母 |
| isalnum | 字母或数字 |
| ispunct | 标点符号,任何不属于数字或字母的图形字符(可打印) |
| isgraph | 任何图形字符 |
| isprint | 任何可打印字符,包括图形字符和空白字符 |
举例:使用isspace函数判断‘ ’和‘\0’是否为空白字符
int isspace ( int ch );
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>
int main()
{
int ret1 = isspace(' ');
printf("ret1=%d\n", ret1);
int ret2 = isspace('\0');
printf("ret2=%d\n", ret2);
return 0;
}
运行结果为

说明“ ”是空白字符,‘\0’不是空白字符
2. 字符转换函数
这些函数的使用都需要包含头文件 ctype.h
int tolower ( int ch );//将参数穿进去的大写字母转小写
int toupper ( int ch );//将参数穿进去的小写字母转大写
举例:将一个字符串中的小写字母转成大写
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>
int main()
{
char arr[] = "LY_likun";
int i = 0;
char c = 0;
while (arr[i])//arr[i]为'\0'时,'\0'的ASCII码值为0,退出循环
{
c = arr[i];
if (islower(c))
{
c= toupper(c);
}
putchar(c);
i++;
}
return 0;
}
二、字符串函数
这些函数的使用都需要包含头文件 string.h
1. strlen的使用和模拟实现
size_t strlen ( const char* str );
①strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
②参数指向的字符串必须要以 ‘\0’ 结束。
③注意函数的返回值是size_t,是无符号整形(易错)
下面是strlen的一种模拟实现方法
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
//不创建临时变量模拟实现strlen
size_t my_strlen(const char* arr)
{
if (*arr == '\0')
return 0;
else
return 1 + my_strlen(arr + 1);
}
int main()
{
char* arr = "LY_likun";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
自己尝试尝试其他的模拟实现方式吧!
2. strcpy的使用和模拟实现
char* strcpy ( char* destination, const char* source );
①Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
②源字符串必须以 ‘\0’ 结束,会将源字符串中的 ‘\0’ 拷贝到目标空间。
③目标空间必须足够大,必须可修改
strcpy的使用:
int main()
{
char des[256] = {0};
char* src = "LY_likun";
strcpy(des, src);
printf("%s\n", des);//
return 0;
}
结果打印出LY_likun
模拟实现:
char* my_strcpy(char* des, const char* src)
{
assert(des);
assert(src);
char* ret = des;//用ret保存des起始位置的地址
while (*des++=*src++)
{
;
}
return ret;
}
int main()
{
char arr1[256] = "*****************";
char arr2[] = "LY_likun" ;
char* ret=my_strcpy(arr1, arr2);
printf("%s\n", ret);
printf("%s\n", my_strcpy(arr1, arr2));
printf("%s\n", arr1);
return 0;
}
结果打印出
LY_likun
LY_likun
LY_likun
3.strcat的使用和模拟实现
char* strcat ( char* dest,const char* src );
①Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
②目标字符串都必须有’\0’,否则不知道从哪里开始拼接。
③源字符串必须以’\0’结束,
④目标空间必须足够大,必须可修改
⑤字符串不能自己拼接自己
strcat的使用:
int main()
{
char dest[256] = "LY ";
char src[] = "likun";
strcat(dest, src);
printf("%s\n", dest);
return 0;
}
打印出LY likun
strcat的模拟实现:
char* my_strcat(char* dest, const char* src)
{
assert(dest&& src);
char* ret = dest;
while (*dest)
{
dest++;
}
//错误写法:while (*dest++); *dest是'\0'时,循环终止,后置++让dest+1,
//那么下一步“拼接”将在'\0'之后进行,LY \0likun\0,最终打印出来的是LY 。
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[256] = "LY ";
char arr2[] = "likun";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
结果打印出LY likun
为什么字符串不能自己拼接自己呢?
我们假设一个空间足够大的字符数组arr,其中存放着"abcd"字符串,并strcat(arr,arr)
结果如图

4.strcmp的使用和模拟实现
int strcmp ( const char* str1,const char* str2 );
①This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached.
②strcmp本质上在比较两个字符串对应位置上ASCII码值的大小。若str1>str2,返回大于0的数字;str1=str2,返回0;str1<str2,返回小于0的数字。
strcat的使用:
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcdef";
char arr3[] = "abbbbbbb";
char arr4[] = "abz";
printf("%d\n", strcmp(arr1, arr2));
printf("%d\n", strcmp(arr1, arr3));
printf("%d\n", strcmp(arr1, arr4));
return 0;
}
打印结果为
0
1
-1
strcat的模拟实现:
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1++ == *str2++ && *str1 != '\0')//当*str1与*str2不等时退出循环,或两者相等等于\0时退出循环
{
;
}
return *str1 - *str2;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcdzz";
int ret = my_strcmp(arr1, arr2);
printf("ret=%d\n", ret);
return 0;
}
打印结果为ret=-20
5.strncpy、strncat、strncmp的使用
char* strncpy ( char* dest,const char* src,size_t num );
①Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
②拷贝num个字符从源字符串到目标空间。
③如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
strncpy的使用:
int main()
{
char dest[256] = "xxxxxxxxxxxxxxx";
char src[] = "LY_likun";
strncpy(dest, src, 12);
return 0;
}

追加了三个0(‘\0’)
char* strncat ( char* dest,const char* src,size_t num );
①Appends the first num characters of source to destination, plus a terminating null-character.
If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.
②如果源字符串的长度小于num,只拼接到源字符串的’\0’
strcat的使用:
int main()
{
char dest[256] = "xxxxx\0xxxxxxxxxx";
char src[] = "LY_likun";
strncat(dest, src, 12);
return 0;
}

只拼接到源字符串的’\0’
int strncmp ( const char* str1,const char* str2,size_t num );
①Compares up to num characters of the C string str1 to those of the C string str2.
This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ, until a terminating null-character is reached, or until num characters match in both strings, whichever happens first.
②最多比较str1和str2的前num个字符,全部相等返回0、大于则返回一个大于零的整数,小于则返回一个小于零的整数
③如果两字符串一模一样但长度小于num,比较到两者’\0’位置为止。
strncmp的使用:
int main()
{
char* str1 = "abcddd";
char* str2 = "abceee";
int ret = strncmp(str1, str2, 3);
printf("%d\n", ret);
return 0;
}
打印结果为0
6.strstr的使用和模拟实现
char* strstr ( const char* str1,const char* str2 );
①Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
The matching process does not include the terminating null-characters, but it stops there.
②如果字符串str2是“\0”,则返回str1
strstr的使用:
int main()
{
char* str1 = "abcddefhdeg";
char* str2 = "de";
char* ret=strstr(str1, str2);
printf("%s\n", ret);
return 0;
}
打印结果为defhdeg
strstr的模拟实现:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <assert.h>
char* my_strstr(const char* str1, const char* str2)
{
const char* s1 = NULL;
const char* s2 = NULL;
assert(str1 && str2);
const char* wait = str1;
if (*str2 == '\0')
return (char*)str1;
while (*wait)
{
s1 = wait;
s2 = str2;
while (*s1 == *s2 && *s1 !='\0' && *s2 != '\0')//防止越界访问
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return wait;
}
wait++;
}
return NULL;
}
7.(扩展)strtok、strerror、perror的使用
strtok
char* strtok ( char* str,const char* sep);
①sep参数指向⼀个字符串,定义了用作分隔符的字符集合。例sep字符串"@。"分隔符有 @ 。两个
②strtok函数找到str中的下⼀个分隔符,替换为\0,返回⼀个指向这个分隔符的指针,并保存它在字符串中的位置
③strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个分隔符;
strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置之后,查找下⼀个分隔符
④如果查找一个分隔符时遇到\0,返回指向\0的指针,下一次返回NULL。
strtok的使用:
int main()
{
char str[] = "LY.likun@csdn.com";
char sep[] = "@.";
for (char* ret = strtok(str, sep); ret != NULL; ret = strtok(NULL, sep))
{
printf("%s", ret);
}
return 0;
}
打印结果为:LYlikuncsdncom
strerror
char* strerror( int errnum )
①strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。
②在不同的系统和C语言标准库的实现中都规定了⼀些错误码,⼀般是放在errno.h 这个头文件中说明的,(使用需要包含头文件 errno.h)C语言程序启动的时候就会使用⼀个全面的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在errno中,而⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。
strerror的使用:(理解即可)
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
for (int i = 0; i <= 10; i++)
{
printf("%d:%s\n", i, strerror(i));
}
return 0;
}
打印结果为:
0:No error
1:Operation not permitted
2:No such file or directory
3:No such process
4:Interrupted function call
5:Input/output error
6:No such device or address
7:Arg list too long
8:Exec format error
9:Bad file descriptor
10:No child processes
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
FILE* pFile;
pFile = fopen("unexist.ent", "r");
if (pFile == NULL)
printf("Error opening file unexist.ent: %s\n", strerror(errno));
return 0;
}
打印结果为:
Error opening file unexist.ent: No such file or directory
perror
void perror( const char* str );
①perror函数能直接将错误信息打印出来
②perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
FILE* pFile;
pFile = fopen("unexist.ent", "r");
if (pFile == NULL)
perror("Error opening file unexist.ent");
return 0;
}
打印结果为:
Error opening file unexist.ent: No such file or directory
三、内存操作函数
内存操作函数可以对任意类型的数据进行操作
这些函数的使用都需要包含头文件 string.h
memcpy
void* memcpy ( void* dest,const void* src,size_t num )
①函数memcpy从src的位置开始向后复制num个字节的数据到destination指向的内存位置。
②这个函数在遇到 ‘\0’ 的时候并不会停下来。
③src和dest不能有任何的重叠(不能包含相同地址)
例:
int src[] = { 1,2,3,4,5,6,7,8,9 };
//想让src[]={1,2,1,2,3,4,5,8,9};
memcpy(src+2, src, 5 * sizeof(src[0]));
//错误写法,前两个参数中指针会包含相同地址(3,4,5重叠)
//src会变成src[]={1,2,1,2,1,2,1,8,9};
memcpy的使用:
int main()
{
//把src里面的元素全部复制到dest里面
int dest[100] = { 0 };
int src[] = { 1,2,3,4,5,6,7,8,9 };
int sz = sizeof(src) / sizeof(src[0]);
memcpy(dest, src, sz * sizeof(src[0]));
for (int i = 0; i < sz; i++)
{
printf("%d ", dest[i]);
}
return 0;
}
打印结果为:1 2 3 4 5 6 7 8 9
memcpy的模拟实现:
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
memmove
void* memmove ( void* dest,const coid* src,size_t num )
①功能与memcpy相似
②和memcpy的差别是memmove函数处理的源内存块和目标内存块是可以重叠的。
③如果源空间和目标空间出现重叠,就得使用memmove函数处理。
memmove的使用:
int main()
{
int src[] = { 1,2,3,4,5,6,7,8,9 };
//要src[] = { 1,2,1,2,3,4,5,8,9 };
int sz = sizeof(src) / sizeof(src[0]);
memmove(src+2, src, 5* sizeof(src[0]));
for (int i = 0; i < sz; i++)
{
printf("%d ", src[i]);
}
return 0;
}
打印结果为:1 2 1 2 3 4 5 8 9
memmove的模拟实现:

那么令:
src<dest时,src从尾向到首移动
否则,src从首到尾移动
void* my_memmove(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest && src);
if (src < dest)
{
src = (char*)src + num - 1;//使src指向最后一个字节
dest = (char*)dest + num - 1;//使dest指向最后一个字节
while (num--)
{
//实现从尾到首移动
*(char*)dest = *(char*)src;
src = (char*)src - 1;
dest = (char*)dest - 1;
}
}
else
{
while (num--)
{
//实现从首到尾移动
*(char*)dest = *(char*)src;
src = (char*)src + 1;
dest = (char*)dest + 1;
}
}
return ret;
}
memset
void* memset ( void* ptt,int value,size_t num );
①memset是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容。
②注意是以字节为单位设置
memset的使用:
int main()
{
char arr[] = "LYlikunnnnnn";
memset(arr, 'n', 6 * sizeof(arr[0]));
printf("%s\n", arr);
return 0;
}
打印结果为:nnnnnnnnnnnn
int main()
{
int arr[] = {0,1,2,3,4,5,6,7,8,9};
int sz = sizeof(arr) / sizeof(arr[0]);
memset(arr, 0, sz*sizeof(arr[0]));
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
打印结果为:0 0 0 0 0 0 0 0 0 0
错误操作:
int main()
{
//想把arr中每个元素都设置为1
int arr[] = {0,1,2,3,4,5,6,7,8,9};
int sz = sizeof(arr) / sizeof(arr[0]);
memset(arr, 1, sz*sizeof(arr[0]));
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
打印结果如下图

因为memset以字节为单位进行操作,所以对一个整数进行置1操作时将其设置为0x 01 01 01 01,转换为十进制数是16843009
通常使用memset对整数数组进行置零操作
memcmp
int memcmp( const void* ptr1,const void* ptr2,size_t num );
①比较从ptr1和ptr2指针指向的位置开始,向后的num个字节(最多比较num个字节)
②ptr1>ptr2则返回1,ptr1=ptr2则返回0,ptr1<ptr2则返回-1
memcmp的使用:
int main()
{
int arr1[] = { 1,2,3,4,5,6 };
int arr2[] = { 1,2,3,8,8,8 };
int ret=memcmp(arr1, arr2, 5 * sizeof(arr1));
printf("%d\n", ret);
return 0;
}
打印结果为:-1
完~。
3414

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



