目录
1. 求字符串长度
strlen
2. 长度不受限制的字符串函数
strcpy
strcat
strcmp
3. 长度受限制的字符串函数
strncpy
strncat
strncmp
4. 字符串查找
strstr
strtok
5. 内存操作函数
memcpy
memmove
memset
● 字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不 包含 '\0' )。
● 参数指向的字符串必须要以 '\0' 结束。
● 函数的返回值为size_t,是无符号的
使用如下:
#include
#include
int main()
{
char str[] = "abcde";
printf("%u\n", strlen(str));
return 0;
}
模拟实现:
① 计数方式
#include
size_t my_strlen(const char* str)
{
int count = 0;
while (*str++)
count++;
return count;
}
int main()
{
size_t sz = my_strlen("abcde");
printf("%u\n", sz);
return 0;
}
注意:返回值size_t为无符号数
② 递归方式
int my_strlen(const char* str)
{
if (*str == '\0')
return 0;
else
return 1 + my_strlen(str + 1);
}
③指针-指针方式
int my_strlen(char* str)
{
char* p = str;
while (*p != '\0')
p++;
return p - str;
}
将源指向的 C 字符串复制到目标指向的数组中,包括终止的 null 字符(并在该点停止)。
为避免溢出,目标指向的数组的大小应足够长,以包含与源相同的 C 字符串(包括终止空字符),并且不应在内存中与源重叠。
● 源字符串必须以 '\0' 结束
● 会将源字符串中的 '\0' 拷贝到目标空间
● 目标空间必须足够大且是可变的,以确保能存放源字符串
● 不应在内存中与源重叠
使用如下:
#include
#include
int main()
{
char arr1[10] = "abcdefg";
char arr2[] = "xxxxx";
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
模拟实现
#include
#include
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*src)
{
*dest = *src;
dest++;
src++;
}
*dest = *src; //复制“\0”
//或
/*while (*dest++ = *src++)
{
;
}*/
return ret;
}
int main()
{
char arr1[10] = "abcdefg";
char arr2[] = "xxxxx";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
注意:源字符串中的“\0”,也要拷贝到目标串
将源字符串的副本追加到目标字符串。目标中的终止空字符("\0")被源的第一个字符覆盖,并且在目标中由两者串联形成的新字符串的末尾包含一个空字符。目标串和源串不得重叠。
● 源字符串必须以 '\0' 结束
● 目标空间必须有足够的大,能容纳下源字符串的内容
● 目标空间必须可修改
● 目标串和源串不能重叠
使用如下:
#include
#include
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
模拟实现
#include
#include
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;//保存目标串的首地址
//找目标串中的空字符"\0"
while (*dest)
dest++;
//连接
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
将 C 字符串 str1 与 C 字符串 str2 进行比较。此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续往下比较,直到字符不同或达到终止空字符。
返回值 :
使用如下:
#include
#include
int main()
{
char arr1[] = "bbq";
char arr2[] = "bcq";
printf("%d\n", strcmp(arr1, arr2));//arr1中b比c小,故返回小于零的数
return 0;
}
模拟实现:
#include
#include
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return *str1 - *str2;//返回的是小于0或大于0的值
}
int main()
{
int ret = my_strcmp("bbq", "bcq");
printf("%d\n", ret);
return 0;
}
注意:返回值应写成两字符的差的形式,这样返回的才是小于0或大于0的数字
说明:vs编译器返回值为1(大于0时)、-1(小于0时)、0(等于0时),不同编译器或许会有所不同
将源的第一个字符数复制到目标。如果在复制 num 个字符之前找到源 C 字符串的末尾(由 null 字符表示),则目标将填充零,直到总共写入 num 个字符为止。如果源长度超过 num,则不会在目标末尾隐式附加空字符,因此,在这种情况下,不应将目标视为以空结尾的 C 字符串(这样读取它会溢出)。目标串和源串不得重叠(有关重叠时更安全的替代方案,请参见 Memmove)。
● 拷贝num个字符从源字符串到目标空间
● 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到 num个
● 目标串和源串不能重叠
使用如下:
模拟实现:
#include
#include
char* my_strncpy(char* dest, const char* src, size_t num)
{
assert(dest && src);
char* ret = dest;//保存目标串的首地址
while (num-- && (*dest++ = *src++))
{
;
}
//补超出的num个"\0"
while (num--)
*dest++ = '\0';
return ret;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "xxx";
my_strncpy(arr1, arr2, 2);
printf("%s\n", arr1);
return 0;
}
将源的第一个数字字符追加到目标,外加一个终止空字符;如果源中 C 字符串的长度小于 num,则仅复制终止空字符之前的内容。
使用如下:
注意: num无论小于或大于源串长度,结尾的 "\0" 都是外加的终止符,strncat函数仅复 制"\0"之前的字符
模拟实现:
#include
#include
char* my_strncat(char* dest, const char* src, size_t num)
{
assert(dest && src);
char* ret = dest;
while (*dest)
dest++;
while (num && *src)
{
*dest = *src;
dest++;
src++;
num--;
}
*dest = '\0'; //额外附加"\0";strncat只连接源串中空字符之前的字符
return ret;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "xxxxxx";
my_strncat(arr1, arr2, 8);
printf("%s\n", arr1);
return 0;
}
将 C 字符串 str1 的字符数与 C 字符串 str2 的字符数进行比较。此函数开始比较每个字符串的第一个字符。 如果它们彼此相等,则继续使用以下对,直到字符不同,直到达到终止的空字符,或者直到两个字符串中的 num 字符匹配,以先发生者为准.
● 比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完
返回值:
使用如下:
#include
#include
int main()
{
char arr1[] = "abcqwertyuio";
char arr2[] = "abcpef";
printf("%d\n", strncmp(arr1, arr2, 4));
return 0;
}
模拟实现:
#include
#include
int my_strncmp(const char* str1, const char* str2, size_t num)
{
assert(str1 && str2);
//没有字符比较
if (!num)
return 0;
//当字符相等且不为'\0'时比较下一个字符
while (num-- && *str1 && (*str1 == *str2))
{
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char arr1[] = "abcqwertyuiop";
char arr2[] = "abcdef";
int ret = my_strncmp(arr1, arr2, 4);
printf("%d\n", ret);
return 0;
}
返回指向 str2 中第一次出现的 str1 的指针,如果 str2 不是 str1 的一部分,则返回一个空指针。匹配过程不包括终止空字符,但它到此为止。
使用如下:
#include
#include
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
char* ret = strstr(arr1, arr2);
if (ret != NULL)
printf("%s\n", ret);
else
printf("找不到\n");
return 0;
}
模拟实现:
#include
char* my_strstr(char* str1, char* str2)
{
char* cp = str1;
char* s1 = cp;
char* s2 = str2;
//判断源字符串是否为空串
if (*str2 == '\0')
return str1;
//匹配不成功时把cp指针赋给s1让s1指针往后走
while (*cp)
{
s1 = cp;
s2 = str2;
//匹配
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return cp;
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
char* ret = my_strstr(arr1, arr2);
if (ret != NULL)
printf("%s\n", ret);
else
printf("找不到\n");
return 0;
}
● delimiter参数是个字符串,定义了用作分隔符的字符集合
● 第一个参数指定一个字符串,它包含了0个或者多个由delimiter字符串中一个或者多个 分隔符分割的标记。
● strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针 (注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都 是 临时拷贝的内容并且可修改。)
● strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保 存 它在字符串中的位置
● strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查 找 下一个标记
● 如果字符串中不存在更多的标记,则返回 NULL 指针
使用如下:
#include
#include
int main()
{
char arr[] = "[email protected]@666#777";
char copy[30]; //为了源串不被修改,提前备份
strcpy(copy, arr);
char delimiter[] = "@.#";
char* ret = NULL;
for (ret = strtok(copy, delimiter); ret != NULL; ret=strtok(NULL, delimiter))
{
printf("%s\n", ret);
}
return 0;
}
知道会用即可
将字节数的值从源指向的位置直接复制到目标指向的内存块。源指针和目标指针指向的对象的基础类型与此函数无关;结果是数据的二进制副本。该函数不检查源中的任何终止空字符 - 它总是准确地复制字节数。为避免溢出,目标和源参数指向的数组大小应至少为字节数,并且不应重叠(对于重叠的内存块,memmove 是一种更安全的方法)
● 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位 置
● 这个函数在遇到 '\0' 的时候并不会停下来
● 如果source和destination有任何的重叠,复制的结果都是未定义的,即不应重
使用如下:
此函数可拷贝不同类型的数据,此处以int型为例
#include
#include
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
//将arr1中的内容,拷贝到arr2中
memcpy(arr2, arr1, 40);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
模拟实现:
//函数拷贝结束后,返回目标空间的起始地址
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(src && dest);
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
my_memcpy(arr2, arr1, 20);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
将字节数的值从源指向的位置复制到目标指向的内存块。复制就像使用了中间缓冲区一样,允许目标和源重叠。源指针和目标指针指向的对象的基础类型与此函数无关;结果是数据的二进制副本。该函数不检查源中的任何终止空字符 - 它总是准确地复制字节数。为避免溢出,目标参数和源参数指向的数组的大小应至少为字节数。
● 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
● 如果源空间和目标空间出现重叠,就得使用memmove函数处理
使用如下:
#include
#include
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
//把3 4 5 6 7拷贝到1 2 3 4 5
memmove(arr1, arr1+2, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
模拟实现:
#include
#include
void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest && src);
char* ret = dest;
if (dest < src)
{
//从前往后拷贝(包括不重叠)
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//从后往前拷贝
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1+2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
ptr 指向要填充的内存块的指针
value 要设置的值。该值作为 int 传递,但该函数使用此值的无符号 char 转换填充内存块
num 要设置为该值的字节数。
使用如下:
#include
#include
int main()
{
char arr[] = "hello bit";
memset(arr+1,'x',4);//以字节为单位设置
printf("%s\n", arr);
return 0;
}