字符串函数、字符函数、内存函数的使用及其模拟实现(1)

简介: 字符串函数、字符函数、内存函数的使用及其模拟实现(1)

字符串长度

strlen

函数功能

字符串长度,求一个字符串中字符的个数(不包含’\0’)。

函数参数

size_t strlen( const char *string );
# size_t 是函数的返回类型
# char* string 是函数参数

函数使用

#include <stdio.h>
#include <string.h>  //strlen对应头文件
int main()
{
  char arr[] = "abcdef";
  int len = strlen(arr);
  printf("%d\n", len);
  return 0;
}

2020062310470442.png

模拟实现(初阶)

#include <stdio.h>
#include <assert.h>  //assert对应头文件
size_t my_strlen(const char* str)
{
  assert(str != NULL);   //检查str是否为空指针
  int count = 0;
  while (*str != '\0')
  {
    str++;
    count++;
  }
  return count;
}
int main()
{
  char arr[] = "abcdef";
  int len = my_strlen(arr);
  printf("%d\n", len);
  return 0;
}

2020062310470442.png

模拟实现(进阶)

#include <stdio.h>
#include <assert.h>  //assert对应头文件
size_t my_strlen(const char* str)   //const用于保护源字符串不被修改
{
  assert(str != NULL);
  char* head = str;      //记录字符串开头的地址
  while (*str++);        //找到字符串结束的地址
  return str - head - 1; //指针-指针得到元素个数,-1减去\0
}
int main()
{
  char arr[] = "abcdef";
  int len = my_strlen(arr);
  printf("%d\n", len);
  return 0;
}

2020062310470442.png

注意事项

  • 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含’\0’)。
  • 函数参数指向的字符串必须要以 ‘\0’ 结束,否则得到的就是随机值(strlen会一直往后找,直到遇到’\0’才结束)。(常考)
  • 注意函数的返回值为size_t,是无符号的。(易错:可能出现算术转换)

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

strcpy

函数功能

字符串拷贝,把一个字符串里面的内容拷贝到另一个字符串中去(包括’\0’)。

函数参数

char* strcpy(char * destination, const char * source );
# char* 是函数的返回值,返回的是目标空间的起始地址
# source 是要拷贝的字符串
# destination 是目标空间

函数使用

#include <stdio.h>
#include <string.h>  //strcpy对应头文件
int main()
{
  char arr1[] = "abcdef";
  char arr2[10] = "";
  strcpy(arr2, arr1);
  printf("%s\n", arr2);
  return 0;
}

2020062310470442.png

模拟实现(初阶)

#include <stdio.h>
#include <assert.h>  //assert对应头文件
char* my_strcpy(char* dest, const char* src)  //const用于保护源字符串
{
  assert(dest && src);  //保证传递过来的不是空串
  char* ret = dest;  //记录目标空间的起始地址
  while (*src != '\0')
  {
    *dest = *src;
    dest++;
    src++;
  }
  *dest = *src;  //将末尾的'\0'赋给dest
  return ret;
}
int main()
{
  char arr1[] = "abcdef";
  char arr2[10] = "";
  my_strcpy(arr2, arr1);
  printf("%s\n", arr2);
  return 0;
}

2020062310470442.png

模拟实现(进阶)

#include <stdio.h>
#include <assert.h>  //assert对应头文件
char* my_strcpy(char* dest, const char* src)  //const用于保护源字符串
{
  assert(dest && src);  //保证传递过来的不是空串
  char* ret = dest;  //记录目标空间的起始地址
  while (*dest++ = *src++);  //连同末尾的'\0'一起赋给了dest
  return ret;
}
int main()
{
  char arr1[] = "abcdef";
  char arr2[10] = "";
  my_strcpy(arr2, arr1);
  printf("%s\n", arr2);
  return 0;
}

2020062310470442.png

注意事项

  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可变。

strcat

函数功能

字符串追加,在一个字符串的末尾追加另外一个字符串(包括’\0’)。

