目录
1. 字符串函数
1.1 strlen
✨ 函数定义
size_t strlen ( const char * str );
✨ 函数作用 :计算一个字符串的长度
✨ 函数使用
int main()
{
char s[] = "qwerty"
size_t len = strlen(s); //但其实这里的类型应该是size_t(无符号)
printf("%zu", len); // 结果是6
return 0;
}
✨ 注意事项
- 字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )
- 参数指向的字符串必须要以 '\0' 结束
- 函数的返回值为size_t,是无符号的
✨ strlen模拟实现
//1.计数器
int my_print(const char* str)
{
assert(str);
int cnt = 0; //定义一个计数器
while (*str)
{
str++;
cnt++;
}
return cnt;
}
//2.递归
int my_print(const char* str)
{
assert(str);
if (!(*str)) //当*str为0时,返回0
{
return 0;
}
return 1 + my_print(str + 1);
}
//3.指针-指针
int my_print(const char* str)
{
assert(str);
const char* start = str; //保存字符串的起始地址
while (*str)
{
str++; //字符串结束标志 \0 的地址
}
return (int)(str - start);
}
1.2 strcpy
✨ 函数定义
char* strcpy(char * destination, const char * source );
✨ 函数作用 :将一个字符串从源(source)拷贝到目的(destination)
✨ 函数使用
int main()
{
char dest[] = "teststring";
char src[] = "aaaa";
printf("%s", strcpy(dest, src)); //strcpy的返回值是目标空间的起始地址
//结果是aaaa,后面的字符哪去了?原因是,strcpy拷贝时,将aaaa后面的\0一起拷过去了并覆盖一个字符,整个s里面是 aaaa\0tring\0
return 0;
}
✨ 注意事项
- 源字符串必须以 '\0' 结束
- 会将源字符串中的 '\0' 拷贝到目标空间
- 目标空间必须足够大,以确保能存放源字符串
- 目标空间必须可变
✨ strcpy模拟实现
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);
char* start = dest; //保存字符串的起始地址
while (*dest++ = *src++) //逐个拷贝字符串,当拷贝到\0时,将\0拷贝过去后,表达式结果为0(假),出循环
{
;
}
return start;
}
1.3 strcat
✨ 函数定义
char * strcat ( char * destination, const char * source );
✨ 函数作用 :将一个源字符串拼接到目的字符串后面
✨ 函数使用
int main()
{
char dest[20] = "teststring";
char src[] = "aaaa";
printf("%s", strcat(dest, src)); //strcat的返回值是目标空间的起始地址
//把src字符串(包括最后的\0)接到dest字符串后面,结果是teststringaaaa\0,这说明会把dest里原有的的\0用第一个a替换
return 0;
}
✨ 注意事项
- 源字符串必须以 '\0' 结束
- 目标空间必须有足够的大,能容纳下源字符串的内容
- 目标空间必须可修改
✨ strcat模拟实现
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* start = dest; //保存字符串的起始地址
while (*dest) //找到目的字符串中的\0,dest指向\0
{
dest++;
}
while (*dest++ = *src++) //类似strcpy,一一拷贝
{
;
}
return start;
}
1.4 strcmp
✨ 函数定义
int strcmp ( const char * str1, const char * str2 );
✨ 函数作用 :比较两个字符串的大小
✨ 函数使用
int main()
{
char src[] = "teststring";
char cmp[] = "testq";
printf("%d\n", strcmp(src, cmp)); //strcmp逐一比较src和cmp的每个字符,如果src>cmp,则返回正值 =返回0 <返回负值,这里是s>q,返回1
return 0;
}
✨ strcmp模拟实现
int my_strcmp(const char* src, const char* cmp)
{
assert(src && cmp);
while (*src == *cmp) //逐一判断对应字符是否相等
{
if (*src == '\0') //当找到 \0 = \0 ,说明比较完成且两字符串相等
{
return 0;
}
src++;
cmp++;
}
int ret = (*s > *c) ? 1 : -1; //走到这里说明找到了第一对不相等的字符,进行比较
return ret;
}
1.5 strncpy
✨ 函数定义
char * strncpy ( char * destination, const char * source, size_t num );
✨ 函数作用 :将一个源字符串的n个字符拷贝到目的字符串
✨ 函数使用
int main()
{
char dest[20] = "teststring";
char src[] = "aaaaaa";
printf("%s\n", strncat(dest, src, 7)); //如果给的n超过了(比如这里s有6个字符能拷过去,写了拷7个),也只会拷6个
return 0;
}
✨ strncpy模拟实现
char* my_strcpy(char* dest, const char* src, size_t n)
{
assert(dest && src);
char* start = dest; //保存字符串的起始地址
while (n && (*dest++ = *src++)) //逐个拷贝字符串,当拷贝到\0或n为零时,将\0拷贝过去后,表达式结果为0(假),出循环
{
n--;
}
return start;
}
1.6 strncat
✨ 函数定义
char * strncat ( char * destination, const char * source, size_t num );
✨ 函数作用 :将一个源字符串的n个字符拼接到目的字符串后面
✨ 函数使用
int main()
{
char dest[20] = "teststring";
char src[] = "aaaaa";
printf("%s\n", strncat(dest, src, 7)); //如果给的n超过了(比如这里s有6个字符能拷过去,写了拷7个),也只会拷6个
return 0;
}
✨ strncat模拟实现
char* my_strncat(char* dest, const char* src, size_t n)
{
assert(dest && src);
char* start = dest; //保存字符串的起始地址
while (*dest) //找到目的字符串中的\0,d指向\0
{
dest++;
}
while (n && (* dest++ = *src++)) //类似strcpy,一一拷贝
{
n--;
}
*dest = '\0'; //拷贝完成后在末尾补上\0
return start;
}
1.7 strncmp
✨ 函数定义
char * strncat ( char * destination, const char * source, size_t num );
✨ 函数作用 :比较两个字符串的前n个字符的大小
✨ 函数使用
int main()
{
char src[] = "teststring";
char cmp[] = "teststa";
printf("%d\n", strncmp(src, cmp, 7)); //比较前n个,有不同,立即返回,比较完无不同,返回0
return 0;
}
✨ strncmp模拟实现
int my_strncmp(const char* src, const char* cmp,size_t n)
{
assert(src && cmp);
while (n && (*src == *cmp)) //逐一判断对应字符是否相等
{
n--;
if (*src == '\0' || n == 0) //当找到 \0 = \0或者比较完了 n 对,此时 n = 0 ,说明比较完成
{
return 0;
}
src++;
cmp++;
}
int ret = (*src > *cmp) ? 1 : -1; //走到这里说明找到了第一对不相等的字符,进行比较
return ret;
}
1.8 strstr
✨ 函数定义
char * strstr ( const char *str1, const char * str2);
✨ 函数作用 :若str2字符串是str1字符串的一个字串,则返回该字串在str1中的位置
✨ 函数使用
int main()
{
char dest[] = "teststring";
char src[] = "str";
printf("%s\n", strstr(dest, src)); //找出dest中src的子串,并把子串的首地址返回
//这里打印 string
return 0;
}
✨ strstr模拟实现
char* my_strstr(const char* dest, const char* src)
{
assert(dest && src);
const char* s1 = dest;
const char* s2 = src;
const char* cur = dest;
while (*cur)
{
s1 = cur;
s2 = src;
while (*s1 && *s2 && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return (char*)cur;
}
cur++;
}
return NULL;
}
1.9 strtok
✨ 函数定义
char * strtok ( char * str, const char * sep );
✨ 函数作用 :用sep里的字符来分隔str的字符串
✨ 函数使用
int main()
{
char str[] = "teststring";
const char* sep = "ei"; //在str中先遇到e停下来,打印t,再引用strtok时,将源置为NULL,就在sep中找第二个
char buf[50] = { 0 };
strcpy(buf, str);
char* stra = NULL;
for (stra = strtok(buf, sep);stra != NULL;stra = strtok(NULL, sep))
{
printf("%s\n",stra);
}
//打印结果:t
ststr
ng
return 0;
}
✨ 注意事项
- sep参数是个字符串,定义了用作分隔符的字符集合
- 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记
- strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)
- strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置
- strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记
- 如果字符串中不存在更多的标记,则返回 NULL 指针
1.10 strerror
✨ 函数定义
char * strerror ( int errnum )
✨ 函数作用 :返回错误码,所对应的错误信息
✨ 函数使用
int main()
{
//printf("%s\n", strerror(0)); // No error
//
//
//printf("%s\n", strerror(1)); // Operation not permitted
//printf("%s\n", strerror(2)); // No such file or directory
//printf("%s\n", strerror(3)); // No such process
int* p = (int*)malloc(INT_MAX); //分配空间太大导致失败,返回一个空指针
if (p == NULL)
{
printf("%s\n", strerror(errno)); //errno是一个全局变量,一旦发生错误,就会将错误码放到errno中
}
return 0;
}
1.11 字符分类函数
函数 | 符合条件为真 |
iscntrl | 任何控制字符 |
isspace | 空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v' |
isdigit | 十进制数字 0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F |
islower | 小写字母a~z |
isupper | 大写字母A~Z |
isalpha | 字母a~z或A~Z |
isalnum | 字母或者数字,a~z,A~Z,0~9 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
✨ 函数使用
int main()
{
printf("%d\n", isdigit('5')); //isdigit,如果参数是数字字符,返回真
printf("%d\n", isdigit('z')); //否则,返回假(0)
printf("%d\n", islower('a')); //islower,如果参数是小写字符,返回真
printf("%d\n", islower('A')); //否则,返回假
printf("%d\n", isalnum('A')); //isalnum,如果参数是字母或者数字,返回真
printf("%d\n", isalnum(',')); //否则,返回假
return 0;
}
字符转换
int main()
{
printf("%c\n", tolower('A')); //大写转小写
printf("%c\n", toupper('a')); //小写转大写
return 0;
}
2. 内存函数
2.1 memcpy
✨ 函数定义
void * memcpy ( void * destination, const void * source, size_t num );
✨ 函数作用 :将source指针指向的内存地址中的num个字节数据拷贝到destination指针指向的内存中
✨ 注意事项
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置
- 这个函数在遇到 '\0' 的时候并不会停下来
- 如果source和destination有任何的重叠,复制的结果都是未定义的
✨ 函数使用
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[5] = { 0 };
memcpy(arr2, arr1, 20); //20是将20个字节(5个整形)从源拷贝到目的
for (int i = 0;i < 5;i++)
{
printf("%d ", arr2[i]);
}
//1 2 3 4 5
return 0;
}
✨ memcpy模拟实现
void* my_memcpy(void* dest, const void* src, size_t cnt)
{
assert(dest && src);
void* start = dest; //先保存初始地址
while (cnt--)
{
*(char*)dest = *(char*)src; //一个字节一个字节的取,将void* 类型的指针先强转为char*的指针再解引用
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return start;
}
2.2 memmove
✨ 函数定义
void * memmove ( void * destination, const void * source, size_t num );
✨ 函数作用 :实现重叠的内存拷贝
✨ 注意事项
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理
✨ 函数使用
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr + 2, arr, 20); //1,2,1,2,3,4,5,8,9,10
my_memmove(arr + 2, arr, 20);
for (int i = 0;i < 10;i++)
{
printf("%d ", arr[i]);
}
return 0;
}
✨ memmove模拟实现
void* my_memmove(void* dest, const void* src, size_t cnt)
{
assert(dest && src);
void* start = dest; //先保存初始地址
//判断从前往后拷贝还是从后往前拷贝,就是看源和目的的交界处,是位于源的前方还是后方
//1 2 3 4 5 6 7 8 9 假设源是3 4 5 6 ,目的是1 2 3 4 ,相交是3 4,是源的前方
//1 2 3 4 目的
// 3 4 5 6 源 (为确保源在拷贝过程中数据不变,先把相交处拷贝了,所以从前往后拷贝)
//
// 3 4 5 6 源
// 6 7 8 9 目的 (为确保源在拷贝过程中数据不变,先把相交处拷贝了,所以从后往前拷贝)
if (dest < src)
{
//从前向后拷贝
void* start = dest;
while (cnt--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//从后向前拷贝
while (cnt--)
{
*((char*)dest + cnt) = *((char*)src + cnt);
}
}
return start;
}
2.3 memcmp
✨ 函数定义
int memcmp ( const void * ptr1, const void* ptr2, size_t num );
✨ 函数作用 :内存中数据的比较
✨ 注意事项
- 比较从ptr1和ptr2指针开始的num个字节
✨ 函数使用
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,3,4,0x11223305 };
//int ret = memcmp(arr1, arr2, 17); //前16和17个字节都一样,返回0
int ret = memcmp(arr1, arr2, 18); //第18个字节arr1是00, arr2是33, arr1小, 返回-1
printf("%d\n", ret);
return 0;
}
2.4 memset
✨ 函数定义
void *memset( void *dest, int c, size_t count );
✨ 函数作用 :将dest指针指向内存的count个字节数据设为字符c()
✨ 函数使用
int main()
{
int arr[] = { 1,2,3,4,5 };
memset(arr, 0, 19);
for (int i = 0;i < 5;i++)
{
printf("%d\n", arr[i]);
}
return 0;
}