(一)字符函数和字符串函数详细讲解和模拟实现(优化)

简介: (一)字符函数和字符串函数详细讲解和模拟实现(优化)

❤️字符串函数讲解及模拟实现

📕长度不受限制的字符串函数:

1.strcpy函数

库函数strcpy

char * strcpy ( char * destination, const char * source );
  • 将源指向的C字符串复制到目标指向的数组中,包括终止的空字符(并在此时停止)。

注意:


  • 源字符串必须以 ‘\0’ 结束。(尤其注意arr[ ]={‘a’,‘b’,‘c’};这种’ \0 '不确定的;)
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。(会以source首元素会替代destination末尾’\0’)
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可变。

目标空间必须可修改(强调)

#include<stdio.h>
#include<string.h>
int main()
{
  char* arr = "sadkajfjlsjaldj";
  char arr1[] = "hello!";
  strcpy(arr, arr1);
  printf("%s", arr);
  return 0;
}

这个代码一运行就会崩掉,原因就是目标空间为字符串,无法被修改,所以无法拷贝;

模拟实现:

#include <stdio.h>

void my_strcpy(char* dest,char* src);

int main()
{
   char arr1[20]="asdfghjkl";
   char arr2[]="hello!";
   
   my_strcpy(arr1,arr2);
   //把arr2拷贝到arr1中;
   printf("%s",arr1);
   
   return 0;
}
  • 模拟实现1:
char* my_strcpy(char* dest,char* src)
{
   while(src!='\0')
   char* ret=dest;
   {
     *dest=*src;
      dest++;
      src++;
  }
  //成功拷贝hello!
  *dest=*src;//拷贝'\0'
  return ret;
}
  • 优化:
#include<assert.h>
char* my_strcpy(char* dest,const char* src)
//我们是要src拷贝到dest,const让无需更改的来源地址变为常变量,无法修改。可防止后面*dest=*src写反;
{
   assert(src!=NULL)//断言
   assert(dest!=NULL)//断言
   //提高可调式性
   char* ret=dest;
   while(*dest++=*src++)
   {
          ;
    //直接打印hello!\0
   }
   return ret;
}


2.strcat函数

库函数strcat

char * strcat ( char * destination, const char * source );
  • 将源字符串的副本附加到目标字符串中。目标中的终止空字符将被源的第一个字符覆盖,并且在目标中两者的连接形成的新字符串的末尾包含一个空字符。

注意:

  • 源字符串必须以 ‘\0’ 结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。

模拟实现:

char* my_strcat(char* dest, const char* src)
{
  assert(dest && src);
  char* ret = dest;
  //查找\0;
  while (*dest)
    dest++;
  //追加;
  while (*src)
  {
    *dest++ = *src++;
  }
  return ret;
}

3.strcmp函数

库函数strcmp

int strcmp ( const char * str1, const char * str2 );
  • 这个函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续使用以下的对,直到字符不同或达到终止的空字符。

注意:


  • 标准规定: 第一个字符串大于第二个字符串,则返回大于0的数字 第一个字符串等于第二个字符串,则返回0 第一个字符串小于第二个字符串,则返回小于0的数字
  • 库函数中一般相等返回0;大于返回1;小于返回-1。
#include<stdio.h>
#include<string.h>
int main()
{
  char* p1 = "abcdef";
  char* p2 = "abcdef";
  char* p3 = "abcd";
  char* p4 = "bcde";
  printf("%d\n", strcmp(p1,p2 ));
  printf("%d\n", strcmp(p1,p3 ));
  printf("%d\n", strcmp(p3,p4 ));
}

  • 这里稍微补充下:我们不能进行*arr>*arr1或者“asdsfa”>“asw”比较来比较字符串大小,要借助函数。
  • 模拟实现:
int my_strcmp(const char* p1,const char* p2)
{
  assert(p1 && p2);
  while (*p1 == *p2)
  {
    if (p1 == '\0')
    //这里是表达当他们同时为'\0'就表明相等
    {
      return 0;
    }
    //如果都相等且都不等于'\0';进行++比较下一位;
    p1++;
    p2++;
  }
  //比较不相同的字符,返回差值(这里有整形提升)
  return *p1 - *p2;
}
//再借助判断即可;


📙长度受限制的字符串函数:

1.strncpy函数

库函数strncpy

char * strncpy ( char * destination, const char * source, size_t num );
  • 将源文件的第一个数个字符复制到目标文件。如果在复制num字符之前找到源C字符串的结尾(由空字符表示的信号),则将用零填充目标,直到写入了全部num字符为止。

注意:

  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加\0,直到num个

VS2019实现:

char * __cdecl strncpy (char * dest,const char * src,size_t count)
{
        assert(dest&&src);
        char *start = dest;

        while (count && (*dest++ = *src++) != '\0')    //拷贝到dest中,并且用count限制
                count--;

        if (count)                             
                while (--count)
                        *dest++ = '\0';               //完成第二步:长度不够,补'\0';

        return(start);
}

2.strncat函数

库函数strncat

char * strncat ( char * destination, const char * source, size_t num );
  • 将源代码的第一个num字符附加到目标代码中,再加上一个终止的空字符。如果源代码中的C字符串的长度小于num,则只复制直到终止的空字符的内容。
  • VS2019实现:
char * __cdecl strncat(char * front,const char * back,size_t count)
{
        char *start = front;

        while (*front++)
                ;
        front--;

        while (count--)
                if ((*front++ = *back++) == 0)
                        return(start);

        *front = '\0';
        return(start);
}

3.strncmp函数

库函数strncmp

int strncmp ( const char * str1, const char * str2, size_t num );
  • 这个函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续使用以下的对,直到num个数。

注意:

  • 比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
  • VS2019实现:
int __cdecl strncmp(const char *first,const char *last,size_t  count)
{
    size_t x = 0;

    if (!count)
    {
        return 0;
    }

    /*
     * This explicit guard needed to deal correctly with boundary
     * cases: strings shorter than 4 bytes and strings longer than
     * UINT_MAX-4 bytes .
     */
    if( count >= 4 )
    {
        /* unroll by four */
        for (; x < count-4; x+=4)
        {
            first+=4;
            last +=4;

            if (*(first-4) == 0 || *(first-4) != *(last-4))
            {
                return(*(unsigned char *)(first-4) - *(unsigned char *)(last-4));
            }

            if (*(first-3) == 0 || *(first-3) != *(last-3))
            {
                return(*(unsigned char *)(first-3) - *(unsigned char *)(last-3));
            }

            if (*(first-2) == 0 || *(first-2) != *(last-2))
            {
                return(*(unsigned char *)(first-2) - *(unsigned char *)(last-2));
            }

            if (*(first-1) == 0 || *(first-1) != *(last-1))
            {
                return(*(unsigned char *)(first-1) - *(unsigned char *)(last-1));
            }
        }
    }

    /* residual loop */
    for (; x < count; x++)
    {
        if (*first == 0 || *first != *last)
        {
            return(*(unsigned char *)first - *(unsigned char *)last);
        }
        first+=1;
        last+=1;
    }

    return 0;
}


📘求字符串长度:

1.strlen函数:

库函数strlen

size_t strlen ( const char * str );
  • 读取字符串长度,并返回长度。
  • 注意:
  • 字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包
    含 ‘\0’ )。
  • 参数指向的字符串必须要以 ‘\0’ 结束。
  • 注意函数的返回值为size_t,是无符号的( 易错 )因为统计字符串长度都为正数。