函数参数

char * strcat ( char * destination, const char * source );
# char* 是函数的返回值,返回的是目标空间的起始地址
# source 是要追加的字符串
# destination 是目标空间

函数使用

#include <stdio.h>
#include <string.h>  //strcat对应头文件
int main()
{
  char arr1[] = "world!";
  char arr2[20] = "hello ";
  strcat(arr2, arr1);
  printf("%s\n", arr2);
  return 0;
}

2020062310470442.png

模拟实现(初阶)

#include <stdio.h>
#include <assert.h>
//字符串追加可以分为两部分:1、找到目标字符串的末尾 2、字符串拷贝
char* my_strcat(char* dest, const char* src)  //const用于保护源字符串
{
  assert(dest && src);  //保证传递过来的不是空串
  char* ret = dest;  //记录目标空间的起始地址
  while (*dest != '\0')  //找到目标空间的末尾
  {
    dest++;
  }
  while (*src != '\0')
  {
    *dest = *src;
    dest++;
    src++;
  }
  *dest = *src;  //将末尾的'\0'赋给dest
  return ret;
}
int main()
{
  char arr1[] = "world!";
  char arr2[20] = "hello ";
  my_strcat(arr2, arr1);
  printf("%s\n", arr2);
  return 0;
}

2020062310470442.png

模拟实现(进阶)

#include <stdio.h>
#include <assert.h>
//字符串追加可以分为两部分:1、找到目标字符串的末尾 2、字符串拷贝
char* my_strcat(char* dest, const char* src)  //const用于保护源字符串
{
  assert(dest && src);  //保证传递过来的不是空串
  char* ret = dest;  //记录目标空间的起始地址
  while (*dest++ != '\0');   //找到目标空间的末尾
  dest--;  //抵消最后一次自增的副作用
  while (*dest++ = *src++);  //字符串拷贝
  return ret;
}
int main()
{
  char arr1[] = "world!";
  char arr2[20] = "hello ";
  my_strcat(arr2, arr1);
  printf("%s\n", arr2);
  return 0;
}

2020062310470442.png

注意事项

  • 源字符串必须以 ‘\0’ 结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。
  • strcat 函数不能自己给自己追加。(追加会覆盖掉末尾的’\0’,导致死循环)

strcmp

函数功能

字符串比较,以字节为单位比较两个字符串的大小

函数参数

int strcmp ( const char * str1, const char * str2 );
# int 函数返回值
# char* str1  char* str2 用于比较的两个字符串

函数返回值

>0 : str1 大于 str2;
=0 : str1 等于 str2;
<0 : str1 小于 str2

函数使用

#include <stdio.h>
#include <string.h>  //strcmp对应头文件
int main()
{
  char str1[] = "abcdef";
  char str2[] = "abq";
  int ret = strcmp(str1, str2);
  printf("%d\n", ret);
  return 0;
}

2020062310470442.png

模拟实现

#include <stdio.h>
#include <assert.h>  //assert对应头文件
int my_strcmp(const char* str1, const char* str2)
{
  assert(str1 && str2);
  while (*str1 == *str2 && *str1 != '\0' && *str2 != '\0')  //找到字符串中不相等字符的位置
  {
    str1++;
    str2++;
  }
  if (*str1 != '\0' && *str2 != '\0')   //如果此位置不是字符串末尾,则不相等,返回差值
    return *str1 - *str2;
  return 0;  //若前面没返回,说明相等,返回0
}
int main()
{
  char str1[] = "abcdef";
  char str2[] = "abq";
  int ret = my_strcmp(str1, str2);
  printf("%d\n", ret);
  return 0;
}

2020062310470442.png

20200623104134875.png

注意事项

  • 对每一对字符进行比较,直到遇到不相等的字符或者遇到’\0’。
  • 比较的是每一对字符的ASCII值。


长度受限制的字符串函数

