C语言—字符函数和字符串函数的模拟实现

简介: C语言—字符函数和字符串函数的模拟实现
  • 求字符串长度
  • strlen
  • 长度不受限制的字符串函数
  • strcpy
  • strcmp
  • strcat
  • 长度受限制的字符串函数
  • strnlen
  • strncmp
  • strncpy
  • strncat
  • 字符串查找
  • strstr
  • strtok
  • 错误信息报告
  • strerror
  • 内存操作函数
  • memcpy
  • memmove
  • memset
  • memcmp

  • 首先我们来看strlen
  • 字符串是以‘\0’为结束标志,strlen函数返回的是‘\0’出现的字符个数(但不包括‘\0’)
  • 我们还要注意一下就是strlen的返回值,它是无符号的(size_t)
size_t my_strlen(const char *str)
{
  assert(str);
  int count = 0;
  while (*str != '\0')
  {
    count++;
    str++;
  }
  return count;
}
int main()
{
  size_t ret = my_strlen("abcdef");
  printf("%d\n", ret);
  return 0;
}

  • 源字符串必须以‘\0’结束
  • 会将源字符串中的‘\0’拷贝到目标空间中
  • 目标空间必须足够大了,以确保能存放源字符串
char* my_strcpy(char *dest,const char *src)
{
  assert(src);
  assert(dest);
  char* ret = dest;
  while (*src != '\0')
  {
    *dest = *src;
    src++;
    dest++;
  }
  *dest = *src;
  return ret;
}
int main()
{
  char arr1[20] = "hello wolrd";
  char arr2[] = "xxxxxx";
  my_strcpy(arr1, arr2);
  printf("%s\n", arr1);
  return 0;
}

首先,我们来看返回值,你是否一开始和我有一样的疑问呢?? 为什么返回值是char*的??

我从《C语言和陷阱》中得到了答案,这是为了链式访问

strcpy传递的两个参数,第一个就是目标空间,第二个就是源字符串

思路:

我们要注意源字符串的‘\0’,我们是将源字符串一个一个拷贝到dest中,并且‘\0’也是要拷贝到'\0'的


  • 标准规定:
  • 第一个字符串大于第二个字符串,则返回大于0的数字
  • 第一个字符串等于第二个字符串,则返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字
int my_strcmp(const char *str1,const char *str2)
{
  assert(str1);
  assert(str2);
  while (*str1 == *str2)
  {
    if(*str1 == '\0')
    {
      return 0;
    }
    str1++;
    str2++;
  }
  //if (*str1 > *str2)
  //{
  //  return 1;
  //}
  //else
  //  return -1;
  return (*str1 - *str2);
}
int main()
{
  int ret = my_strcmp("ab", "abc");
  printf("%d\n", ret);
  return 0;
}

思路:

我们也是和之前一样的比较方法,结束标志都是看'\0‘,我们通过一个一个比较,最后c会和‘\0’比较,因为我们的c大于0,所以会返回一个小于0的数字,我们return (*str1 - *str2);  就是返回了一个大于或小于0的值,这样写就不用用if else来判断了,代码少了很多


  • strcat,就是在目标字符串的后面加上源字符串
char* my_strcat(char *dest,const char *src)
{
  assert(dest);
  assert(src);
  char* ret = dest;
  while (*dest!='\0')
  {
    dest++;
  }
  while (*dest++ = *src++)
  {
    ;
  }
  return ret;
}
int main()
{
  char arr1[20] = "hello ";
  char arr2[] = "world";
  my_strcat(arr1,arr2);
  printf("%s\n", arr1);
  return 0;
}

思路:

  • 因为我们是将arr2追加到arr1中,所以我们特别要关于arr2‘’\0'的位置,这样我们通过一个一个追加到arr1后面的位置,就可以实现了strcat的实现,最后我们为了链式访问,我们要一开始要保存一个dest一开始的地址


strncmp就是在传参后面加上了要比较的个数

int main()
{
  char arr1[] = "abcdefghijk";
  char arr2[] = "abcdef";
  int ret = strncmp(arr1, arr2, 7);
  printf("%d\n", ret);
  return 0;
}
  • 我们来看这个例子,因为我们在传参加上了要比较的个数,在这两个字符串中,前7个字符就是相同的,所以最后返回是的0
  • 所以,我们如果要用字符串的函数,
  • strnlen
  • strncmp
  • strncpy
  • strncat
  • 会安全很多,可以根据自己的需求来实现自己想达到的母的


