字符和字符串的库函数模拟与实现

前言:

相信大家平常在写代码的时候,用代码解决实际问题时苦于某种功能的实现,而望而止步,这个时候库函数的好处就体现出来了,当然个人代码编写能力强的可以自己创建一个函数,不过相当于库函数来说却是浪费了一点时间,库函数的准确性和有效性对我们的好处就显而易见了。本次重点是着重介绍字符函数字符串函数的模拟和实现

本章重点知识点:

(1)求字符串长度

      strlen

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

  strcpy
          strcat
          strcmp

(3)长度受限制的字符串函数介

    strncpy
          strncat
          strncmp
(4) 字符串查找
          strstr
          strtok
(5) 错误信息报告
  strerror
(6) 字符操作
(7)内存操作函数
          memcpy
          memmove
          memcmp
          memset

1、函数的介绍

1.1 strlen函数

 size_t strlen (const char *str);

头文件名:#include<string.h>

size_t 是表示无符号整数的意思,也就相当于unsigned int 。

实际用法:

#include<stdio.h>
int main()
{
    char arr1[] = "abcdef";
    int net = strlen(arr1);

    printf("%d", net) ;
    return 0;
}

 众所周知字符串以'\0'为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包 含 '\0' )。

1.2  strcpy函数

 char *strcpy (char *destination,  const  char  *source)

头文件名:#include<string.h>

const函数用来限制 *source,也就是指针*source 不能随意改变数据。

比如:

int main()
{
    int b = 10;
    int* p = &b;
    *p = 6;
    return 0;
}

此时*p在没有const函数修饰的情况下*p可以随意更改所指的数据大小 。

int main()
{
    int b = 10;
    const int* p = &b;
    *p = 6;
    return 0;
}

而现在*p有了const函数修饰,现在运行程序就会报错。

所以该函数的用法就知道了,用指针*source所指向地址的数据复制到指针*destination中。

下面来看strcpy函数实际用法:

#include<stdio.h>
#include<string.h>
int main()
{
    char  arr1[20] = { 0 };
    char  arr2[20] = "abcdefgh";
    strcpy(arr1, arr2);
    printf("%s", arr1);
    return 0;
}

为了arr2中能够完全的存放下arr1中的数据,所以arr2的空间与arr1一致,当然在arr2创建的空间足够大的前提下 arr[20]也可以变成这样写arr[],这样也是符合语法标准。

1.3 strcat函数

char *strcat (char *destination,  const  char *source)

头文件名:#include<string.h>

const函数的用法在介绍strcpy函数时就已经讲到了对于还不太清楚的伙伴可以往上翻一下,了解明白,在此后就不做过多解释了。

此次strcat函数里的参数和strcpy函数里的参数的内容大致相同,不过用法确实大不相同。

从第一个图中几个关键词:来源,目的,串联等,应该不难想到,该函数应该是把后面字符串的内容连接到第一个 字符串后面。

实际应用:

#include<stdio.h>
#include<string.h>
int main()
{
    char arr1[20000] = "abcdef";
    char arr2[20] = "yangyang";
    strcat(arr1, arr2);
    printf("%s", arr1);
    return 0;
}

 运行后该函数的用法和我们所猜的差不多。在程序中,因为是把第二个字符串连接到第一个 字符串中,所以第一个字符串数组的空间必须大,所以我才给了arr1这么大的空间,当然在保证了第一个字符串数组足够大的情况下,arr2[20]也可以写成arr2[]。

1.4 strcmp函数

int  strcmp(const char  *str1,  const  char  *str2)

头文件名:#include<string.h>

此函数较前几个函数还是有很大不同,光两个参数就不能随意改变,而且返回值有很大区别,上面函数的函数返回值大多都是void型,而此函数的返回值是int型。根据图中的意思,该函数是一个比较两个字符串大小的函数。如果两个字符串相等就返回0,如果是第一个字符串大于第二个字符串就返回大于0的整数,反之就会返回小于0的数。在比较时前提是所比较的字符必须表示同一个大小,不然即使多,但实际比出来也是小。

实际应用:

#include<stdio.h>
int main()
{
    char  arr1[] = "abcdefgh";
    char  arr2[] = "abcdefghgdhs";

    char  abb1[] = "abcdef";
    char  abb2[] = "abc";

    char  acc1[] = "abcdef";
    char  acc2[] = "abcdef";

    int num1 = strcmp(arr1, arr2);
    int num2 = strcmp(abb1, abb2);
    int num3 = strcmp(acc1, acc2);

    printf("num1 = %d\nnum2 = %d\nnum3 = %d\n", num1, num2, num3);
    return 0;
}

 相信有了这个strcmp函数,大家在平常计算字符串长度会更加方便。

1.5 strncpy函数

 char *strncpy(char  *destinnation,  const  char  *source, size_t  num)

头文件名:#include<string.h>

size_t是无符号整型,而根据图中的解释这个函数仅仅比strcpy函数多了第二个字符串可以指定多少字节的字符来复制在第一个字符串中的功能。

实际应用1:

#include<stdio.h>
#include<string.h>
int main()
{
    char  arr1[2000] = { 0 };
    char arr2[] = "abcdef";

    strncpy(arr1, arr2, 5);

    printf("%s\n", arr1);
    return 0;
}

 此函数比strcpy用的范围更大,更适应如今变化多端的局面。

1.6 strncat函数

 char  *strncat  (char  *destination,  const  char  *source,  size_t  num)

 头文件名:#include<string.h>

此函数也比strcat函数多了第二个字符串可以指定多少字符连接在第一个字符串的后面的功能其它大体都是相同。

实际应用:

#include<stdio.h>
#include<string.h>
int main()
{
    char  arr1[2000] = "abcd";
    char  arr2[] = "abcdefgh";

    strncat(arr1, arr2, 4);

    printf("%s\n", arr1);

    return 0;
}

 更方便大家的使用。


1.7 strncmp函数

int strncmp ( const char * str1, const char * str2, size_t num );

 头文件名:#include<string.h>

 此函数较strcmp函数也只是多了可以指定用多少字节的字符来比较的功能,其它的大体相同。比上面几个函数有点不同,此函数的后面的数字是作用于两个字符串,而不仅仅作用于第二个字符串了。

实际应用:

#include<stdio.h>
#include<string.h>
int main()
{
    char  arr1[] = "abcd";
    char  arr2[] = "abcdefgh";

    char  arr3[] = "abcdef";
    char  arr4[] = "abcd";

    int num1 = strncmp(arr1, arr2, 2);
    int num2 = strncmp(arr1, arr2, 6);
    int num3 = strncmp(arr1, arr2, 4);
    int num4 = strncmp(arr3, arr4, 6);

    printf("num1 = %d\nnum2 = %d\nnum3 = %d\n", num1, num2, num3);


    printf("%d\n", num4);


    return 0;
}

 多出的功能也只是为了方便使用,更灵活。

1.8 strstr函数

char * strstr ( const char *str1, const char * str2)

 头文件名:#include<string.h>

根据图中的意思,此函数大概就是寻找子函数,并打印子函数及其后面的内容,返回值也是char *指针。

实际应用:

#include<stdio.h>
#include<string.h>
int main()
{
    char arr1[20] = "abcdefgh";
    char arr2[20] = "de";

    char *str = strstr(arr1, arr2);

    printf("%s\n", str);
    return 0; 
}

1.9 strtok函数

 char * strtok ( char * str, const char * sep )

 头文件名:#include<string.h>

此函数的参数和strstr函数的参数大致相同表达的意思有些许的差别,由const函数可知该函数的第二个参数是不能变,而图中拆分字样,那第一个参数应该是等同于标识符,把第二个参数分成多组字符然后再打,分隔符的顺序是没有讲究的,随便放就可以。

sep参数是个字符串,定义了用作分隔符的字符集合

第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标 记。

strtok 函数找到 str 中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:
strtok 函数会改变被操作的字符串,所以在使用 strtok 函数切分的字符串一般都是临时拷贝的内容
并且可修改。)
strtok 函数的第一个参数不为 NULL ,函数将找到 str 中第一个标记, strtok 函数将保存它在字符串
中的位置。
strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
记。
如果字符串中不存在更多的标记,则返回 NULL 指针。

实际应用:

#include<stdio.h>
#include<string.h>
int main()
{
    char arr1[20] = "abc@def、jkm.klj";
    char arr2[10] = "@、.";
    char coop[20] = { 0 };
    strcpy(coop, arr1);
    char* str = NULL;
    for (str = strtok(coop, arr2); str != NULL; str = strtok(NULL, arr2))
    {
        printf("%s\n", str);
    }
    return 0;
}

 上面那段for循环那段函数可有有些人看不懂,它可以还可以替换成:

    str = strtok(coop, arr2);
    printf("%s\n", str);

    str = strtok(NULL, arr2);
    printf("%s\n", str);

    str = strtok(NULL, arr2);
    printf("%s\n", str);

    str = strtok(NULL, arr2);
    printf("%s\n", str);