由于strcpy、strcat、strcmp等字符串函数存在安全隐患(目标空间小于源空间等问题),C语言还提供了另外几种相对安全的字符串函数,即strncpy、strncat、strncmp,这些字符串函数相比于原字符串函数多了一个参数,用于指定操作的字节数。(注意:strncpy、strncat、strncmp函数只是相对安全,并不是绝对安全,多一个参数只是起到一个提醒作用)

strncpy

函数功能

字符串拷贝,把一个字符串中num个字节的内容拷贝到另一个字符串中去。

函数参数

char * strncpy ( char * destination, const char * source, size_t num );
# char* 是函数的返回值,返回的是目标空间的起始地址
# source 是要拷贝的字符串
# destination 是目标空间
# num 是要拷贝的字节数

    函数使用

    #include <stdio.h>
    #include <string.h>  //strncpy对应的头文件
    int main()
    {
      char arr1[] = "abcdef";
      char arr2[10] = "";
      strncpy(arr2, arr1, sizeof(arr1) / sizeof(arr1[0]) * 1);
      //sizeof(arr)/sizeof(arr[0]) 求得数组元素个数,*1 乘以每个元素的大小,得到整个数组的字节数
      printf("%s\n", arr2);
      return 0;
    }
    
      2020062310470442.png 2020062310470442.png

    模拟实现

    //模拟实现strncpy
    #include <stdio.h>
    #include <assert.h>
    char* my_strncpy(char* dest, const char* src, size_t num)
    {
      assert(dest && src);
      char* ret = dest;  //记录目标空间的起始地址
      while (num--)
      {
        *dest = *src;
        if (*dest == '\0')  //如果*dest为0,说明将src的结束字符赋给了dest,这种情况下源字符串的长度小于num
        {
          while (num--)
          {
            //如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。(与库函数的实现方式保持一致)
            *dest++ = 0;
          }
          break;
        }
            dest++;
            src++;
      }
      *dest = '\0';  //在dest的末尾补上结束字符
      return ret;
    }
    int main()
    {
      char arr1[] = "abc";
      char arr2[10];
      my_strncpy(arr2, arr1, 4);
      printf("%s\n", arr2);
      return 0;
    }

    2020062310470442.png

    20200623104134875.png

    注意事项

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

    strncat

    函数功能

    字符串追加,将一个字符串中num个字节的内容追加到另一个字符串的末尾,并在最后面加上’\0’。

    函数参数

    char * strncat ( char * destination, const char * source, size_t num );
    # char* 是函数的返回值,返回的是目标空间的起始地址
    # source 是要追加的字符串
    # destination 是目标空间
    # num 是要追加的字节数

    函数使用

    #include <stdio.h>
    #include <string.h>  //strncat对应的头文件
    int main()
    {
      char arr1[] = "world!";
      char arr2[20] = "hello ";
      strncat(arr2, arr1, sizeof(arr1) / sizeof(arr1[0]) * 1);
      //sizeof(arr)/sizeof(arr[0]) 求得数组元素个数,*1 乘以每个元素的大小,得到整个数组的字节数
      printf("%s\n", arr2);
      return 0;
    }

    2020062310470442.png

    模拟实现

    #include <stdio.h>
    #include <assert.h>
    char* my_strncat(char* dest, const char* src, size_t num)
    {
      assert(dest && src);
      char* ret = dest;  //记录目标空间的起始地址
      //找到dest末尾
      while (*dest != '\0')
      {
        dest++;
      }
      //strncpy
      while (num--)
      {
        *dest = *src;
        if (*dest == '\0')  //如果*dest为0,说明将src的结束字符赋给了dest,这种情况下源字符串的长度小于num
        {
          //如果源字字符串的长度小于num,则只复制到终止空字符的内容。(与库函数的实现方式保持一致)
          return ret; //直接返回
        }
        dest++;
        src++;
      }
      *dest = '\0';  //如果循环正常结束,则在dest的末尾补上结束字符
      return ret;
    }
    int main()
    {
      char arr1[20] = "abcdef";
      char arr2[] = "ABCDEF";
      my_strncat(arr1, arr2, 5);
      printf("%s\n", arr1);
      return 0;
    }

    2020062310470442.png

    20200623104134875.png

    注意事项

    • 将源字符串中num个字节的内容追加到目标字符串的末尾,并在最后添加’\0’。
    • 如果源中字符串的长度小于num,则只复制到终止空字符的内容

    strncmp

    函数功能

    字符串比较,比较两个字符串中前num个字节的大小。

    函数参数

    int strncmp ( const char * str1, const char * str2, size_t num );
    # int 函数返回值
    # char* str1  char* str2 用于比较的两个字符串
    # num 要比较的字节数

    函数返回值

    >0 : str1 大于 str2;
    =0 : str1 等于 str2;
    <0 : str1 小于 str2

    函数使用

    #include <stdio.h>
    #include <string.h>  //strncmp对应的头文件
    int main()
    {
      char arr1[] = "abcdef";
      char arr2[] = "abcq";
      int len = strncmp(arr2, arr1, 3);
      printf("%d\n", len);
      return 0;
    }

    2020062310470442.png

    注意事项

      • 对前num对字节中的每一对字符进行比较,直到遇到不相等的字符。
      • 比较的是每一对字符的ASCII值。








      相关文章
      |
      10天前
      |
      C语言
      【C语言】:动态内存管理函数malloc,calloc,realloc和free的介绍的介绍
      【C语言】:动态内存管理函数malloc,calloc,realloc和free的介绍的介绍
      19 0
      |
      10天前
      |
      C语言
      【C语言】:4大内存函数
      【C语言】:4大内存函数
      13 2
      |
      6天前
      |
      Java 程序员 Linux
      探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
      探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
      13 0
      |
      6天前
      |
      程序员 C语言
      C语言内存管理:malloc、calloc、realloc与free函数详解
      C语言内存管理:malloc、calloc、realloc与free函数详解
      8 0
      |
      18天前
      |
      消息中间件 存储 Kafka
      实时计算 Flink版产品使用问题之 从Kafka读取数据,并与两个仅在任务启动时读取一次的维度表进行内连接(inner join)时,如果没有匹配到的数据会被直接丢弃还是会被存储在内存中
      实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
      |
      10天前
      |
      存储 Java C++
      Java虚拟机(JVM)管理内存划分为多个区域:程序计数器记录线程执行位置;虚拟机栈存储线程私有数据
      Java虚拟机(JVM)管理内存划分为多个区域:程序计数器记录线程执行位置;虚拟机栈存储线程私有数据,如局部变量和操作数;本地方法栈支持native方法;堆存放所有线程的对象实例,由垃圾回收管理;方法区(在Java 8后变为元空间)存储类信息和常量;运行时常量池是方法区一部分,保存符号引用和常量;直接内存非JVM规范定义,手动管理,通过Buffer类使用。Java 8后,永久代被元空间取代,G1成为默认GC。
      22 2
      |
      14天前
      |
      存储
      数据在内存中的存储(2)
      数据在内存中的存储(2)
      25 5
      |
      14天前
      |
      存储 小程序 编译器
      数据在内存中的存储(1)
      数据在内存中的存储(1)
      28 5
      |
      14天前
      |
      存储 安全 Java
      SpringSecurity6从入门到实战之初始用户如何存储到内存
      Spring Security 在 SpringBoot 应用中默认使用 `UserDetailsServiceAutoConfiguration` 类将用户信息存储到内存中。当classpath有`AuthenticationManager`、存在`ObjectPostProcessor`实例且无特定安全bean时,此配置生效。`inMemoryUserDetailsManager()`方法创建内存用户,通过`UserDetails`对象填充`InMemoryUserDetailsManager`的内部map。若要持久化到数据库,需自定义`UserDetailsService`接口实
      |
      13天前
      |
      存储 编译器 C语言
      数据在内存中的存储
      数据在内存中的存储
      17 2