【C语言】—— 字符串&内存函数(详解)(2)

简介: 【C语言】—— 字符串&内存函数(详解)(2)

四、内存操作函数

1.memcpy函数

函数原型:void *memcpy( void *dest, const void *src, size_t count );


头  文  件:<memory.h>or<string.h>


函数功能:内存拷贝:(适用于内存不重叠的场景)


功能:


       1.函数memcpy从src的位置开始向后复制count个字节的数据到dest的内存位置;


       2.这个函数在遇到 \0 的时候并不会停下来;


       3.如果source和destination有任何重叠,复制的结果都是未定义的;

举例:

#include <stdio.h>
#include <string.h>
int main()
{
  int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
  memcpy(arr1, arr1 + 4, 16);
  //arr1+2是指向5的,从这个位置向后16个字节的数据存到arr1向后16个字节
  //也就是把5 6 7 8 拷贝到1 2 3 4 上去
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr1[i]);
  }
  printf("\n");
  return 0;
}

1ecd1b2606ed46e9956a89f231c9802c.png

 

2.memmove 函数

函数原型:void *memmove( void *dest, const void *src, size_t count );


头  文  件:<string.h>


函数功能:内存拷贝:(适用于内存重叠或不重叠的场景)


注意事项:


       1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。

       2.如果源空间和目标空间出现重叠,就得使用memmove函数处理

举例:

#include <stdio.h>
#include <string.h>
int main()
{
  int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
  memmove(arr1, arr1 + 2, 16);
  //arr1+2是指向3的,从这个位置向后16个字节的数据存到arr1向后16个字节
  //也就是把3 4 5 6 拷贝到1 2 3 4 上去(这里就是内存重叠了,重叠的位置是3 4)
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr1[i]);
  }
  printf("\n");
  return 0;
}

1ecd1b2606ed46e9956a89f231c9802c.png

3.memcmp函数

函数原型:int memcmp( const void *buf1, const void *buf2, size_t count );


头  文  件:<memory.h>or<string.h>


函数功能:内存比较:(比较buf1和buf2指针开始的num个字节)


比较方法:


               1.当buf1<buf2时 返回<0


               2.当buf1=buf2时 返回=0


               3.当buf1>buf2时 返回>0

举例:

#include <stdio.h>
#include <string.h>
int main()
{
  int arr1[] = { 1,2,3,4,5 };
  int arr2[] = { 1,2,3,6,6 };
  int ret = memcmp(arr1, arr2, 12);
  //这里向后比较12个字节,就是比较1 2 3
  if (ret > 0)
  {
    printf("ret=%d arr1>arr2\n", ret);
  }
  else if (ret < 0)
  {
    printf("ret=%d arr1<arr2\n", ret);
  }
  else
  {
    printf("ret=%d arr1=arr2\n", ret);
  }
  return 0;
}

1ecd1b2606ed46e9956a89f231c9802c.png

4.memset函数

函数原型:void *memset( void *dest, int c, size_t count );

头  文  件:<memory.h>or<string.h>

函数功能:内存设置(memset函数将dest的第一个count个字节设置为字符c)

举例:

#include <stdio.h>
#include <string.h>
int main()
{
  char str[] = "almost every programmer should know memset!";
  memset(str, '-', 6);//从起始位置开始向后6个字节的内容改为 '-'
  puts(str);
  return 0;
}.

1ecd1b2606ed46e9956a89f231c9802c.png

五、库函数的模拟实现

1.模拟实现strlen函数

①递归实现

#include <stdio.h>
int my_strlen(const char* pa)
{
  if (*pa != '\0')
  {
    return 1 + my_strlen(pa + 1);//1+1+1+1+1+1+0
  }
  else
  {
    return 0;
  }
}
int main()
{
  char arr[] = "abcdef";
  int ret = my_strlen(arr);
  printf("arr的长度为:%d\n", ret);
  return 0;
}

②计数器实现