两种写法是表达一样的意思。

1.10 strerror函数

 char  *strerror(int errnum )

 头文件名:#include<string.h>

根据图中的意思,这个函数大概就是:返回错误码,所对应的错误信息。

实际应用:

#include <stdio.h>
#include <string.h>
int main ()
{
 FILE * pFile;
 pFile = fopen ("unexist.ent","r");
 if (pFile == NULL)
   printf ("Error opening file unexist.ent: %s\n",strerror(errno));
   //errno: Last error number
 return 0;
}

1.11  memcpy函数

 void  *memcpy (void *destination ,  const  void * source,  size_t  num)

 头文件名:#include<string.h>

 虽然此函数也是复制函数但是较前面几个函数不同,这是内存函数。由它是void型就大致知道,大部分结构都能复制,比较灵活。也能指定多少数据复制,只不过第三个参数是以字节为单位

实际应用:

#include<stdio.h>
#include<string.h>
int main()
{
    int abb1[10] = { 1,2,3,4,5,6,7,8,9,10 };
    int abb2[20] = { 0 };

    char arr1[10] = "abcdefghi";
    char arr2[20] = { 0 };

    memcpy(abb2, abb1, 20);
    memcpy(arr2, arr1, 20);

    int i = 0;
    for (i = 0; i < 20; i++)
    {
        printf("%d ", abb2[i]);
    }
    printf("\n");

    printf("%s\n", arr2);
    return 0;
}

 从上图中可知当空间过剩时会用0来补上,而当是字符串传递时就不会,如下图:

1.12 memmove函数

 void  *memmove( void  *destination,  const  void *source,  size_t  num)

 头文件名:#include<string.h>

此函数和memcpy函数功能大体相同,memmove可以说成是memcpy的子集,memcpy只能复制两个来自不同空间,不能有所重叠。而memmove函数它可以复制同一个空间的值,可以重叠,它后面第三个参数也是以字节为单位。

实际应用:

#include<stdio.h>
#include<string.h>
int main()
{
    int abb[10] = { 1,2,3,4,5,6,7,8,9,10 };
    memmove(abb + 4, abb, 24);
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        printf("%d ", abb[i]);
    }
    return 0;
}

1.13 memcmp函数

 int  memcmp(  const void *ptr1,  const   void *ptr2,   size_t   num)

头文件名: #include<string.h>
由图中所介绍的意思可知,该函数与strncmp函数有异曲同工之妙,只是该函数可比较的范围更大,并不仅仅只是比较字符串,同样它也是一个内存函数。
实际应用:

#include<stdio.h>
#include<string.h>
int main()
{
    char  arr1[20] = "abcdefgh";
    char  arr2[20] = "abcdef";
    //因为该指定的字节是作用于两个参数,故只能比较相等时或者另一个大于另一个,而不能比较小的时候的大小
    int num1 = memcmp(arr1, arr2, 20);
    int num2 = memcmp(arr1, arr2, 2);

    printf("num1 = %d\n", num1);
    printf("num2 = %d\n", num2);

    return 0;
}

1.14 memset函数

 void  *memset(void  *ptr,  int value, size_t  num)

 头文件名:#include<string.h>

由图中表达的意思,这就是一个填充函数,也就是用第二个int型参数,再根据第三个参数所制定的字节数,从而把in型参数填充到第一个参数中。

实际应用:

#include<stdio.h>
#include<string.h>
int main()
{
    char  arr1[20] = "abcdefgh";
    memset(arr1, '0', 8);
    printf("%s\n", arr1);
    return 0;
}

 库函数的讲解就讲解在此,希望大家能有所收获。

2、库函数的模拟实现

2.1  模拟实现strlen函数

第一种方法:使用了临时变量。利用临时变量来计数,最后返回临时变量的值即可。

int my_strlen(char* arr)
{
    int count = 0;
    while (*arr++ != '\0')
    {
        count++;
    }
    return count;
}

第二种方法:不使用临时变量(递归)。使用递归也是过程最简单的。