易错点补充:

思考:输出的结果是大于还是小于?

#include<stdio.h>
#include<string.h>
int main()
{
  char arr[] = "asdasf";
  char arr1[] = "uqiwhdqio";
  if (strlen(arr) - strlen(arr1) < 0)
  {
    printf("小于");
  }
  else
  {
    printf("大于");
  }
  return 0;
}

  • 为什么结果是大于?难道不是我们理解的6-9=-3吗?别急听我为你解释。


  • 在库函数<string.h>中strlen返回的是size_t(也就是我们理解的无符号类型)
  • 我们说(有符号数-有符号数)得到有符号数,同样的(无符号数-无符号数)得到的也是无符号数(如果计算机没有别的格式化要求);格式化要求比如printf,用%d来打印这就是一种格式化要求;
#include<stdio.h>
#include<string.h>
int main()
{
  char arr[] = "asdasf";
  char arr1[] = "uqiwhdqio";
  printf("%u", strlen(arr) - strlen(arr1));
  //为了展现我们就以%u打印(计算机中也默认为无符号数,上述打印大于就能证明);结果为4294967293
  return 0;
}```
==>具体的计算过程:<==
//6----->00000000 00000000 00000000 00000110 原码--->补码
//9----->00000000 00000000 00000000 00001001 原码--->补码
//-9---->10000000 00000000 00000000 00001001 原码
//-9---->11111111111111111111111111111110111 补码
//-3---->11111111 11111111 11111111 11111101 无符号数打印

模拟实现:

  • 优化方式和strcpy相近,若没看上述,建议先看更好,观感更佳,这就直接代码体现:
  • 主函数:
int main()
{
 char arr[]='ashduhewu';
 
 printf("%d",my_strlen(arr));

  return 0;
}
  • 1.常规实现:
#include<stdio.h>
#include<assert.h>

size_t my_strlen(const char* str)
//size_t相当于unsigned int,因为字符串长度一定为正整数,并且传入的字符串无需更改,所以加上const修饰*str;
{
    assert(str);
    //直接写str,若str为NULL,返回的是0,判断为假,报错提醒;
    int count = 0;
    while(str!='\0')
    {
       count++;
       str++;
  }
   return (unsigned int) count;
}
  • 2.递归实现:
int my_strlen(const char* str)
{
  if (*str == '\0')
    return 0;
  else return 1 + my_strlen(str + 1);
  //先遍历,后返回,总返回:return 【(*str=='\0';遍历结束,开始返回)0+1+1+1+···+1】
}

  • 3.指针实现:
int my_strlen(const char* str)
{
  char* p = str;
  while (*p != '\0')
    p++;
  //得到末尾地址
    return (p - str);
  //返回得到两地址间数组元素个数的绝对值
  //数组元素是低地址到高地址排列,所以建议用末尾地址减去初始地址,得到正数;
}

Tips:细心的小伙伴已经发现了,下面两个函数模拟,我们返回类型是int而并非size_t(unsigned int),这里是想要告诉大家,库函数只是一个给定的方式,仅仅是一种方式(当然也是比较好的方式),但我们要根据所需进行自己的更改!

相关文章
|
20天前
(二)字符函数和字符串函数详细讲解和模拟实现(优化)
(二)字符函数和字符串函数详细讲解和模拟实现(优化)
|
1月前
|
安全
16.字符串函数的使用和模拟实现(全)
16.字符串函数的使用和模拟实现(全)
|
2月前
字符串函数的模拟实现
字符串函数的模拟实现
22 1
|
2月前
|
C语言
字符函数和字符串函数解析及模拟实现
字符函数和字符串函数解析及模拟实现
52 0
|
7月前
|
编译器 C语言
字符串函数的使用及模拟实现
字符串函数的使用及模拟实现
27 0
|
7月前
|
程序员
字符串函数的使用及其模拟实现
字符串函数的使用及其模拟实现
39 0
|
9月前
|
C语言 C++
C/C++字符函数和字符串函数详解————内存函数详解与模拟
C/C++字符函数和字符串函数详解————内存函数详解与模拟
30 1
|
12月前
|
C语言
深入探索字符串函数与模拟实现
深入探索字符串函数与模拟实现
81 1
深入探索字符串函数与模拟实现
字符函数和字符串函数的使用及模拟实现(上)(2)
字符函数和字符串函数的使用及模拟实现
71 0