字符函数和字符串函数可以分为以下几类:
- 求字符串长度
strlen
- 长度不受限制的字符串长度
strcpy
strcat
strcmp
- 长度受限制的字符串函数介绍
strncpy
strncat
strncmp
- 字符串查找
strstr
strtok
- 错误信息报告
strerror
- 字符操作
- 内存操作函数
memcpy
memmove
memset
memcmp
函数介绍
1.strlen
size_t strlen(const char* str)
计数长度以‘\0’作为结束标志,返回‘\0’前出现的字符个数。因此如果返回的字符串无‘\0’将会出现随机数。返回值是size_t,是无符号的。
同时sizeof也可以计数,但其不是函数,是操作数。
模拟实现:
size_t my_strlen(const char* str)
{
int count = 0;
// 断言,不满足会报错
assert(str != NULL);
while (*str != '\0')
{
count++;
str++;
}
return count;
}
2.strcpy
strcpy(arr1,arr2)
表示把arr2拷贝到arr1中
arr2必须以‘\0’结尾,并会将’\0’拷贝到目标空间,因此目标空间必须足够大,必须可变,确保能存放源字符串。
//strcpy返回的是目标字符串的起始地址
char* my_strcpy(char* dest, char* str)
{
assert(dest && str);
char* ret = dest;
while (*dest++=*str++)
{
;
}
return ret;
}
对于数组必须确定个数,不然容易返回随机数。
3.strcat
strcat(arr1, arr2)表示把arr2追加到arr1中,
同样,arr2必须以‘\0’结尾。
模拟实现:
//模拟实现strcat
char* my_strcat(char* dest, char* str)
{
assert(dest && str);
char* ret = dest;
//找'\0'
while (*dest)
{
dest++;
}
//拷贝
while (*dest++ = *str++)
{
;
}
return ret;
}
4.strcmp
用来比较两个字符串,比较的是对应位置上字符串的大小,如果相同,就比较下一对,指导不同或遇到’\0’
strcmp(arr1, arr2)
- arr1 > arr2
返回大于0的数(VS环境下返回1) - arr1 = arr2
返回0(VS环境下返回0) - arr1 < arr2
返回小于0的数(VS环境下返回-1)
模拟实现:
int my_strcmp(const char* s1, const char* s2)
{
assert(s1 && s2);
while (*s1 == *s2)
{
if (*s1 == '\0')
{
return 0;
}
s1++;
s2++;
}
/*if (*s1 > *s2)
{
return 1;
}
else
{
return -1;
}*/
return *s1 - *s2;
}
5.strncpy
6.strncat
7.strncmp
使用与前几个相似,唯一不同是可以选择操作的字符数
eg. strncpy(arr1, arr2, n),把arr2中n个字符拷贝到arr1中,若arr2字符串长度小于n,则补0。
其余两个函数类似。
8.strstr
strstr(arr1,arr2)
寻找arr2中包含的arr1子串。
包含,返回arr1子串第一次出现的地址;
若不包换,返回空指针
9.strtok
char* strtok(char* str, const char* sep)
str表示将要被分隔的字符串,sep是用作分隔符的字符合集。
10.strerror
char* strerror(int errnum)
返回错误码所对应的错误信息。
使用时注意包含头文件 #include <errno.h>
会有一个全局变量 errno
若想直接打印可用perror("****")
部分自定义,会在打印时表示错误名称。
11.memcpy
void memcpy(void destination, const void source, size_t num)
这个函数在遇到’\0’时不会停下来,若source和dest有任何的重叠,结果未定义
模拟实现:
void* my_memcpy(void* dst,const void* src,size_t count)
{
assert(dst&&src);
void* ret = dst;
while (count--)
{
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
return ret;
}
12.memmove
void* memmove(void* destination, const void* source, size_t num)
与memcpy唯一的区别是处理的源内存块可以重叠。
模拟实现要注意每段复制顺序,不然会有重复(思路如图):
void* my_memmove(void* dst, const void* src, size_t count)
{
assert(dst&&src);
void* ret = dst;
//从前向后
if (dst <= src || (char*)dst >= ((char*)src + count))
{
while (count--)
{
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
}
//从后向前
// //写法一
//else
//{
// dst = (char*)dst + count - 1;
// src = (char*)src + count - 1;
// while (count--)
// {
// *(char*)dst = *(char*)src;
// dst = (char*)dst - 1;
// src = (char*)src - 1;
// }
//}
//写法二
else
{
while (count--)
{
*((char*)dst + count) = *((char*)src + count);
}
}
return ret;
}
13.memcmp
int memcmp(const void* ptr1, const void* ptr2, size_t num)
一对字节一对字节往后比,无视‘\0’
14.memset
内存设置,以字节为单位初始化
memset(arr, 0, 20)把arr中20个字节改为0