int my_strlen(char* arr)
{
    if (*arr == '\0')
        return 0;
    else return 1 + my_strlen(arr + 1);
}

第三种方法:使用两个指针。利用指针与指针之间的距离长度来算字符的大小。

int my_strlen(char* arr)
{
    char* p = arr;
    while (*p != '\0')
        p++;
    return p - arr;

}

2.2 模拟实现strcpy

第一种写法:是利用字符串以‘\0’为结束标志的特性,来依次把值存过去。

void my_strcpy(char* arr, char* aee)
{
    while (*aee != '\0')
    {
        *arr = *aee;
        arr++;
        aee++;
    }
}

另一种写法:这种写法相较于传统的写法有很大不同,是直接构造char*的函数,首先利用一个指针来记录目的指针的初始位置,在利用另一个带有目的数据的指针来传入目的指针里,最后再传回用来记录目的指针的初始位置指针。

char * my_strcpy(char* arr, char* aee)
{
    char* net = arr;
    while (*arr++ = *aee++)
    {
        ;
    }
    return net;
}

2.3模拟实现strcat函数

该方法是利用了指针与字符串的特性。

void my_strcat(char* arr1, char* arr2)
{
    while (*arr1)
    arr1++    ;

    while (*arr2 != '\0')
    {
        *arr1 = *arr2;
        arr1++;
        arr2++;
    }
}

2.4 模拟实现strcmp函数

int my_strcmp(char* arr1, char* arr2)
{
    while (*arr1 == *arr2)
    {
        if (*arr1 = '\0')
            return 0;
        arr1++;
        arr2++;
    }
    if (*arr1 > *arr2)
        return 1;
    else return -1;
}

2.5 模拟实现strstr函数 

首先利用s1、s2、cp三个指针进行辅助

char* my_strstr(char* str1, char* str2)
{
    char* cp = str1;
    char* s1 = cp;
    char* s2 = str2;
    while (*cp)
    {
        s1 = cp; 
        s2 = str2;
        while (*s1 && *s2 && *s1 == *s2)
        {
            s1++;
            s2++;
        }
        if (*s2 == '\0')
            return cp;
        cp++;
    }

}

首先用cp标记str1的初始位置,然后用s1标记cp的位置,利用循环找到s1和s2相同的地方,再判断是否s2中的数据在s1中能够找到。如果找到,s2就会为‘\0’,从而结束循环,返回cp即可。如果s2中的数据不能在s1中全部找到,那么cp就继续移动到下一位直到移动到'\0'结束程序。此过程可能有点繁琐,需要大家仔细、用心的去感悟和理解。

2.6 模拟实现memcpy函数

