目录
1.strlen
重点:
模拟实现:
法一:
法二:
法三:
2.strcpy
重点:
模拟实现:
3.strcat
重点:
模拟实现:
4.strcmp
重点:
模拟实现
1.strlen
strlen函数是用来计算字符串长度的
重点:
-
字符串以
'\0'
作为结束标志,
strlen
函数返回的是在字符串中
'\0'
前面出现的字符个数(不包含 '\0'
)
。
-
注意函数的返回值为
size_t
,是无符号的(
易错
)
-
1.
这里答案为6,确实是有6个字符,但是没有看到'\0'啊!
其实,'\0'是在最后一个字符后面自动添加的。
我们进一步验证该字符函数是以'\0'来计算字符串长度的我们可以在字符串的中间部分手动添加一个'\0'。
这时,字符串就提前终止,计算到的数值为3。
2.
前面字符串的长度为3,后面字符串的长度为4,按理说应该是打印小于号,但是这里却是大于号!
其实,无论你怎么减,这里都只能是大于号,因为strlen函数的定义类型就是size_t类型,即无符号整形,所以无论如何他都是大于0的。
3.
如上图代码,字符串中只有4个字符,但是却输出有74个字符,那是因为,这种定义的字符串后面不会自动添加'\0',strlen函数要一直向后读取,直到找到'\0'为止,这个数值是随机的。
因此,strlen函数的参数指向的字符串必须要以 '\0' 结束。
模拟实现:
创建一个my_strlen函数,模拟实现strlen函数的功能:
法一:
计数器的方式,只要遇到'\0'就停止
size_t my_strlen(const char* str)//返回值类型和参数与原函数保持一致
{
int num = 0;
while (*str != '\0')//当不等于'\0'时进入循环
{
num++;//计数器加一
str++;//向后移动一位
}
return num;//最后循环结束,返回计数器的值,即为字符串的长度
}
int main()
{
char arr[] = "abcdef";
int ret = my_strlen(arr);
printf("%d\n", ret);
return 0;
}
法二:
不能创建临时变量计数器,使用递归算法:
size_t my_strlen(const char* str)//返回值类型和参数与原函数保持一致
{
if (*str == '\0')//若该字符为'\0'就返回0.
return 0;
else
return 1 + my_strlen(str + 1);//不是'\0'就返回1+my_strlen(str+1),实现递归
}
int main()
{
char arr[] = "abcdef";
int ret = my_strlen(arr);
printf("%d\n", ret);
return 0;
}
法三:
指针-指针的方式:(我们之前讲过指针-指针得到的时两个指针间的元素个数)
size_t my_strlen(const char* str)//返回值类型和参数与原函数保持一致
{
char* p = str;//创建一个char* 类型保存字符串的起始位置
while (*str != '\0')//当*str不为'\0'时,str++一下指向下一个字符,否则结束循环,
str++; //否则结束循环,得到字符串的结束位置
return str - p;//最终两个指针相减,得到中间的元素个数
}
int main()
{
char arr[] = "abcdef";
int ret = my_strlen(arr);
printf("%d\n", ret);
return 0;
}
2.strcpy
strcpy函数是将source指向的字符串拷贝到destination指向的空间中,同时覆盖该空间中原有的字符串
重点:
-
源字符串必须以
'\0'
结束。
-
会将源字符串中的 '\0'
拷贝到目标空间。
-
-
1.
与上一个strlen函数相似,这里需要'\0'来判断拷贝是否完成,当source指向的字符串读取到'\0'时拷贝就结束了。
2.
int main()
{
char arr1[] = "abcdefghij";
char arr2[] = "qwerhhhh";
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
通过监视,我们发现arr1字符串中有两个'\0',其中红色的'\0'是由arr2字符串拷贝过来的,黑色的'\0'是arr1字符串中自带的。
3.
这条就不用过多解释了吧,目标空间不够大的话根本拷贝不过去的,编译器也会报错。
4.
目标空间的内容必须可变,不能是常量字符串。
发生访问冲突,就是p指向的这个常量字符串不可以被修改,就不能使用strcpy函数。
模拟实现:
创建一个my_strcpy函数,模拟实现strcpy函数的功能:
#include <assert.h>//assert函数所需的头文件
char* my_strcpy(char* dest, const char* src)//返回值类型和参数类型与原函数保持一致,
{//dest所指向的字符串需要被修改,不用const保护,src所指向的字符串不需要被修改用const修饰保护
assert(dest && src);//断言一下,保证两个指针均不为空指针,若为空指针则中止程序并报错
char* ret = dest;//创建一个char*变量保存起始地址,后面需要返回起始地址
while (*dest++ = *src++)//将src所指向的内容赋值给dest所指向的内容,
; //也可以赋值'\0'然后就被判定为假,退出循环
return ret;//返回起始地址,容易形成链式访问
}
int main()
{
char arr1[] = "xxxxxxxxxxx";
char arr2[] = "abcdef";
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
3.strcat
在destination指向的字符串后面追加一个source指向的字符串
int main()
{
char arr1[15] = "hello ";
char arr2[] = "world!";
strcat(arr1, arr2);
return 0;
}
重点:
-
源字符串必须以
'\0'
结束。
-
目标空间必须有足够的大,能容纳下源字符串的内容。
-
目标空间必须可修改。
-
1、2、3.
与上面所诉的strcpy函数相似,这里就不多赘述了。
4.
int main()
{
char arr1[15] = "hello \0xxxxxxx";
char arr2[] = "world!";
strcat(arr1, arr2);
return 0;
}
通过监视,我们发现arr1字符串中有两个'\0',其中红色的'\0'是由arr2字符串追加过来的,黑色的'\0'是arr1字符串中自带的。
模拟实现:
创建一个my_strcat函数,模拟实现strcat函数的功能:
#include <assert.h>
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest; //上面的代码与前几个模拟实现的函数原因相同,这里就不多赘述了
while (*dest != '\0') //找到dest指针指向的字符串的末尾的'\0'
dest++;
while (*dest++ = *src++)//将src所指向的内容赋值给dest所指向的内容,
; //也可以赋值'\0'然后就被判定为假,退出循环
return ret;//最后返回字符串的起始地址
}
int main()
{
char arr1[15] = "abcdef";
char arr2[] = "1234";
printf("%s\n", my_strcat(arr1, arr2));
return 0;
}
4.strcmp
strcmp是用来比较两个字符串大小的
重点:
strcmp比较的是对应位置上字符的大小,而非字符串的长度
模拟实现:
创建一个my_strcmp函数,模拟实现strcmp函数的功能:
#include <assert.h>
int my_strcmp(const char* str1, const char* str2)//返回值类型和参数类型与原函数保持一致
{ //该函数只是比较两个字符串的大小,不对字符串进行修改,所以用const保护起来
assert(str1 && str2); //断言,防止参数为NULL
while (*str1 == *str2) //比较字符,当两字符不同时就跳出来
{
if (*str1 == '\0')
return 0; //判断是否已经比较到了末尾,若为'\0'则表示两字符串相等
str1++;
str2++;
}
return *str1 - *str2; //返回直接就用两字符相减
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcefg";
printf("%d\n", my_strcmp(arr1, arr2));
return 0;
}