个人主页(找往期文章包括但不限于本期文章中不懂的知识点):我要学编程(ಥ_ಥ)-CSDN博客
目录
strlen的使用与模拟实现
函数原型:
size_t strlen ( const char * str );//求字符串的长度
• 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )。
• 参数指向的字符串必须要以 '\0' 结束。
• 注意函数的返回值为size_t,是无符号的
• strlen的使用需要包含头文件 <string.h>
• 学会strlen函数的模拟实现
strlen的使用
#include <stdio.h>
#include <string.h>
int main()
{
char ch[] = "abcdef";//有'\0'结尾
size_t ret = strlen(ch);
printf("%zd\n", ret);
return 0;
}
#include <stdio.h>
#include <string.h>
int main()
{
char ch[] = { 'a','b','c' };//没有以'\0'结尾
size_t ret = strlen(ch);
printf("%zd\n", ret);
return 0;
}
strlen的模拟使用
方法1(计数器的方式):
#include <stdio.h>
#include <assert.h>//断言包含的头文件
size_t my_strlen(const char* str)
{
size_t count = 0;
assert(str);//不等于空指针程序正常运行
while (*str)//当不等于'\0'时,进入
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
size_t ret = my_strlen(arr);
printf("%zd\n", ret);
return 0;
}
方法2(指针-指针的方式) :
#include <stdio.h>
#include <assert.h>
size_t my_strlen(const char* str)
{
assert(str);
const char* str2 = str;//记录起始位置
while (*str)
{
str++;
}
return str - str2;//末地址-起始地址就是两者之间的元素个数
}
int main()
{
char arr[] = "abcdef";
size_t ret = my_strlen(arr);
printf("%zd\n", ret);
return 0;
}
方法3(递归的方式):
#include <stdio.h>
#include <assert.h>
size_t my_strlen(const char* str)
{
assert(str);
if (*str == '\0')
{
return 0;//当为'\0'时,就返回
}
return 1 + my_strlen(++str);
}
int main()
{
char arr[] = "abcdef";
size_t ret = my_strlen(arr);
printf("%zd\n", ret);
return 0;
}
递归存在一个限制条件,并且随着递归的深入越来越接近这个限制条件。这个限制条件应该是比较容易想到的, 就是等于'\0'的时候,写法和求n的阶乘类似。
strcpy的使用与模拟实现
函数原型:
char* strcpy(char * destination, const char * source );//字符串的拷贝
source是被拷贝字符串,即源字符串;destination是把字符串拷贝到这里,即目标字符串。其返回类型是char*,返回的是一个地址:目标字符串的起始地址。
• 源字符串必须以 '\0' 结束。
• 会将源字符串中的 '\0' 拷贝到目标空间。
• 目标空间必须足够大,以确保能存放源字符串。
• 目标空间必须可修改。(当目标空间有时,也是从源头开始拷贝,这也就导致了一个问题,目标空间原来的字符串被覆盖了。)
• 学会模拟实现。
strcpy的使用
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = { 0 };//当目标空间不足时,也会完全拷贝,但是会报错
char arr2[] = "abcdef";
strcpy(arr1, arr2);
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
因此源字符串也是要以'\0'结尾,因为这样才能知道拷贝的具体内容。
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[10] = "abc";
char arr2[] = "edf";
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
如果要把 edf 搞到 abc 的后面需要用到另外一个函数strcat 。
上面这个就是目标空间不足时(会导致越界访问),报错界面。
strcpy的模拟实现:
根据前面的函数原型我们就可以开始来来模拟实现strcpy函数了。首先得想出思路:是将源字符串的字符赋值给目标空间,然后指向两者地址的指针往后走,直至遇到源字符串的'\0'就可以停止了。
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* str1, const char* str2)
{
assert(str1 && str2);//限制不为空指针
char* p = str1;
while (*str2)//当还没有遇到'\0'时,就继续拷贝
{
*str1 = *str2;
str1++;
str2++;
}
//因为我们要返回目标空间的初始地址,就得记录一下初始地址
return p;
}
int main()
{
char arr1[20] = { 0 };
char arr2[] = "abcdef";
char* ret = my_strcpy(arr1, arr2);
my_strcpy(arr1, arr2);
printf("%s\n", ret);//ret接收的时arr1的初始地址,也就是首元素的地址
printf("%s\n", arr1);//数组名是首元素的地址,因此这两个打印的结果是相同的
return 0;
}
当然这个模拟实现strcpy的部分还可以简化一些。
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* str1, const char* str2)
{
assert(str1 && str2);//限制不为空指针
char* p = str1;
//这个可以根据优先级来理解:++(后置)> * > = ,由于是后置++,所以是先使用str1与str2
//即*str1 与 *str2,再++,最后再赋值
while(*str1++ = *str2++)
{
;
}
//因为我们要返回目标空间的初始地址,就得记录一下初始地址
return p;
}
int main()
{
char arr1[20] = { 0 };
char arr2[] = "abcdef";
char* ret = my_strcpy(arr1, arr2);
my_strcpy(arr1, arr2);
printf("%s\n", ret);
printf("%s\n", arr1);
return 0;
}
strcat的使用与模拟实现
函数原型:
char * strcat ( char * destination, const char * source );//字符串的拼接(追加)
这些函数参数也是和strcpy一样的意义,source是要拼接的字符串,destination是被拼接的字符串。其返回的是char*,是目标空间的起始地址
• 源字符串必须以 '\0' 结束。
• 目标字符串中也得有 '\0' ,否则没办法知道追加从哪里开始(在追加的时候会把这个'\0',给覆盖掉)。
• 目标空间必须有足够的大,能容纳下源字符串的内容。
• 目标空间必须可修改。
• 字符串自己给自己追加,如何?
strcat的使用
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = "hello ";//当这个空间不足时,虽然依然会完全追加,但是会报错
char arr2[] = "world";
char* p = strcat(arr1, arr2);
printf("%s\n", p);
return 0;
}
当目标空间不足时,报错界面与上面的一样,也是越界访问导致的。
strcat的模拟实现
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* str1, const char* str2)
{
assert(str1 && str2);//控制不是空指针
char* p = str1;
//我们得先找到目标字符串的'\0',再在'\0'后追加
while (*str1)
{
str1++;
}
//当跳出这个while循环就代表我们已经找到这个'\0'的地址了,接下来开始追加
while (*str2)//这个也可以和上面那个strcpy一样简化
{
*str1 = *str2;
str1++;
str2++;
}
*str1 = *str2;//因为while循环里没有把'\0'追加到目标字符串
return p;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
char* ret = my_strcat(arr1, arr2);
printf("%s\n", ret);
printf("%s\n", arr1);
return 0;
}
strcmp的使用与模拟实现
函数原型:
int strcmp ( const char * str1, const char * str2 );//字符串的比较
str1与str2就是我们想要比较的字符串。其返回类型是 int ,当str1 > str2时,返回大于0的数;当str1 == str2时,返回等于0的数;当str1 < str2时,返回0。比较两个字符串中对应位置上字符ASCII码值的大小。 而在比较时,是一个字符一个字符的比较。
例如:我们比较 abc 与 abq时,是 a 与 a 比较,当它们相等时,就比较下一个,会一直比较到两个字符不相等(当出现了字符不相等的时候,比较也就结束了。即使后面还有也不再比较),或者全部比较完。就像上面那个例子,当我们比较到 c 与 q 时,c < q,就会返回一个小于0的数字。(注意会比较到'\0'才停止)
strcmp的使用
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abc";
int ret = strcmp(arr1, arr2);
printf("%d\n", ret);
return 0;
}
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abq";
int ret = strcmp(arr1, arr2);//q>c,也就是arr1<arr2,输出一个小于0的数
printf("%d\n", ret);
return 0;
}
有细心的小伙伴可能会发现,这个arr1大于arr2,输出的是一个数字1。其实这个还是和编译器有关的,我这个是VS2022,大于0,输出的就是1;小于0,就是输出-1。
strcmp的模拟实现
#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
//本来是*str1 == *str2 == '\0',但因为*str1 == *str2,所以就简写
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
//如果要和编译器一样的话,就可以写成:
/*if (*str1 - *str2 > 0)
{
return 1;
}
else if (*str1 - *str2 < 0)
{
return -1;
}*/
return *str1 - *str2;//返回两者不相等的情况
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abq";
int ret = my_strcmp(arr1, arr2);
printf("%d\n", ret);
return 0;
}
上面这一系列函数是长度没有限制的。例如:在拷贝时,我们没有限制拷贝几个字符;在追加时,没有限制追加几个字符;在比较时,没有比较几个字符。但是如果我们想要限制长度,怎么实现呢?C语言库还给出了长度限制的一系列函数,这类函数就让我们下期一起来学习吧!。