字符串函数、字符函数、内存函数的使用及其模拟实现(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值。








      相关文章
      |
      1月前
      |
      C语言 C++
      C语言 之 内存函数
      C语言 之 内存函数
      34 3
      |
      29天前
      |
      程序员 C++ 容器
      在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
      在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
      |
      25天前
      |
      存储 C语言
      【c语言】字符串函数和内存函数
      本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
      21 0
      |
      4月前
      |
      存储 分布式计算 Hadoop
      HadoopCPU、内存、存储限制
      【7月更文挑战第13天】
      283 14
      |
      3月前
      |
      存储 编译器 C语言
      【C语言篇】数据在内存中的存储(超详细)
      浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
      376 0
      |
      24天前
      |
      存储 C语言
      数据在内存中的存储方式
      本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
      50 1
      |
      28天前
      |
      存储
      共用体在内存中如何存储数据
      共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。
      |
      1月前
      |
      存储 弹性计算 算法
      前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
      本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
      |
      1月前
      |
      存储 编译器
      数据在内存中的存储
      数据在内存中的存储
      41 4
      |
      1月前
      |
      存储 Java
      JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
      这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
      53 0
      JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配