#include <stdio.h>
int my_strlen(const char* pa)
{
  int count = 0;
  for (int i = 0; pa[i] != '\0'; i++)
  {
    count++;//只要不等于 \0 就加一
  }
  return count;
}
int main()
{
  char arr[] = "abcdef";
  int ret = my_strlen(arr);
  printf("arr的长度为:%d\n", ret);
  return 0;
}

③指针 - 指针

#include <stdio.h>
int my_strlen(const char* pa)
{
  char* pa1 = pa;//先保存首元素的地址
  while (*pa1)
  {
    pa1++;//去找 \0 的地址
  }
  return pa1 - pa;//pa1是 \0 的地址,pa是首元素的地址;相减就得到元素个数
}
int main()
{
  char arr[] = "abcdef";
  int ret = my_strlen(arr);
  printf("arr的长度为:%d\n", ret);
  return 0;
}

2.模拟实现strcpy函数

#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
{
  assert(dest && src);//断言 --- 判断这两个指针是否为空
    char* ret = dest;
  while (*dest++ = *src++)//直接赋值,直到遇到'\0'就停下
  {
    ;
  }
    return ret;
}
int main()
{
  char arr1[20] = "xxxxxx";
  char arr2[] = "Hello";
  printf("拷贝前为:%s\n", arr1);
  char* ret = my_strcpy(arr1, arr2);
  printf("拷贝后为:%s\n", ret);
  return 0;
}
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
{
  assert(dest && src);//断言 --- 判断这两个指针是否为空
  int i = 0;
  for (i = 0; src[i] != '\0'; i++)
  {
    dest[i] = src[i];//赋值,但是没有'\0'结束标志
  }
  dest[i] = '\0';//末尾添加一个'\0'
}
int main()
{
  char arr1[20] = "xxxxxx";
  char arr2[] = "Hello";
  printf("拷贝前为:%s\n", arr1);
  my_strcpy(arr1, arr2);
  printf("拷贝后为:%s\n", arr1);
  return 0;
}

3.模拟实现strcat函数

#include <stdio.h>
#include <assert.h>
char* my_strcat(char* dest, const char* src)
{
  assert(dest && src);//断言 --- 判断这两个指针是否为空
  while (*dest)
  {
    //先找到dest所指向的数组中'\0'的位置
    dest++;
  }
  while (*src)
  {
    *dest++ = *src++;//进行追加
  }
}
int main()
{
  char arr1[20] = "Hello ";
  char arr2[] = "World";
  printf("追加前为:%s\n", arr1);
  my_strcat(arr1, arr2);
  printf("追加后为:%s\n", arr1);
  return 0;
}

4.模拟实现strcmp函数

#include <stdio.h>
#include <assert.h>
int my_strcmp(char* str1, const char* str2)
{
  assert(str1 && str2);//断言 --- 判断这两个指针是否为空
  while (*str1==*str2)
  {
    if (*str1 == '\0')
    {
      return 0;
    }
      str1++;
      str2++;
  }
  return *str1 - *str2;
}
int main()
{
  char arr1[] = "ABCDEF";
  char arr2[] = "ABCDE";
  int ret = my_strcmp(arr1, arr2);
  if (ret > 0)
  {
    printf("ret = %d:arr1>arr2", ret);
  }
  else if (ret < 0)
  {
    printf("ret = %d:arr1<arr2", ret);
  }
  else
  {
    printf("ret = %d:arr1=arr2", ret);
  }
  return 0;
}

5.模拟实现strncpy函数

#include <stdio.h>
#include <assert.h>
char* my_strncpy(char *dest, const char *src,size_t count)
{
  assert(dest && src);
  char *ret = dest;
  //1.拷贝字符串的个数
  while (count && (*dest++ = *src++))
  {
    count--;
  }
  //2.不够的用\0补
  if (count)
  {
    while (--count)
    {
      *dest++ = '\0';
    }
  }
  return ret;
}
int main()
{
  char arr1[20] = "xxxxxxxx";
  char arr2[] = "Hello World";
  printf("拷贝前为:%s\n", arr1);
  char* ret = my_strncpy(arr1, arr2, 5);
  printf("拷贝后为:%s\n", ret);
  return 0;
}

