【C语言】字符串相关函数的实现

一、strcpy函数

1.将基本的功能实现:把目标数组的内容换成源数组的内容。

void my_strcpy (char* dest,char* src)
{
    //字符串内容的拷贝
    while (*src != '\0') {
        *dest = *src;
        dest++;
        src++;
    }
    //\0的拷贝
    *dest = *src;
}

思路:(1).字符串内容的拷贝:将源数组的第一个字符赋值给目标数组的第一个,之后源数组和

目标数组的指针向后挪一位,直到当移动到src指向\0时,不满足循环条件,退出循环。此时已经

将字符串内容部分全部拷贝完成,但是由于*src==‘\0’时没有进入循环,所以没有将\0赋值给目标

数组,需要单独将\0赋值给目标数组。

(2).\0的拷贝:现在*src==‘\0‘,所以直接将*src赋值给*dest即可。

2.简单优化

void my_strcpy (char* dest,char* src)
{
    //字符串内容的拷贝
    while (*src != '\0') {
        *dest++ = *src++;
    }
    //\0的拷贝
    *dest = *src;
}

思路:原本是先解引用在++,所以可以合并成后置++,即*dest++ = *src++  ==>  做的是先解引

用,后++,和1中的循环体内的代码等价。

3.进一步优化

void my_strcpy (char* dest,char* src)
{
    //实现了整个字符串的拷贝
    while ((*dest++ = *src++)) {
        ;
    }
}

思路:将*dest++ = *src++放到循环判断条件里,就可以将整个字符串拷贝过去。

原因:例如刚开始时,将源数组的首元素赋值给目标数组,循环判断条件就为*dest的值,一定

不为0,所以为真,循环会继续······ 直到当src指针挪到\0时,这时将\0赋值给*dest,判断条

件的值为0(\0的ASCII值为0),判断为假,循环结束,但是\0也赋值给了*dest,所以就完成了

整个字符串的拷贝。

4.优化为易于调试的代码 -- assert断言 -- 使用头文件#include <assert.h>

assert():用于在调试过程中捕捉程序错误。

括号内如果为真,则程序继续运行;为假,程序停止运行,并报错。

void my_strcpy (char* dest,char* src)
{
    assert(src != NULL);
    assert(dest != NULL);
    
    //实现了整个字符串的拷贝
    while ((*dest++ = *src++)) {
        ;
    }
}

思路:进入函数首先利用assert,判断传过去的dest和src是否为空指针。如果是NULL,程序停

止运行,并报错;如果不是,程序继续运行。

5.进一步优化为易于调试的代码

(1)回顾const:const修饰变量,这个变量就被称为常变量,不能被修改,但是本质上还是变量

 但是观察这段代码发现:num是const修饰的变量,理论上来说不能被修改。但是通过找到num

的地址从而改变了num的值。这种操作违反了const不能被修改的本意。

(2)想要实现真正的不能被修改:介绍const修饰指针变量

     int*       p有两个放const的位置:const int* p和int* const p

​​​​​​​  (a)const放在*的左边(const int* p):修饰的是*p,表示指针指向的内容,是不能通过指针来改

变的;但是指针变量本身是可以修改的。

 这时*p即num的值不可以改变。(达到const的本意:不可修改值)

 但是p的值(地址)可以改变的。

  (b)const放在*的右边(int* const p):修饰的是指针变量p,表示指针变量不能被改变;但是指针

指向的内容,可以被改变。

这时p的值(地址)不可以改变。 (没有达到const的本意:不可修改值)

但是*p即num的值可以被改变了。

  (c)const int* const p:p不可以改变,*p也不可以改变。

strcpy函数:把src指向的内容拷贝放进dest指向的空间中。从本质上讲,希望dest指向的内容被

修改,src指向的内容不应该被修改。

现在利用const修饰指针变量来优化,来保护 *src​​​​​​​ 不被修改。

void my_strcpy (char* dest,const char* src)
{
    assert(src != NULL);
    assert(dest != NULL);
    
    //实现了整个字符串的拷贝
    while ((*dest++ = *src++)) {
        ;
    }
}

6.实现与库函数strcpy()基本相同的结果

库函数strcpy()的返回值类型是char* ,返回的是目标空间的起始地址。这样做的好处是可以实现

函数的链式访问。

char* my_strcpy (char* dest,const char* src)
{
    assert(src != NULL);
    assert(dest != NULL);
    
    //记录目标空间的起始地址
    char* ret = dest;
    
    //实现了整个字符串的拷贝
    while ((*dest++ = *src++)) {
        ;
    }
    
    //返回目标空间的起始地址
    return ret;
}
    char arr1[] = "xxxxxxxxxxxxx";
    char arr2[] = "hello";
    
    printf("%s\n",my_strcpy(arr1,arr2));//链式访问

二、strlen函数

目前已知有三种方法可以实现strlen函数:计数器版本(无assert和const),递归版本,指针-指针

1.创建临时变量(计数器版本)求解

思路:将数组传过去,从字符串的第一个字符开始判断,如果第一个字符不是\0,那么加一记录

一个字符(count++),并且将字符串向后挪一位(str++),如果检测到\0,结束循环,返回count,

即字符串长度。

int my_strlen(char* str)
{
    int count = 0;
    while(*str != '\0'){
        count++;//记录字符个数
        str++;//字符向前一位
    }
    return count;
}

2.利用assert和const 优化strlen函数

思路:为了防止有人传空指针,所以加上assert;strlen函数本质上是不会改变字符串内容的,所

以用const修饰从而保护字符串内容。这样做可以增加代码的健壮性(鲁棒性)。

int my_strlen (const char* str)
{
    assert(str != NULL);
    
    int count = 0;
    while (*str != '\0') {
        count++;
        str++;
    }
    return count;
}

3.又发现字符串长度一定是一个整数,所以可以将返回值类型改为unsigned int (size_t)

size_t my_strlen (const char* str)
{
    assert(str != NULL);
    
    int count = 0;
    while (*str != '\0') {
        count++;
        str++;
    }
    return count;
}

三、strcat函数

思路:先将dest指向‘\0’,在追加源字符串(相当于strcpy)

最后返回目标字符串的地址

char* my_strcat (char* dest ,const char* src)
{
    char* ret = dest;
    //断言
    assert(dest && src);
    
    //1.先找到dest的\0
    while (*dest!='\0') {
        dest++;
    }
    
    //2.追加源字符串,源字符串的全部(字符部分和\0)
    while ((*dest++ = *src++)) {;}
    
    return ret;
}

四、strcmp函数

思路:一个一个字符比,相等返回0

int my_strcmp (const char* str1 ,const char* str2)
{
    assert(str1 && str2);

    while (*str1==*str2)
    {
        if(*str1 == '\0')
        {
            return 0;
        }
        str1++;
        str2++;
    }
    if(*str1>*str2)
        return 1;
    else
        return -1;
}
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
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值