文章目录
● 前言
● 一、求字符串长度
● 1. strlen
● 二、长度不受限制的字符串函数
● 2.1. strcpy
● 2.2. strcat
● 2.3. strcmp
● 三、长度受限制的字符串函数
● 3.1 strncpy
● 3.2. strncat
● 3.3. strncmp
● 四、总结
兄弟们,咱们这篇博客,我会把以前我们遇到过的或者还没遇到过的但是要求掌握的字符函数和字符串函数,来完整的梳理一遍。大概需要两篇博客完成本章内容。我尽量用通俗易懂的语言给大家呈现出来。若大家对本文有任何疑问,欢迎家人们指正批评,讨论,或者联系我,我会在第一时间回复!谢谢~
1. strlen
字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )。
函数原型:size_t strlen ( const char * str );
参数指向的字符串必须要以 '\0' 结束。
注意函数的返回值为size_t,是无符号的( 易错 )
注:const char* 是指向一个常量字符的指针,所以说,const char*所修饰的指针变量,其指针变量本身(即指向元素的地址)是可以被修改的,但是其指针所指向的值是不允许被修改的。这里的const不会限制指针变量本身,也就是说,其指针变量是允许指向其他的地址的,const char*和char const*等价。
#include
#include
int my_strlen(const char* str)
{
int count = 0;
assert(str); //断言,防止出现空指针
while (*str) //判断*str是否为'\0'
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "abcd";
int ret = my_strlen(arr);
printf("%d\n", ret);
return 0;
}
strcpy,即string copy(字符串复制)的缩写。
strcpy把含有'\0'结束符的字符串复制到另一个地址空间,返回值的类型为char*。
原型声明:char* strcpy(char* destination, char* source);
使用时注意事项:
● 源字符串必须以 '\0' 结束。
● 会将源字符串中的 '\0' 拷贝到目标空间。
● 目标空间必须足够大,以确保能存放源字符串。
● 目标空间必须可变 。
代码示例:
下面代码中数组arr1是源字符串,arr2是目标空间。
源字符串必须以 '\0' 结束。不然的话程序就会出现以下错误。
源字符串加入'\0'之后,结果正确。
目标空间不够大的话,程序会出现如下错误,所以目标空间必须足够大,以确保能存放源字符串。
程序结束时后面的x打印不出来,是因为printf遇到'\0'打印就结束了
#include
#include
//因为传来的是字符地址,所以我们这里用字符指针接收
// 源头的数据(src)是不用发生变化的,目的地的数据(dest)是要发生变化的,
//所以我们给char* src前面加一个const
// 这样就把源头的数据保护了起来,虽然拿到了地址,但是不能随意更改,这样效果会更好
char* my_strcpy(char* dest, const char* src)
{ //为了实现链式访问,它返回的是char*
char* ret = dest; //先把目标空间的起始位置保存
assert(dest && src); //断言,看两个指针是否有效,防止空指针的出现
//这种写法比较啰嗦,我们可以对其进行简化
//while (*src) //*src如果不是'\0',为真,执行while语句
//{
//*dest = *src; //把src中的内容拷贝到dest中去
//dest++;
//src++;
//}
//*dest = *src; //要把src中的'\0'拷贝到dest中去
//将上面的代码进行简化
while (*dest++ = *src++);
{
;
}
return ret; //返回目标空间的首地址,根据首地址依次打印后面的元素
}
int main()
{
char arr1[] = { 'a', 'b', 'c', 'd', 'e', 'f', '\0' }; //源字符串
char arr2[20] = "xxxxxxxxxxxxx"; //目标空间
my_strcpy(arr2, arr1); //传过去的字符地址
printf("%s\n", arr2);
return 0;
}
什么是链式访问?
一个函数的返回值作为另一个函数的参数就是函数的链式访问。
strcat 即 Strings Catenate,横向连接字符串。
功能:把src所指向的字符串(包括“\0”)复制到dest所指向的字符串后面(删除*dest原来末尾的“\0”)。
要保证*dest足够长,以容纳被复制进来的*src。*src中原有的字符不变。返回指向dest的指针。
● 源字符串必须以 '\0' 结束。
● 目标空间必须有足够的大,能容纳下源字符串的内容。
● 目标空间必须可修改。
代码示例:
#include
int main()
{
char arr1[30] = "hello"; //目标空间必须足够大,且可以修改
char arr2[] = "world"; // { 'w', 'o', 'r', 'l', 'd', '\0' }; //源字符串必须以'\0'结束
strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
#include
#include
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
//1.目标空间的'\0'
while (*dest)
{
dest++; //找到arr1字符串中的'\0'
}
//2.追加内容到目标空间
//等同于实现strcpy的功能
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello"; //目标空间
char arr2[] = "world"; //源空间
printf("%s\n", my_strcat(arr1, arr2)); //链式访问
return 0;
}
如果我们将上面第一步的代码简化如下所示:
这是错误的,当*dest为'\0'的时候++一下,这个++再产生效果的话就把'\0'跳过去了。虽然你追加进去了但是看不到,因为你追加到了'\0'的后面去了。经过下面的调试我们可以看到前置++也不可以,当你目标空间为'\0',它也是错误的,大家可以自行测试一下。
strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2)。若str1=str2,则返回0;若str1
小于0的数;若str1>str2,则返回一个大于0的数。 函数原型:int strcmp(const char *str1,const char * str2);
比较规则:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或者遇到'\0'为止。
特别注意:这里面只能比较字符串,即可用于比较两个字符串常量,或比较数组和字符串常量,不能比较数字等其他形式的参数。
示例代码:
#include
#include
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0') //如果str1为'\0',那么str2也肯定是'\0',则表明两个字符串相等
return 0; //返回0
str1++;
str2++;
}
//return *str1 - *str2; //这种写法也可以
if (*str1 > *str2)
return 1;
else
return -1;
}
int main()
{
//strcmp - 字符串比较
//比较的是对应位置上的字符大小(ASCII码值)
char arr1[] = "abcd";
char arr2[] = "abc";
int ret = my_strcmp(arr1, arr2);
printf("%d\n", ret);
return 0;
}
注:两个字符串不能直接来比较,因为两个字符串产生的是各自首字符的地址,这两个地址肯定是不相同的。
代码的运行结果如下:
strncpy函数用于将指定长度的字符串复制到字符数组中。
函数原型:char *strncpy(char *destination, const char *source, size_t num);表示把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回被复制后的dest。
优点:灵活,更加可控,从某种程度来说会让你的函数变得相对安全一些,因为你会分析这个空间能不放得下。
示例代码:
arr数组中只有he,但是我们硬要拷贝五个字符到arr1中,那他是怎么实现的呢?我们调试的方面来看一下。从下图得到调试中我们可以看出,我们把he拷贝过去之后呢,如果没有东西了,剩下的三个空间它会主动放入'\0'进行补充。
#include
#include
char* my_strncpy(char* dest, const char* src, size_t num)
{
char* ret = dest;
assert(dest && src);
for (*src; num--; *dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[] = "xxxxxxxxx";
char arr2[] = "hello";
printf("%s\n", my_strncpy(arr1, arr2, 5));
return 0;
}
代码的运行结果如下:
strncat主要功能是在字符串的结尾追加n个字符。
函数原型:char * strncat(char *dest, const char *src, size_t num);dest指向目标字符串,src为指向源字符串。
功能:把src所指字符串的前n个字符添加到dest所指字符串的结尾处,并覆盖dest所指字符串结尾的'\0',从而实现字符串的连接。
注意:src和dest所指内存区域不可以重叠,并且dest必须有足够的空间来容纳src的字符串。返回指向dest的指针。
示例代码:
如果代码如下图所示,它会在遇到第一个'\0'时开始追加,追加完成后会在后面添上一个'\0',变成一个完整的字符串。
经过调试我们也可以看出:
如果不在arr1字符串数组中间加'\0',那么它就会出现下面这种结果,证明strncat函数就是从遇到字符串中第一个'\0'处的位置开始追加的。
如果设置追加的数字大于源字符串的本身,它会把源字符串全部追加到目标空间中去就结束了。
过程如下所示:
#include
#include
char* my_strncat(char* dest, const char* src, size_t num)
{
char* ret = dest;
assert(dest && src);
while (*dest) //先找到目标空间的'\0'
{
dest++;
}
for (*src; num--; *dest++ = *src++) //这个就相当于strncpy的功能
{
;
}
return ret;
}
int main()
{
char arr1[20] = "helloxxx";
char arr2[] = "world";
printf("%s\n", my_strncat(arr1, arr2, 4));
return 0;
}
strncmp函数和strcmp功能相似,不同点就是它的函数声明和比较的字符数是可控的。
其函数原型为:int strncmp ( const char * str1, const char * str2, size_t num );其功能还是把str1和str2进行比较,最多比较前num个字节。
#include
#include
int my_strncmp(char* str1, const char* str2, size_t num)
{
assert(str1 && str2);
while (num && *str1 == *str2)
{
if (*str1 == '\0' || *str2 == '\0')
{
break;
}
str1++;
str2++;
num--;
}
if (num == 0)
{
return 0;
}
else
return *str1 - *str2;
}
int main()
{
char arr1[] = "abclef";
char arr2[] = "abcdk";
int ret = my_strncmp(arr1, arr2, 4);
printf("%d\n", ret); // arr1 = arr2返回0
//arr1 > arr2返回大于0的数
//arr1 < arr2返回小于0的数
return 0;
}