6.模拟实现strncat函数

#include <stdio.h>
#include <assert.h>
char* my_strncat(char *dest, const char *src, int count)
{
  assert(dest && src);
  char *ret = dest;
  //1.先找到\0的位置
  while (*dest++)
  {
    ;
  }
  dest--;
  //2.将源字符串追加进去(根据指定的个数)
  while (count--)
  {
    //3.只要不是\0就一直追加,追加到\0为止
    if (!(*dest++ = *src++))
    {
      return ret;
    }
  }
  *dest = '\0';
  return ret;
}
int main()
{
  char arr1[20] = "Hello ";
  char arr2[] = "World";
  printf("追加前的字符串为:%s\n", arr1);
  char *ret = my_strncat(arr1, arr2, 8);
  printf("追加后的字符串为:%s\n", ret);
  return 0;
}

7.模拟实现strncmp函数

#include <stdio.h>
#include <assert.h>
int my_strncmp(char *str1, const char *str2, int count)
{
  assert(str1 && str2);
  while(count&&(*str1 == *str2))
  {
    if (*str1 == '\0')
      return 0;
    str1++;
    str2++;
    count--;
  }
  return *str1 - *str2;
}
int main()
{
  char arr1[] = "Hello";
  char arr2[] = "Helld";
  int ret = my_strncmp(arr1, arr2, 5);
  if (ret > 0)
  {
    printf("ret = %d:arr1>arr2", ret);
  }
  else if (ret < 0)
  {
    printf("ret = %d:arr1<arr2", ret);
  }
  else
  {
    printf("ret = %d:arr1=arr2", ret);
  }
  return 0;
}

8.模拟实现strstr函数

#include <stdio.h>
#include <assert.h>
char* my_strstr(char* str1, const char* str2)
{
  assert(str1 && str2);
  char* s1;
  char* s2;
  char* cp = str1;
    //如果传过来的是 \0
  if (*str2 == '\0')
  {
    return str1;
  }
    //两种情况:
    //        arr1-- abcdef   arr1-- abbbcdef
    //  查找  arr2-- bcd      arr2-- bbc
  while (*cp)
  {
    s1 = cp;
    s2 = str2;
    while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
    {
      s1++;
      s2++;
    }
    if (*s2 == '\0')
    {
      return cp;
    }
    cp++;
  }
  return NULL;//没有找到的情况
}
int main()
{
  char arr1[] = "abbbcdef";
  char arr2[] = "bcd";
  char* ret = my_strstr(arr1, arr2);
  if (ret == NULL)
  {
    printf("找不到\n");
  }
  else
  {
    printf("找到了,是:%s\n", ret);
  }
  return 0;
}

9.模拟实现memcpy函数

#include <stdio.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
  assert(dest && src);
  void* ret = dest;
  while (num--)
  {
    *(char*)dest = *(char*)src;//强制转换为char*,是为了让其一次访问一个字节的内容
    dest = (char*)dest + 1;
    src = (char*)src + 1;
  }
  return ret;
}
int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
  my_memcpy(arr, arr + 4, 4 * sizeof(int));
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

10.模拟实现memmove函数

#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest, const void* src, size_t count)
{
  assert(dest && src);
  void* ret = dest;
  if (dest < src)
  {
    //从前向后拷贝
    while (count--)
    {
             //强制转换为char*,是为了让其一次访问一个字节的内容
      *(char*)dest = *(char*)src;
      dest = (char*)dest + 1;
      src = (char*)src + 1;
    }
  }
  else
  {
    //从后向前拷贝
    while (count--)
    {
      *((char*)dest + count) = *((char*)src + count);
    }
  }
  return ret;
}
int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
  my_memmove(arr, arr + 2, 4 * sizeof(int));
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

11.模拟实现memcmp函数

