在C语言具有许多数据类型,但不具有字符串类型,字符串通常放在字符指针或字符数组中,因为在C语言中对字符和字符串的处理很频繁,从而延伸出许许多多有关字符串的函数。
功能:求字符串中元素的个数,不包括末尾的 ’ \0 '。 头文件为#include
字符串是以 ’ \0 '作为结束标志,strlen函数返回的是在字符串中 ’ \0 '前面的总元素个数(不包括 ’ \0 ') 。
注意:
1.strlen函数的返回值为 size_t ,无符号整形(unsigned int)。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
const char* str1 = "abcdef"; //元素个数为6个
const char* str2 = "bbb"; //元素个数为3个
if (strlen(str2) - strlen(str1) > 0) //两个无符号进行运算,则结果也为无符号
{
printf("str2>str1\n");
}
else
{
printf("srt1>str2\n");
}
return 0;
}
2.参数指向的字符串必须要以 ‘\0’ 为结束标志,否则,strlen会越界一直找’ \0 ',直到遇到 ’ \0 ’ 停止,结果为随机值。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
char arr1[8] = "abcde";
char arr2[5] = {'a','b','c','d','e'};
printf("%d\n",strlen(arr1));
printf("%d\n",strlen(arr2));
return 0;
}
1.计数器
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int my_strlen(const char* arr) //计数器模拟实现strlen
{
assert(arr); //断言,检查指针的有效性,防止对空指针进行解引用、加减整数操作
int count = 0;
while (*arr)
{
count++;
arr++;
}
return count;
}
int main()
{
char arr[10] = "hello bit";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
2.指针-指针(计算的是两指针之间的元素个数)
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int my_strlen(const char* arr) //指针-指针模拟实现strlen
{
assert(arr); //断言,检查指针的有效性,防止对空指针进行解引用、加减整数操作
char* start = arr;
char* end = arr;
while (*end)
end++;
return end - start;
}
int main()
{
char arr[10] = "hello bit";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
3.递归
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int my_strlen(const char* arr) //递归模拟实现strlen
{
assert(arr); //断言,检查指针的有效性,防止对空指针进行解引用、加减整数操作
if (*arr != '\0')
return my_strlen(arr + 1) + 1;
else
return 0;
}
int main()
{
char arr[10] = "hello bit";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
功能:将源头字符串的内容拷贝到目标字符串,包括末尾的 ‘\0’(相当于从前往后进行覆盖)。 头文件为#include
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
char dest[20] = "abcdefg";
char source[6] = "hello";
strcpy(dest, source + 2); //可以从源字符串的任意位置处开始拷贝
printf("%s", dest);
return 0;
}
=注意:
1.会将源头字符串的 '\0’拷贝进去。2.目标空间要足够大,足以存放源头字符串。
3.目标空间必须是可变的(不能被const修饰)。
4.源头字符串必须以 ‘\0’ 为结束标志(因为strcpy拷贝完\0’后就立即停止拷贝)。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
char* my_strcpy(char* dest, const char* source)
{
assert(dest&&source); //断言,检查指针的有效性,防止对空指针进行解引用、加减整数操作
char* ret = dest;
while (*dest++ = *source++)
{
;
}
return ret;
}
int main()
{
char dest[20] = "abcdefg";
char source[6] = "hello";
char* ret = my_strcpy(dest, source);
printf("%s", ret);
return 0;
}
功能:将源头字符串的内容追加到目标字符串的后面(从目标串的’\0’位置开始向后追加)。 头文件为#include
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
char dest[30] = "heihei";
char source[] = " hello";
strcat(dest, source);
printf("%s", dest);
return 0;
}
注意:
1.目标字符串必须可修改。
2.源字符串必须含有 '\0’为结束标志。
3.目标空间要足够大,足以容纳源头字符串的内容。
问题:字符串是否可以自己给自己追加?
答:字符串不可以自己给自己追加,因为源头字符串的’\0’会被覆盖,造成源头字符串会一直向后死循环追加。strcat遇到源头字符串的 ‘\0’就停止追加,并且源头字符串末尾的’\0’也会被追加过去。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
char* my_strcat(char* dest,const char* source)
{
assert(dest&&source); //断言,检查指针的有效性,防止对空指针进行解引用、加减整数操作
char* ret = dest;
while (*dest) //找目标字符串中的'\0'
{
dest++;
}
while (*dest++ = *source++)
{
;
}
return ret;
}
int main()
{
char dest[30] = "abcde";
char source[] = "hello bit";
char* ret = my_strcat(dest, source);
printf("%s", ret);
return 0;
}
功能:用来比较两字符串的大小,两字符串不能直接用==进行比较。 头文件为#include
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
char s1[] = "abcdefg";
char s2[] = "abcde";
int ret=strcmp(s1, s2);
printf("%d\n", ret);
return 0;
}
问题:strcmp如何判断两字符串大小?
答:两个字符串从前向后依次比较两个字符,判断是否相等,相等,则继续比较下一个字符,直到有一个串遇到’\0’,并比较完’\0’,就停止。若不相等,比较两字符的ASCII值,ASCII值大的串,字符串大。《—等价于—》ASCII值的比较
a.字符串1(前面的参数)大于 字符串2(后面的参数),则返回大于0的数。
b.字符串1(前面的参数)小于 字符串2(后面的参数),则返回小于0的数。
c.字符串1(前面的参数)等于 字符串2(后面的参数),则返回等于0的数。
#define _CRT_SECURE_NO_WARNINGS 1
#include
int my_strcmp(const char* s1, const char* s2)
{
assert(s1 && s2);
while (*s1 == *s2)
{
if (*s1 == '\0')
return 0;
s1++;
s2++;
}
return *s1 - *s2;
}
int main()
{
char s1[] = "abcde";
char s2[] = "abcdef";
int ret = my_strcmp(s1, s2);
printf("%d", ret);
return 0;
}
功能: 头文件为#include
情况1:源字符串的长度>num,将源字符串的前num个字符拷贝到目标字符串中;
情况2:源字符串的长度
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
int num = 5; //源字符串的长度>num
char dest[30] = "heheabcd";
char source[] = "lala hello";
strncpy(dest, source, num);
printf("%s", dest);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
int num = 20; //源字符串的长度
char dest[30] = "heheabcdefghi";
char source[] = "lala hello";
strncpy(dest, source, num);
printf("%s", dest);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
char* my_strncpy(char* dest,const char* source, int num)
{
assert(dest && source);
char* ret = dest;
while (num--)
{
if (*source != '\0') //情况1,源字符串的长度>num
*dest++ = *source++;
else //情况2,源字符串的长度
*dest++ = '\0';
}
return ret;
}
int main()
{
int num = 5;
char dest[30] = "heheabcdefghi";
char source[] = "lala hello";
char* ret = my_strncpy(dest, source, num);
printf("%s\n", dest);
return 0;
}
功能: 头文件为#include
情况1:源字符串的长度>num,将源字符串的前num个字符追加到目标字符串后面,最后在目标字符串后面自动补上 ‘\0’;
情况2:源字符串的长度
情况1代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
int main()
{
int num = 5; //情况1,源字符串的长度>num
char dest[30] = "abcde\0lalalalalala";
char source[] = "hello world";
strncat(dest, source, num);
printf("%s\n", dest);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
int main()
{
int num = 20; //情况2,源字符串的长度
char dest[30] = "abcde\0lalalalalalalalalalala";
char source[] = "hello world";
strncat(dest, source, num);
printf("%s\n", dest);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
char* my_strncat(char* dest, const char* source,int num)
{
assert(dest && source);
char* ret = dest;
while (*dest)
dest++;
while (num--)
{
*dest = *source;
if (*source == '\0') //清款2
break;
dest++;
source++;
}
if (*source != '\0') //情况1
*dest = '\0';
return ret;
}
int main()
{
int num =5;
char dest[30] = "abcde\0lalalalalalalalalalala";
char source[] = "hello world";
char* ret=my_strncat(dest, source, num);
printf("%s\n", ret);
return 0;
}
功能:比较前num个字符的大小, 头文件为#include
比较到在num范围内有一个串结束、两串中有一个字符不相等,前num个字符全部比完,就停止比较了。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int my_strncmp(const char* s1,const char* s2, int num)
{
assert(s1&&s2);
while (num--)
{
while (*s1 == *s2)
{
if(*s1 == '\0')
return 0;
s1++;
s2++;
}
return *s1-*s2;
}
}
int main()
{
int num = 3;
char arr1[] = "abcdef";
char arr2[] = "abed";
int len = my_strncmp(arr1, arr2,num);
printf("%d\n", len);
return 0;
}
功能:在string指向的字符串中查找strCharSet指向的字符串是否出现,出现,则返回strCharSet指向的字符串在tring指向的字符串第一次出现的起始位置,若未出现,则返回NULL。 头文件为#include
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
int main()
{
char arr[] = "abcdefbcdef";
char src[] = "bcdef";
char* ret=strstr(arr, src);
printf("%s\n", ret);
return 0;
}
版本1:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
char* my_strstr(char* dest, char* src)
{
assert(dest && src);
char* cur = dest;
char* s1;
char* s2;
while (*cur)
{
s1 = cur;
s2 = src;
while (*s2&&*s1)
{
if (*s1 != *s2)
break;
s1++;
s2++;
}
if (*s2 == '\0')
return cur;
cur++;
}
}
int main()
{
char arr[] = "abbbcdefbcdef";
char src[] = "bcdef";
char* ret=my_strstr(arr, src);
printf("%s\n", ret);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
char* my_strstr(char* dest, char* src)
{
assert(dest && src);
char* ret = dest;
int len1 = strlen(dest);
int len2 = strlen(src);
int i=0;
for ( ; i + len2 <= len1; i++)
{
int j = 0;
for (; j < len2; j++)
{
if (dest[i+j] != src[j])
break;
}
if (j == len2)
return (ret + i);
}
return NULL;
}
int main()
{
char arr[] = "abbbcdefbcdef";
char src[] = "bcdef";
char* ret=my_strstr(arr, src);
printf("%s\n", ret);
return 0;
}
功能:用于处理带标记的字符串。头文件为#include
注意:
1.参数2strDelimit指向的字符串定义了用作分隔符的集合,注意参数2必须是字符串,而’\0‘代表的是字符串结束符,通常用于标记字符串的末尾,并不作为分隔符。
2.strToken指向的字符串,它包含了0个或者多个strDelimit指向字符串的分隔符标记。
3.strtok函数找到strDelimit指向字符串中的下一个分隔符的标记,并会自动保存这个标记符在字符串的位置,返回一个指向这个标记的指针。
4.当第一个参数不为NULL,找到第一个分割符标记,该函数内部会自动保存这个标记符在字符串的位置,进行第二次使用strtok函数时,函数的第一个参数为NULL,该函数会从上次strtok函数保存的上个分割标记符后一个位置处查询下一个分割标记符并保存下一个分割标记符所在字符串中的位置,直到不存在分隔符停止查找。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
char arr1[] = "naifu,naiyou.fsq#zzx";
const char* arr2= ",.#";
for (char* ret = strtok(arr1, arr2); ret != NULL; ret=strtok(NULL, arr2))
{
printf("%s\n", ret);
}return 0;
}
功能:返回错误码所对应的错误信息。头文件为#include
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include //strerror库函数的头文件
#include //必须包含的头文件
int main()
{
FILE* p = fopen("lala.txt", "r");
if (p == NULL)
{
printf("%s\n", strerror(errno)); //errno存放错误码
return 1;
}
fclose(p);
p = NULL;
return 0;
}
strerror函数可以用于确定库函数在执行时发生的错误的原因。当库函数遇到错误时,它会设置一个全局变量errno,C语言会将错误码存放在errno这个全局变量中,strerror函数使用errno确定特定错误码对应的错误消息。
功能:返回错误码所对应的错误信息。头文件为#include
与strerror作用效果相同,只是perror会输出string指向的字符串内容在加个冒号(:),在输出错误码所对应的错误信息,在文件操作中,确定错误信息是什么,常用perror函数。
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
FILE* p = fopen("lala.txt", "r");
if (p == NULL)
{
perror("fopen");
return 1;
}
fclose(p);
p = NULL;
return 0;
功能:从src位置向后拷贝count个字节的内容到dest指向的字符串中(遇到\0不会停下来)。若拷贝的字节数大于源头字符串的总字节数,超过的字节数拷贝的内容为随机值。 头文件为#include
注意:memecpy适用于不重叠数据或者无关联的数据拷贝。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
int count = 4;
int arr[10] = { 1,2,3,4,5,6 };
int src[6] = { 7,8,9,10,11,12 };
memcpy(arr, src, sizeof(arr[0])*count);
for (int i = 0; i <10; i++)
printf("%d ", arr[i]);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
int count = 3;
int arr[10] = { 1,2,3,4,5,6 };
int src[3] = { 7,8,9};
memcpy(arr, src, sizeof(arr[0])*count);
for (int i = 0; i <10; i++)
printf("%d ", arr[i]);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
void* my_memcpy(void* dest, void* src, int count) //适用于任意类型
{
assert(dest && src);
while (count--)
{
*(char*)dest = *(char*)src; //对空指针进行解引用操作,具有临时性,有效时长仅在其所在的语句中
(char*)dest = (char*)dest + 1; //(char*)dest++,因优先级:++>(),dest(NULL)先与++结合,不能对空指针进行加减、解引用操作
(char*)src = (char*)src + 1;
}
return ;
}
int main()
{
int count = 4;
int arr[10] = { 1,2,3,4,5,6,7,8 };
int src[6] = { 9,10,11,12 };
int len = sizeof(arr) / sizeof(arr[0]);
my_memcpy(arr, src, sizeof(arr[0] )* count);
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
问题:memcpy可以拷贝重叠数据吗?
答:memcpy不可以拷贝重叠数据,会造成数据被覆盖。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
void* my_memcpy(void* dest, void* src, int count) //适用于任意类型
{
assert(dest && src);
while (count--)
{
*(char*)dest = *(char*)src; //对空指针进行解引用操作,具有临时性,有效时长仅在其所在的语句中
(char*)dest = (char*)dest + 1; //(char*)dest++,因优先级:++>(),dest(NULL)先与++结合,不能对空指针进行加减、解引用操作
(char*)src = (char*)src + 1;
}
return ;
}
int main()
{
int count = 5;
int arr[10] = { 1,2,3,4,5,6,7,8 };
int src[6] = { 9,10,11,12 };
int len = sizeof(arr) / sizeof(arr[0]);
my_memcpy(arr+2, arr, sizeof(arr[0] )* count); //memcpy拷贝重叠数据
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
功能:从src位置向后拷贝count个字节的内容到dest指向的字符串中(遇到\0不会停下来)。若拷贝的字节数大于源头字符串的总字节数,超过的字节数拷贝的内容为随机值。 头文件为#include
注意:memmove既适用于重叠数据或者有关联的数据拷贝,又适用于不重叠数据或者无关联的数据拷贝。
重叠数据或者有关联的数据拷贝:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
int count = 5;
int arr[10] = { 1,2,3,4,5,6,7,8 };
int len = sizeof(arr) / sizeof(arr[0]);
memmove(arr+2, arr, sizeof(arr[0] )* count);
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
int count = 5;
int arr[10] = { 1,2,3,4,5,6,7,8 };
int src[5] = { 9,10,11,12,13 };
int len = sizeof(arr) / sizeof(arr[0]);
memmove(arr,src, sizeof(arr[0] )* count);
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
void* my_memmove(void* dest, const void* src, int count)
{
void* ret = dest;
if (dest < src) //从前往后拷贝
{
while (count--)
{
*((char*)dest) = *((char*)src);
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else //从后往前拷贝
{
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return ret;
}
int main()
{
int count = 5;
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr+2, arr, sizeof(int) * count); //重叠数据
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
答:memmove既可以处理重叠数据,又可处理不重叠数据(100%)。 memcpy被规定来只能用来处理不重叠或者无关联的数据(60%),但在有些编译器上,memcpy也可用来处理重叠数据,所以一般处理重叠数据的拷贝选择memmove,处理不重叠的数据选择memcpy。
功能:将dest指向的内存空间的前count字节的内容全部设置为c。 头文件为#include
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int count = 5;
memset(arr, 0, sizeof(int) * count);
for (int i = 0; i < 10; i++)
printf("%d ", arr[i]);
return 0;
}
应用场景:常适用于初始化一块连续的内存空间,eg:静态版通讯录实现。
功能:将dest指向的内存空间前count字节的内容与src指向的内存空间前count字节的内容相比较,比较到在count字节范围内有一个空间结束、两空间中有一个字节不相等,前num个字节全部比完,就停止比较了,返回值与strncmp相同。
铁铁们,字符函数和字符串函数知识总结就到此结束啦,若博主有不好的地方,请指正,欢迎铁铁们留言,请动动你们的手给作者点个鼓励吧,你们的鼓励就是我的动力✨