void my_memcpy(void* arr1,const void* arr2, int se)
{
    char* ret = arr1;
    while (se)
    {
        *(char*)arr1 = *(char*)arr2;
        arr1 = (char*)arr1 + 1;
        arr2 = (char*)arr2 + 1;
        se--;
    }
    return ret;

 

首先我们需要用一个指针来记录目标函数的起始位置。为什么要记录呢?也就是为了我们最后返回去,不然我们操作完目标函数的指针的位置不在起始位置。

关于为什么要这样写 :

 arr1 = (char*)arr1 + 1;
 arr2 = (char*)arr2 + 1;

而不是这样写:

arr1++;

arr2++;

这是因为当初创建my_memcpy函数时我们为了瞒住各种数据的需求,就用void型,而在void型中arr1++和arr2这样写就是错误的,系统不知道你是什么类型,它怎么知道加多少呢也就是会造成系统错误。

可能有的人会说不是在上一步已经进行了强制数据转换了吗,而我要说的是强制数据转换只是在那一个过程转换了,而在下一个过程它有又会失效,不信的话你们可以去试试,我就不作过多的解释。

2.7 模拟实现memmove函数

void *my_memmove( void* dest,const void* trst, int se)
{
    void* ret = dest;
    if (dest < trst)
    {
        while (se--)
        {
            *((char*)dest) = *(char*)trst;
            dest = (char*)dest + 1;
            trst = (char*)trst + 1;
            
        }
    }
    else
    {
        while (se--)
        {
            *((char*)dest + se) = *((char*)trst + se);
            
        }
    }
    return ret;
}

此函数模拟的难度应该就在于为什么要判断。这个总共分为两种情况,第一种情况是dest在trst前面时,只能从前面传入数据才能正确表达,也就是在执行函数时这样的表达:

my_memmove(arr1,  arr1+2,  8);

也就是此种情况。

而第二种情况就是dest在trst的后面时,只能从后面开始传入数据才能正确表达,也就是在执行函数时这样的表达:

my_memmove(arr1 + 2,  arr1,  8);

两种表达的意思在代码运行时是两种情况。

我们先来讲讲第一种情况:dest在trst的前面看能不能从后面开始传入数据:

按照常规就是把trst中的数据依次放在dest中也就是6放在dest中4的位置,然后trst中的5放在dest中3的位置,相信此时大家已经看出来了由于dest和trst都是指针,它们中数据的改变会影响目标函数,此时由于之前的移动原本trst中还没有传过去的3和4已经被5和6给代替了,所以如果继续传的话大概率是5和6一直交替。

而相反如果从前面开始传入就不会覆盖数据,大家可以试一试。

第二种情况也就是这样的一个过程,大家可以仔细想一想其中的逻辑关系或者在纸上画一下感受一下。

感谢语

字符和字符串的库函数模拟与实现,在这里也就讲完了,由于我自己的知识水平,可能在某些方面讲的不是那么通俗易懂,有些知识讲的不是很完整,大家多多包容包容,再次感谢大家的观看,谢谢!

我们一起加油 GO GO GO !

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/62618.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis进阶 - JVM进程缓存

原文首更地址&#xff0c;阅读效果更佳&#xff01; Redis进阶 - JVM进程缓存 | CoderMast编程桅杆https://www.codermast.com/database/redis/redis-advance-jvm-process-cache.html 传统缓存的问题 传统的缓存策略一般是请求到达 Tomcat 后&#xff0c;先查询 Redis &…

Java文件操作

目录 一、File类概述 1.1 使用案例 二、文件内容的读写 2.1 字符流 2.1.1 读取文件 2.1.2 写入文件 2.2 字节流 2.2.1 读取文件 2.2.2 写入文件 对于Java操作文件&#xff0c;具体详情可以参考Java api文档 中的Java.io.File类 一、File类概述 首先先了解一下File类中常见的属…

Unity 从2018升级为2021之后 IAP(内购插件)报错解决

从老项目升级为2021高版本之后报了个错 大概就是… the type iwindowsiap exists in both unityengine.purchasing.winrtcore, version0.0.0.0, 这种 具体的我也没粘贴全部过来 原因貌似是 PackManger里面的IPA包和项目自带的冲突了 解决方法&#xff1a; 删除项目文件夹下面…

leetcode3. 无重复字符的最长子串(滑动窗口 - java)

滑动窗口 无重复字符的最长子串滑动窗口 上期经典 无重复字符的最长子串 难度 - 中等 3. 无重复字符的最长子串 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc…

代码随想录算法训练营第五十二天 | 300.最长递增子序列,674. 最长连续递增序列,718. 最长重复子数组

代码随想录算法训练营第五十二天 | 300.最长递增子序列&#xff0c;674. 最长连续递增序列&#xff0c;718. 最长重复子数组 300.最长递增子序列674. 最长连续递增序列718. 最长重复子数组 300.最长递增子序列 题目链接 视频讲解 给你一个整数数组 nums &#xff0c;找到其中最…

JDK源码解析-LinkedList

1. LinkedList类 1.1 LinkedList类定义&数据结构 定义 LinkedList是一种可以在任何位置进行高效地插入和移除操作的有序序列&#xff0c;它是基于双向链表实现的。 数据结构 基础知识补充 单向链表&#xff1a; element&#xff1a;用来存放元素 next&#xff1a;用来…

SpringBoot项目(jar)部署,启动脚本

需求 SpringBoot项目&#xff08;jar&#xff09;部署&#xff0c;需要先关闭原来启动的项目&#xff0c;再启动新的项目。直接输入命令&#xff0c;费时费力&#xff0c;还容易出错。所以&#xff0c;使用脚本启动。 脚本 脚本名&#xff1a;start.sh 此脚本需要放置在jar包…

AI文本标注的概念,类型和方法

我们每天都在与不同的媒介&#xff08;例如文本、音频、图像和视频&#xff09;交互&#xff0c;我们的大脑对收集到的信息进行处理和加工&#xff0c;从而指导我们的行为。在我们日常接触到的信息中&#xff0c;文本是最常见的媒体类型之一&#xff0c;由我们交流使用的语言构…

——滑动窗口

滑动窗口 所谓滑动窗口&#xff0c;就是不断的调节子序列的起始位置和终止位置&#xff0c;从而得出我们要想的结果。也可以理解为一种双指针的做法。 leetcode76 class Solution {public String minWindow(String s, String t) {char[] schars s.toCharArray();char[] tc…

【Linux】root和子用户都能执行的命令,sudo无法执行(已解决)

全流程帖子 https://ask.oceanbase.com/t/topic/35604437/7 1.问题 如题&#xff0c;在编译miniob的时候遇到如下错误 [muvm-cnt8:~/code/miniob]$ sudo bash build.sh init build.sh init HEAD is now at 5df3037d Merge branch release-2.1.12-stable-pull into patches-2.…

【2D/3D RRT* 算法】使用快速探索随机树进行最佳路径规划(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

哪些情况需要用到云渲染?原来云渲染有这么多好处!

当前&#xff0c;CG行业发展迅猛&#xff0c;云渲染已成为越来越多的设计师必不可少的工具。在许多情况下&#xff0c;云渲染都能发挥重要的作用。 情况1&#xff1a;项目时间紧急 在当今繁忙的设计行业中&#xff0c;许多设计师需要通宵加班才能完成繁琐的工作。然而&#xf…

跨境做独立站,如何低成本引流?

大家都知道&#xff0c;海外的消费习惯与国内不同&#xff0c;独立站一向是海外消费者的最喜欢的购物方式之一&#xff0c;这也吸引了许多跨境商家开设独立站。 独立站不同于其他的第三方平台&#xff0c;其他平台可以靠平台自身流量来获得转化&#xff0c;而独立站本身没有流…

Git结合Gitee的企业开发模拟

本系列有两篇文章&#xff1a; 一是另外一篇《快速使用Git完整开发》&#xff0c;主要说明了关于Git工具的基础使用&#xff0c;包含三板斧&#xff08;git add、git commit、git push&#xff09;、Git基本配置、版本回退、分支管理、公钥与私钥、远端仓库和远端分支、忽略文…

桌面端后台项目笔记

套用模板 vue-pure-admin 所用主要框架笔记 1. electron app const { app } require(electron) app.on(事件名, () > {} // 回调函数)常用事件 will-finish-launching 当应用程序完成基础的启动的时候触发ready&#xff1a;electron完成初始化时触发window-all-close…

什么是 TF-IDF 算法?

简单来说&#xff0c;向量空间模型就是希望把查询关键字和文档都表达成向量&#xff0c;然后利用向量之间的运算来进一步表达向量间的关系。比如&#xff0c;一个比较常用的运算就是计算查询关键字所对应的向量和文档所对应的向量之间的 “相关度”。 简单解释TF-IDF TF &…

蒲公英路由器如何设置远程打印?

现如今&#xff0c;打印机已经是企业日常办公中必不可少的设备&#xff0c;无论何时何地&#xff0c;总有需要用到打印的地方&#xff0c;包括资料文件、统计报表等等。 但若人在外地或分公司&#xff0c;有文件急需通过总部的打印机进行打印时&#xff0c;由于不在同一物理网络…

ceph对象三元素data、xattr、omap

这里有一个ceph的原则&#xff0c;就是所有存储的不管是块设备、对象存储、文件存储最后都转化成了底层的对象object&#xff0c;这个object包含3个元素data&#xff0c;xattr&#xff0c;omap。data是保存对象的数据&#xff0c;xattr是保存对象的扩展属性&#xff0c;每个对象…

cortex-A7核LED灯实验--STM32MP157

实验目的&#xff1a;实现LED1 / LED2 / LED3三盏灯工作 一&#xff0c;分析电路图 1&#xff0c;思路 分析电路图可知&#xff1a; 网络编号 引脚编号 LED1 PE10 LED2 > PF10 LED3 > PE8 2&#xff0c;工作原理&#xff1a; 写1&#xff1a;LED灯亮&#xf…

Spring Cloud Alibaba-Sentinel规则

1 流控规则 流量控制&#xff0c;其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标&#xff0c;当达到指定的阈值时 对流量进行控制&#xff0c;以避免被瞬时的流量高峰冲垮&#xff0c;从而保障应用的高可用性。 第1步: 点击簇点链路&#xff0c;我们就可以看到访…