#include <stdio.h>
#include <assert.h>
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
  assert(ptr1 && ptr2);
    //void* --- 无具体类型指针
    //1.可以接受任意类型的指针
    //2.但不能进行运算
    //这里进行强制转换后就能够执行了
  while (num&&(*(char*)ptr1== *(char*)ptr2))
  {
    if (*(char*)ptr1 == '\0')
    {
      return 0;
    }
    ptr1 = (char*)ptr1+1;
    ptr2 = (char*)ptr2+1;
    num--;
  }
  return *(char*)ptr1 - *(char*)ptr2;
}
int main()
{
  char buf1[] = "ABCDEF";
  char buf2[] = "ABCDGS";
  int ret = my_memcmp(buf1, buf2, 4 * sizeof(char));
  if (ret > 0)
  {
    printf("buf1>buf2\n");
  }
  else if (ret < 0)
  {
    printf("buf1\<buf2\n");
  }
  else
  {
    printf("buf1=buf2\n");
  }
  return 0;
}

12.模拟实现memset函数

#include <stdio.h>
#include <assert.h>
void* my_memset(void* ptr, int val, size_t num)
{
  assert(ptr);
  for (int i = 0; i < num; i++)
  {
    *((char*)ptr + i) = val;
  }
    return ptr;
}
int main()
{
  char str[] = "almost every programmer should know memset!";
  char ch = '-';
  my_memset(str, ch, 6);
  puts(str);
  return 0;
}

六、总结

        以上的这些库函数大部分使用较多,深入了解并牢牢掌握其功能,对于这方面的解题会得心应手,笔者可能在模拟实现上不一定是最优解,但是可以帮助大家从了解到掌握。


目录
相关文章
|
4天前
|
存储 程序员 编译器
C语言:动态内存管理
C语言:动态内存管理
9 1
|
4天前
|
存储 编译器 程序员
C语言:数据在内存中的存储
C语言:数据在内存中的存储
10 2
|
4天前
|
存储 编译器 C语言
C语言:字符函数 & 字符串函数 & 内存函数
C语言:字符函数 & 字符串函数 & 内存函数
11 2
|
7天前
|
编译器
练习使用动态内存相关的4个函数:malloc、calloc、realloc、free
在了解使用动态内存相关的四个函数之前,我们先了解一下,为什么要有动态内存分配?
15 0
|
7天前
|
C语言
C语言中 字符串和数字的相互转换
C语言中 字符串和数字的相互转换
12 1
|
7天前
|
存储 编译器 C++
【C++】内存管理和模板基础(new、delete、类及函数模板)
【C++】内存管理和模板基础(new、delete、类及函数模板)
21 1
|
7天前
|
编译器 C语言 C++
详解内存操作函数
详解内存操作函数
|
13天前
|
缓存 安全 编译器
【C 言专栏】C 语言函数的高效编程技巧
【5月更文挑战第1天】本文探讨了C语言中函数的高效编程技巧,包括函数的定义与作用(如代码复用和提高可读性)、设计原则(单一职责和接口简洁)、参数传递方式(值传递、指针传递和引用传递)、返回值管理、调用约定、嵌套与递归调用,以及函数优化技巧和常见错误避免。掌握这些技巧能提升C语言代码的质量和效率。
【C 言专栏】C 语言函数的高效编程技巧
|
13天前
|
存储 C语言 开发者
【C言专栏】C 语言实现动态内存分配
【4月更文挑战第30天】C语言中的动态内存分配允许程序运行时按需分配内存,提供处理未知数据量的灵活性。这涉及`malloc()`, `calloc()`, `realloc()`, 和 `free()`四个标准库函数。`malloc()`分配指定大小的内存,`calloc()`同时初始化为零,`realloc()`调整内存大小,而`free()`释放内存。开发者需谨慎处理内存泄漏和指针使用,确保程序的稳定性和性能。动态内存分配是C语言中的重要技能,但也需要良好的内存管理实践。
|
13天前
|
存储 程序员 C语言
C语言进阶第九课 --------动态内存管理-2
C语言进阶第九课 --------动态内存管理