int main()
{
  for (int i =0; i<10; i++)
  {
    printf("%d:%s\n", i, strerror(i));
  }
  return 0;
}


这个函数就是可以给我们看错误的信息报告的

  • 我们来看内存操作的函数,它接受的参数是void* ,这是因为它可能接受浮点型、整型、 字符型,类型是不确定的,所以我们用void* 来接受
void* my_memcpy(void *dest,const void *src,size_t num)
{
  assert(dest && src);
  void* ret = dest;
  while (num--)
  {
    *(char*)dest = *(char*)src;
    src = (char*)src + 1;
    dest = (char*)dest + 1;
  }
  return ret;
}
int main()
{
  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
  int arr2[10] = { 0 };
  my_memcpy(arr1, arr2, 20);
  for (int i=0; i<10; i++)
  {
    printf("%d ", arr1[i]);
  }
  return 0;
}

思路:我们注意,我们memcpy还要传递一个size_t的数,它表示的是字节

如代码所示,我们是将arr2中的0给arr1中,而且是20个字节,所以是把arr1中的前五个数改为0,这是因为一个int是4个字节  arr1中的1 就表示为01 00 00 00 ,2就是 02 00 00 00 ...  这样我们就是一个一个字节的拷贝到目标空间去


  • memmove接收参数的含义其实和memcpy差不多,这里就不再重复了
void* my_memmove(void *dest,const void *src,size_t num)
{
  assert(dest && src);
  void* ret = dest;
  if (dest < src)
  {
    while (num--)
    {
      *(char*)dest = *(char*)src;
      dest = (char*)dest + 1;
      src = (char*)src + 1;
    }
  }
  else
  {
    while (num--)
    {
      *((char*)dest + num) = *((char*)src + num);
    }
  }
  return ret;
}
int main()
{
  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
  int arr2[10] = { 0 };
  my_memmove(arr1, arr2, 20);
  for (int i =0; i<10; i++)
  {
    printf("%d ", arr1[i]);
  }
  return 0;
}

思路:


我们要分时从前->后拷贝还是从后->前拷贝,这是因为如果dest>src的时候,如果我们传递的是my_memmpve(arr1+2,arr1,20)   这是arr1的数据是1 2 1 2 1 2 1  8 9 10,原因就是当会形成覆盖  

所以,我们要分情况,因为数组是从低地址向高地址存贮的,所以当dest< src的时候,就是从前向后存储,这时我们要注意我们是一个一个字节存储的,而且我们是void* 所以我们要强转一下类型

            *(char*)dest = *(char*)src;
      dest = (char*)dest + 1;
      src = (char*)src + 1;
  • 这就是我们移动一次的时候,我们要移动num次,加上while循环就可以了。
  • 从后到前的移动是一样的思想
  • 最后:今天关于常见的字符串函数的模拟实现和内存的函数就到这里了,后续我也会大家多多分享一些常见的知识,多谢各位的支持了。
相关文章
|
3天前
|
Java C语言 C++
定义C语言的int main()函数
定义C语言的int main()函数
|
5天前
|
存储 移动开发 C语言
技术心得记录:嵌入式开发中常用到的C语言库函数
技术心得记录:嵌入式开发中常用到的C语言库函数
|
7天前
|
机器学习/深度学习 C语言
详细解读C语言math.h中常用函数
详细解读C语言math.h中常用函数
10 1
|
2天前
|
Java C语言 C++
定义C语言的int main()函数
定义C语言的int main()函数
|
5天前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
11 0
|
5天前
|
C语言
C语言实现猜数字游戏:代码详解与函数解析
C语言实现猜数字游戏:代码详解与函数解析
7 0
|
5天前
|
程序员 C语言
C语言内存管理:malloc、calloc、realloc与free函数详解
C语言内存管理:malloc、calloc、realloc与free函数详解
6 0
|
5天前
|
C语言
C语言中的函数指针、指针函数与函数回调
C语言中的函数指针、指针函数与函数回调
6 0
|
5天前
|
存储 C语言
C语言中的变量与函数详解
C语言中的变量与函数详解
4 0
|
6天前
|
存储 C语言
C语言中的printf函数详解
C语言中的printf函数详解
12 0