C语言进阶学习日志:字符串和内存函数(一)(上)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: C语言进阶学习日志:字符串和内存函数(一)

strlen函数

strlen函数 用于求字符串的的长度不包括'\0' 注意strlen函数指向的字符串必须有'\0'结尾

image.png

这个是MSDN的讲解  头文件是<string.h>


模拟strlen函数

模拟strlen函数有三种方法是 计数法 递归法 指针运算法

计数法:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* arr)//因为我们只是去计算一个字符串中的字符个数 并不会通过它的地址改变
{                                来改变它的内容 所以我们这里用 const 表示由arr指针指向的内容
  assert(arr != NULL);        不可改变 当然只是不能由arr来改变
  int count = 0;
  while (*arr!='\0')
  {
    arr++;
    count++;
  }
  return count;
}
int main()
{
  char arr[] = "adsdffafs";
  printf("%d", my_strlen(arr));
  return 0;
}

这里面的assert起的是一个断言的作用 因为我们也不清楚 传进来的地址是否是空地址 所以在学习了指针这一块后 对于传址操作 我们应该更加的敏感 以防出现出现错位 而断言就可以做到这一点 就相当于是一个长官对他手下的命令一样 是不能违背的

他的头文件是 <assert.h>


递归法:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* arr)
{
    assert(arr);
  if (*arr == '\0')
  {
    return 0;
  }
  else
  {
    return 1 + my_strlen(arr + 1);
  }
}
int main()
{
  char arr[] = "adsdffafs";
  printf("%d",my_strlen(arr));
  return 0;
}

递归法的原理就是 我们将arr字符串向后递归直到遇到'\0'返回 0 如果不是则加一向后递归下一个字符并加1 最后,递归一次就会加1 从而返回 字符串的长度


指针运算法:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* arr)
{
  assert(arr != NULL);
  const char* sert = arr;
  while (*arr != '\0')
  {
    arr++;
  }
  return arr - sert;
}
int main()
{
  char arr[] = "adsdffafs";
  printf("%d", my_strlen(arr));
}

要使用这种方法我们要知道指针的运算是怎样的


d80613e52e6541f1921d1ea85507c008.png

指针运算中的减法减出来的 就是这个之前到被减指针中间的元素个数 了解这个特性后 就已经有思路了吧

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* arr)
{
  assert(arr != NULL);
  const char* sert = arr;
  while (*arr != '\0')
  {
    arr++;
  }
  return arr - sert;
}
int main()
{
  char arr[] = "adsdffafs";
  printf("%d", my_strlen(arr));
}

这样我们模拟strlen函数的三种方法就说完了


最后有个这样的问题

 #include <stdio.h>
 int main()
 {
     if( strlen("abc") - strlen("abcdef") > 0)
     {
         printf(">0"); 
     }
     else
     {
         printf("<=0");
     }
 }

大家觉得这个代码最后打印出来的是什么内 注意strlen函数的返回值是一个无符号数哦

如果给他们强制类型转换成 int 会是什么结果内


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

  1. strcpy
  2. strcat
  3. strcmp


strcpy函数:

在使用 函数之前要注意这几点

① 源字符串必须以'\0'结尾

② 目标空间必须可变 且足够大来储存拷贝过来的字符串

③ 会将源字符串的'\0'拷进去

de054b5ad8544b7fa68b87cc37a2921c.png

#include <stdio.h>
int main()
{
   char arr[]={1,2,3,4,5,6};//这样的源字符串就是不可取的
   char ret[]="1234567";
   char tmp[]="xxx";
   strcpy(tmp,ret);//像这样也是不可以的 因为目标空间不够
   char ch1[]="1234567";
   char ch2[]="xxx";
   printf("%s", strcpy(ch1,ch2));//链式访问
   //打印出来是xxx因为'\0'也被拷进去了
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* arr, const char* tmp)
{
  char* ret = arr;
  assert(arr && tmp);
  while (*arr++ = *tmp++)//每次赋值完后加加
  {
    ;
  }
  return ret;
}
int main()
{
  char arr1[30] = "asd";
  char arr2[] = "xxxxxx";
  printf("%s",my_strcpy(arr1, arr2));
}

strcat函数:

这个是一个字符串连接函数 就好像"hello" "world" 连接后"helloworld"

其实模拟实现的方法很简单就是找到目标字符串末尾的 ‘\0’ 找到后 重复上面strcpy的步骤

4889884c7b6e48af993aeeaba3d07ed7.png

① 源字符串也是要有 '\0' 的结尾 不然函数不知道从哪里开始追加

②目标空间必须可修改 且足够大来存储追加的字符串

#include <stdio.h>
#include <assert.h>
char* my_strcat(char* tmp, const char* ret)
{
  assert(tmp && ret);
  char* p = tmp;
  while (*tmp != '\0')  不能写成while(*tmp++) 因为在判断到'\0'的时候虽然会跳出循环 但在这之前
  {                     会++一次 跳过末尾的'\0'
    tmp++;
  }
  while (*tmp++ = *ret++)
  {
    ;
  }
  return p;
}
int main()
{
  char arr1[30] = "xxxxxx";
  char arr2[] = "abcd";
  printf("%s",my_strcat(arr1, arr2));
}


strcmp函数:

比较字符串中每个对应位置的字符的ASCLL码值

8199de6fdaaa42a19dc58088b1feaf01.png

要注意的是strcmp函数返回的值是 小于0 等于0 大于0 所以我们在模拟的时候 要注意返回的值不一定就是1,0,-1

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* tmp, const char* ret)
{
  assert(tmp && ret);
  while (*tmp == *ret)
  {
    if (*tmp == '\0')
    {
      return 0;
    }
    tmp++;
    ret++;
  }
  return *tmp - *ret;
}
int main()
{
  char arr1[] = "abc";
  char arr2[] = "abc";
  printf("%d",my_strcmp(arr1, arr2));
}


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
luck++
+关注
目录
打赏
0
0
0
0
0
分享
相关文章
|
6月前
|
C语言 之 内存函数
C语言 之 内存函数
62 3
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
162 6
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
272 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
6月前
|
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
135 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
1164 1
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
105 0