【linux】重定向+缓冲区

重定向+缓冲区

  • 1.重定向
    • 1.1重定向本质
    • 1.2重定向接口
    • 1.3重定向分类
      • 1.3.1>输出重定向
      • 1.3.2>>追加重定向
      • 1.3.3<输入重定向
  • 2.理解 >, >>, <
  • 3.如何理解linux下一切皆文件
  • 4.缓冲区
    • 4.1理解缓冲区问题
      • 4.1.1为什么要有缓冲区
      • 4.1.2缓冲区刷新策略的问题
      • 4.1.3缓冲区在哪里,指的是什么缓冲区
      • 4.1.4如何解释fork问题
  • 5.缓冲区该如何理解
    • 5.1myStdio.h
    • 5.2myStdio.c
      • 5.2.1_fopen
      • 5.2.2_fwrite
      • 5.2.3_fflush
      • 5.2.4_fclose
    • 5.3main.c
  • 6.缓冲区和OS的关系

自我名言只有努力,才能追逐梦想,只有努力,才不会欺骗自己。在这里插入图片描述
喜欢的点赞,收藏,关注一下把!在这里插入图片描述

1.重定向

  1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<stdlib.h>8 9 int main()10 {11    // close(0);12    // close(2);13     close(1);                                                                                                                                                    14     umask(0);                                                         15     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);             16     if(fd == -1)                                                      17     {                                                                 18         perror("open");                                               19         exit(1);                                                      20     }                                                                 21     printf("fd:%d\n",fd);                                             22                                                                       23     close(fd);                                                        24                                                                       25     return 0;                                                         26 }  

在这里插入图片描述

close(1),为什么没有打印新建文件fd呢?

printf(“%d\n”,fd); printf会把内容打印到stdout文件中。
但是close(1)关闭标准输出stdout—>显示器,int fd=open();新打开的文件fd是1。
stdout–>fd–>1,虽然我们手动关闭了stdout,但是系统并不知道,还以为fd为1的位置是stdout,但是这个位置现在已经被新打开的文件占用了,所以打印到了新打开的文件里。

  1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<stdlib.h>8 9 int main()10 {11    // close(0);12    // close(2);13     close(1);14     umask(0);15     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);16     if(fd == -1)17     {18         perror("open");19         exit(1);20     }21     printf("fd:%d\n",fd);22     23     //这里必须刷新一下,不然log.txt里面没有内容,这里和缓冲区有关,下面讲                                                                                                                  24     fflush(stdout);      25     close(fd);           26                          27     return 0;            28 } 

在这里插入图片描述

本来应该打印到显示器文件中,但是却写到文件里了。------>重定向

1.1重定向本质

在这里插入图片描述

1.2重定向接口

在这里插入图片描述
这个主要介绍dup2函数。

int dup2(int oldfd, int newfd);

在这里插入图片描述
那怎么使用dup2来实现刚才的效果,把打印到显示器内容,写入到"log.txt"
在这里插入图片描述
是上面那样写的,还是下面那样写的,我们分析分析。
在这里插入图片描述
画图分析
在这里插入图片描述
在这里插入图片描述
因此正确写法如下
在这里插入图片描述

  4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<stdlib.h>8 9 int main()10 {11    // close(0);12    // close(2);13    // close(1);14     umask(0);15     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);16     if(fd == -1)17     {18         perror("open");19         exit(1);20     }21     //重定向                                                                                                                                                     22     dup2(fd,1);                                                                                                               23     printf("fd:%d\n",fd);                                                                                                     24                                                                                                                               25     //这里必须刷新一下,不然log.txt里面没有内容                                                                               26     fflush(stdout);                                                                                                           27     close(fd);                                                                                                                28                                                                                                                               29     return 0;                                                                                                                 30 }  

在这里插入图片描述

1.3重定向分类

1.3.1>输出重定向

上面内容就是输出重定向,把新打开文件的fd重定向到fd为1(默认为显示器)的位置。

1.3.2>>追加重定向

    1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<stdlib.h>8 9 int main()10 {11    // close(0);12    // close(2);13    // close(1);14     umask(0);15    // int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);16     int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);17     if(fd == -1)18     {19         perror("open");20         exit(1);21     }22     //重定向23     dup2(fd,1);24     printf("你好\n");25     printf("吃了吗\n");                                                                                                                                           26                                                                                                                           27     //这里必须刷新一下,不然log.txt里面没有内容                                                                           28     fflush(stdout);                                                                                                       29     close(fd);                                                                                                            30                                                                                                                           31     return 0;                                                                                                             32 } 

在这里插入图片描述

1.3.3<输入重定向

#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>int main()    
{    // close(0);    // close(2);    // close(1);    umask(0);    // int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);    // int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);    int fd=open("log.txt",O_RDONLY);    if(fd == -1)    {      perror("open");      exit(1);      }      //输入重定向    dup2(fd,0);                                                                                                                                                      char outbuffer[64];        while(1)                   {                          printf("<");                                                     if(fgets(outbuffer,sizeof(outbuffer),stdin) == NULL) break;      printf("%s",outbuffer);                                                                                                                        }return 0;}   

在这里插入图片描述

2.理解 >, >>, <

在前面实现过一个自己的shell,现在我们给这个shell增加重定向功能来理解重定向。
在这里插入图片描述

//增加一个分割指令和文件名的函数                                                                                                                               
commandstrtok(lineCommand);

分割的时候,我们需要知道重定向是什么类型,文件是什么名字,因此增加两个全局变量来记录。

  //重定向类型    //第一个为初始重定向     #define DEFAULT_REDIR 0    #define INPUT_REDIR 1  #define OUTPUT_REDIR 2    #define ERROR_EDIRR 3    //重定向类型+文件名    int redirType=DEFAULT_REDIR;    char* redirFile=NULL;    

分割函数

  //这里找文件名没有写成函数,而写个宏#define trimSpace(start) do{\while(isspace(*start)) ++start;\}while(0)void commandstrtok(char* cmd){assert(cmd);char* start=cmd;char* end=cmd+strlen(cmd);while(start < end){if(*start == '<'){*start=0;++start;//这里可能 ls -a -l >      log.txt,trimSpace(start);redirType=INPUT_REDIR;redirFile=start;break;}else if(*start == '>')                                                                                                                                 {                                                                                                                                                      *start=0;                                                                                                                                          ++start;                                                                                                                                           if(*start == '>')                                                                                                                                  {                                                                                                                                                  redirType=APPEND_REDIR;                                                                                                                        ++start;                                                                                                                                       }                                                                                                                                                  else                                                                                                                                               {                                                                                                                                                  redirType=OUTPUT_REDIR;                                                                                                                        }                                                                                                                                                  trimSpace(start);                                                                                                                                  redirFile=start;                                                                                                                                       break;                                                                                                                                             }                                                                                                                                                      else{                                                                                                                                                      ++start;}}

因为命令是子进程执行的,真正重定向的功能一定是由子进程来完成的,
但是如何重定向是父进程要告知给子进程的。

//创建子进程
pid_t id = fork();
assert(id != -1);
if(id == 0)
{             switch(redirType){case INPUT_REDIR:{int fd=open("log.txt",O_RDONLY);if(fd <0){perror("open");return 1;}//重定向文件已经打开了dup2(fd,0);}break;case OUTPUT_REDIR:case APPEND_REDIR:{umask(0);int flags=O_WRONLY|O_CREAT;if(redirType == OUTPUT_REDIR) flags|=O_CREAT;else flags|=O_APPEND;                                                                                                                     int fd=open("log.txt",flags,0666);if(fd < 0){perror("open");return 1;}dup2(fd,1);     }break;default:printf("bug?\n");break;}//程序替换execvp(myargv[0],myargv);exit(1);
}

在这里插入图片描述

shell完整代码

问:子进程重定向会影响父进程吗?

不会
在这里插入图片描述

问:指向程序替换的时候,会不会影响曾经进程打开的重定向文件呢?

不会
在这里插入图片描述

3.如何理解linux下一切皆文件

Linux下一切皆文件,那键盘,显示器,磁盘,网卡等硬件在linux下都是文件吗?
可以这样说的。
在这里插入图片描述
在这里插入图片描述

站在struct file上层看来,所有的设备和文件,统一都是struct file--------->Linux下一切皆文件。

在这里插入图片描述

这里可能有这样一个问题,如果同一个文件被多个指针指向,但是某个进程把这个文件关了,会不会影响其他进程对这个文件的操作呢?

其实并不会,一个被打开的文件有引用计数
在这里插入图片描述
表明有几个指针指向这个文件,这样做是因为一个文件可能被多个指针指向。如果某个进程关闭文件,影响到其他进程,就不能保证进程的独立性。close关闭文件,其实并不是真正关闭文件,只是把引用计数减1,当只有一个指针指向这个文件,close关闭文件才是真正关闭这个文件。

4.缓冲区

先看一种现象。

  1 #include<stdio.h>  2 #include<string.h>                                                        3 #include<sys/types.h>  4 #include<sys/stat.h>  5 #include<fcntl.h>  6 #include<unistd.h>  7 #include<stdlib.h>  8   9 int main()  10 {  11     printf("hello printf\n");  12     fprintf(stdout,"%s\n","hello fprintf");  13   14   15     const char* output="hello write\n";  16     write(1,output,strlen(output));  17   18                                                                                                                                                                  19     return 0;  20 }     

在这里插入图片描述

  1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<stdlib.h>8 9 int main()10 {11     printf("hello printf\n");12     fprintf(stdout,"%s\n","hello fprintf");13 14 15     const char* output="hello write\n";16     write(1,output,strlen(output));17 18     fork();                                                                                                                                                      19     return 0;                                                                                                                           20 }    

在这里插入图片描述
对比两张图片,第二段代码补充fork(创建子进程),重定向之后,C接口的函数,被打印了两次,系统调用的接口前面都只是打印了一次。

这是什么原因?现在只是知道肯定是fork函数有关。
其实这里也和缓冲区有关。

4.1理解缓冲区问题

缓冲区本质就是一段内存!!!

4.1.1为什么要有缓冲区

这里讲一个小故事,帮助理解。

在四川的张三要给远在北京的李四送一个键盘。
在这里插入图片描述
张三为了节省时间,选择2;
现实中快递行业的意义?
节省发送者的时间。

进程把数据打包给磁盘,是一个很慢的过程,如果让进程一直等着显然不太好。因此我们也需要一个快速的方式----->缓冲区

在这里插入图片描述
缓冲区的意义是什么呢?

节省进程进行数据IO的时间。

但是我们在用文件写的接口时,并没有专门拷贝数据啊?(以fwrite为例)

其实与其理解fwrite是写入到文件的函数,倒不如理解fwrie是拷贝函数,将数据从进程拷贝到"缓冲区"或者“外设”中。

4.1.2缓冲区刷新策略的问题

把东西给顺丰之后,那顺丰什么时候发货呢?

张三第二天在想寄一个鼠标给李四,当走到快递站点发现自己昨天的快递还没有发走,就问快递人员,快递人员说,我们的快递都是用大货车和飞机发送的,就这一个快递不可能马上就发走,等到满足发送件货才发。

缓冲区的刷新策略:
在这里插入图片描述
不同外设IO访问速度是不同的。
缓冲区结合具体的设备,定制自己的刷新策略。(3策略,2特殊)

3策略
a.立即刷新 ----> 无缓冲
b.行刷新 ----> 行缓存 ----> 显示器 (显示器是给人看的,如果一次给很多信息,人看着不舒服)
c.缓冲区满 ----> 全缓存 ----> 磁盘文件(显示器除外)

2特例
1:用户强制刷新 (fflush)
2:进程退出 (进程退出要刷新缓冲区)

4.1.3缓冲区在哪里,指的是什么缓冲区

C接口打印了两次,系统调用接口打印了一次,这种现象一定和缓冲区有关。
虽然现在不知道缓冲区在哪里,但是我们知道缓冲区一定不在内核中
因为C接口底层调用的是系统调用接口,如果缓冲区在内核中,write也应该打印两次。

那缓冲区到底在哪?

我们之前谈论的所有缓冲区,都指的是用户级语言层面给我们提供的缓冲区
还记得C程序默认给我们打开stdin,stdout,stderr都是------->FILE*------>指向FILE结构体,结构体包含-------> fd,其实还包含一个缓冲区

因此,缓冲区在FILE结构体中。

所以当我们自己要强制刷新:fflush(文件指针),关闭:fclose(文件指针)传的都是FILE*。因为缓存区在FILE结构体中。

4.1.4如何解释fork问题

在这里插入图片描述
代码结束之前,创建子进程。

1.我们没有进行>输出重定向,看到了三条信息。

stdout默认使用的是行刷新,在fork之前,两条C函数已经将数据打印输出到到显示器上,你的FILE内部,进程内部不存在对应的数据了。这时创建子进程,等到子进程,父进程退出的时,都要刷新缓冲区,但是这时缓冲区已经没有内容可以刷新了。因此C函数打印两条信息。

2.>输入重定向之后,C接口打印两次

当我们进行>,写入文件就不再是显示器,而是普通文件,采用的刷新策略是全缓存,之前2条C打印函数,虽然带了\n,但是不足与将stdout缓冲区写满,数据并没有被刷新。
fork的时候,stdout属于父进程,创建子进程紧跟着就是进程退出,谁先退出,一定要进行缓冲区刷新(缓存区刷新---->就是修改)
这时就有了写时拷贝!! 因此C接口,数据最终会显示两份。

3.write为什么前后只打印一次

上面过程都是write无关,write没有FILE,而用的是fd,就没有C提供的缓冲区。

5.缓冲区该如何理解

自己写一个简易的缓冲区,来帮助理解"数据刷新策略"+“数据如何缓存”

5.1myStdio.h

  1 #pragma once  2 #include<errno.h> 3 #include<stdio.h>      4 #include<string.h>      5 #include<sys/types.h>      6 #include<sys/stat.h>      7 #include<fcntl.h>      8 #include<unistd.h>      9 #include<stdlib.h> 10   11 #define SIZE 1024    12 #define SYNC_NOW 1    13 #define SYNC_LINE 2      14 #define SYNC_FULL 3     15                      16 typedef struct _FILE{  17     int flags;//刷新方式  18     int fileno;  //文件描述符19     int capacity;//buffer容量  20     int size;//buffer当前使用量  21     char buffer[SIZE]; //缓冲区22 }_FILE;              23   24                      25 _FILE* _fopen(const char* path_name,const char* mode);  26 void _fwrite(const void* ptr,int num,_FILE* fp);                                                                                                                 27 void _fclose(_FILE* fp);  28 void _fflush(_FILE* fp);  

5.2myStdio.c

5.2.1_fopen

 _FILE* _fopen(const char* path_name,const char* mode)
{assert(path_name);int flags=0;int defaultmode=0666;if(strcmp(mode,"r") == 0){flags|=O_RDONLY;}else if(strcmp(mode,"w") == 0){flags|=(O_WRONLY|O_CREAT|O_TRUNC);}else if(strcmp(mode,"a") == 0){flags|=(O_WRONLY|O_CREAT|O_APPEND);}int fd=0;if(flags & O_RDONLY){fd=open(path_name,flags);}else{fd=open(path_name,flags,defaultmode);                                                                                                                        }if(fd < 0){const char*err=strerror(errno);write(2,err,strlen(err));return NULL;//这就是为什么创建文件失败,返回NULL}_FILE* fp=(_FILE*)malloc(sizeof(_FILE));assert(fp);fp->flags=SYNC_LINE;fp->fileno=fd;fp->capacity=SIZE;fp->size=0;memset(fp->buffer,0,SIZE);return fp;
}

5.2.2_fwrite

void _fwrite(const void* ptr,int num,_FILE* fp)                                                                                       
{                                                                                   //写到缓冲区里                                                                                                                  memcpy(fp->buffer+fp->size,ptr,num); //这里没有考虑缓冲区溢出问题                                                                                           fp->size+=num;                                                                                                                  //判断是否要刷新                                                                                                                if(fp->flags & SYNC_NOW)                                                                                                        {                                                                                                                               write(fp->fileno,fp->buffer,fp->size);                                                                                       fp->size=0;//清空缓冲区                                                                                                     }                                                                                                                               else if(fp->flags & SYNC_LINE)                                                                                                  {                                                                                                                               if(fp->buffer[fp->size-1] == '\n')  //这里也没有考虑abc\ndef这种形式,如果是这样的可以用for循环                                                                                        {                                                                                                                            write(fp->fileno,fp->buffer,fp->size);                                                                                       fp->size=0;                                                                                                             }                                                                                                                           }                                                                                                                               else if(fp->flags & SYNC_FULL)                                                                                                  {                                                                                                                               if(fp->size == fp->capacity)                                                                                                {                                                                                                                            write(fp->fileno,fp->buffer,fp->size);                                                                                       fp->size=0;                                                                                   }                                                                                                                           }                                                                                                                               
}     

5.2.3_fflush

void _fflush(_FILE* fp)                                                                                       
{                                                                                       if(fp->size > 0) write(fp->fileno,fp->buffer,fp->size);                                                                                       fsync(fp->fileno); //把数据强制从内核缓冲区刷新到磁盘                                                                                     fp->size=0;                                                                                                                                                      
} 

这里引入了内核缓冲区,下面解释。

5.2.4_fclose

void _fclose(_FILE* fp)                                                                                       
{                                                                                       _fflush(fp);  close(fp->fileno);                                                                                                                                               
}    

5.3main.c

行刷新

  1 #include"myStdio.h"2 3 4 int main()5 {6     _FILE* fp=_fopen("log.txt","w");7     if(fp == NULL)8     {9         perror("_fopen");10         return 1;11     }12 13     int cnt=10;14     const char* msg="hello linux\n";15     while(1)16     {17         _fwrite(msg,strlen(msg),fp);18         sleep(1);19         printf("count:%d\n",cnt--);20         if(cnt == 0) break;21     }                                                                       22     _fclose(fp);23 24     return 0;25 }

在这里插入图片描述

退出刷新

    1 #include"myStdio.h"2 3 4 int main()5 {6     _FILE* fp=_fopen("log.txt","w");7     if(fp == NULL)8     {9         perror("_fopen");10         return 1;11     }12 13     int cnt=10;14     const char* msg="hello linux";15     while(1)16     {17         _fwrite(msg,strlen(msg),fp);18         sleep(1);19         printf("count:%d\n",cnt--);                                       20         if(cnt == 0) break;21     }                    22     _fclose(fp);         23                          24     return 0;            25 }  

在这里插入图片描述
立即刷新

  1 #include"myStdio.h"2 3 4 int main()5 {6     _FILE* fp=_fopen("log.txt","w");7     if(fp == NULL)8     {9         perror("_fopen");10         return 1;11     }12 13     int cnt=10;14     const char* msg="hello linux";15     while(1)16     {17         _fwrite(msg,strlen(msg),fp);18         _fflush(fp);                                                        19         sleep(1);20         printf("count:%d\n",cnt--);21         if(cnt == 0) break;22     }          23     _fclose(fp);24                25     return 0;  26 }   

在这里插入图片描述

6.缓冲区和OS的关系

在这里插入图片描述
这里是由write函数,直接把数据写到磁盘上的文件中吗?
其实并不是这样的。
在这里插入图片描述
在这里插入图片描述
write并不是直接把缓冲区里的内容刷新到文件中,在打开文件对应的struct file{}结构体中其他有一个方法指针,还有一个指向内核缓冲区的指针,系统会把FILE结构体里面缓冲区内容通过struct file{}找到内核缓冲区,再由write()拷贝到内核缓冲区,然后再由这个内核缓冲区把内容刷新到文件中区,至于如何刷新和用户毫无关系,我们所知道的行刷新等,这是由语言层面所分类的,而内核缓冲区刷新由OS自主决定。

那么我们该如何证明有这个内核缓冲区呢?
超级大佬可以证明,这里证明不了,但是我们可以看到接口。
在这里插入图片描述
还有一个问题,如果OS突然宕机了会发生什么情况?
数据肯定会丢失。如果还是按照OS规定的内核缓冲区刷新策略肯定是不行的。
我们希望可以在用户层就告知OS,内核缓冲区不要再给我缓存了,赶紧把数据刷新到磁盘中。

这里介绍fsync函数

在这里插入图片描述
强制性把该文件对应的内核缓冲区数据持久到磁盘。就是OS不要给我缓存了,赶紧把数据给我更新到磁盘上。

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

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

相关文章

【yolov5】改进系列——特征图可视化

文章目录 前言一、特征图可视化二、可视化指定层三、合并通道可视化总结 前言 对于特征图可视化感兴趣可以参考我的另一篇记录&#xff1a;六行代码实现&#xff1a;特征图提取与特征图可视化&#xff0c;可以实现分类网络的特征图可视化 最近忙论文&#xff0c;想在yolov5上…

Java系列 | 如何讲自己的JAR包上传至阿里云maven私有仓库【云效制品仓库】

什么是云效 云效是云原生时代一站式 BizDevOps 平台&#xff0c;产研数字化同行者&#xff0c;支持公共云、专有云和混合云多种部署形态&#xff0c;通过云原生新技术和研发新模式&#xff0c;助力创新创业和数字化转型企业快速实现产研数字化&#xff0c;打造“双敏”组织&…

Python数据挖掘入门进阶与实用案例:自动售货机销售数据分析与应用

文章目录 写在前面01 案例背景02 分析目标03 分析过程04 数据预处理1. 清洗数据2.属性选择3.属性规约 05 销售数据可视化分析1.销售额和自动售货机数量的关系2.订单数量和自动售货机数量的关系3.畅销和滞销商品4.自动售货机的销售情况5.订单支付方式占比6.各消费时段的订单用户…

uni-app 瀑布流布局的实现

方式一&#xff1a;使用纯 CSS 实现 使用 flex 布局方式 <!-- 瀑布流布局 --> <template><view class"container"><viewclass"cont-box":style"{ --layout-width: 100 / flowData.column - flowData.columnSpace % }"v-f…

CatBoost算法模型实现贷款违约预测

前言 此篇文章为整个Boost(提升方法)集成算法模型的终章&#xff0c;前几篇文章依次结合详细项目案例讲解了AdaBoost、GBDT、XGBoost、LighGBM共四个常用的集成算法模型&#xff0c;每一篇文章都包含实战项目以及可运行代码。仅通过看一遍文章不去实践是很难掌握集成算法模型的…

【API篇】三、转换算子API(上)

文章目录 0、demo数据1、基本转换算子&#xff1a;映射map2、基本转换算子&#xff1a;过滤filter3、基本转换算子&#xff1a;扁平映射flatMap4、聚合算子&#xff1a;按键分区keyBy5、聚合算子&#xff1a;简单聚合sum/min/max/minBy/maxBy6、聚合算子&#xff1a;归约聚合re…

maven 新建模块 导入后 按Ctrl 点不进新建模块pom定义

新建的ruoyi-common-mybatisplus 模块,导入一直不正常 画出的模块一直导入不进来 这是提示信息 这是正常的提示信息 加上 <version>3.6.3</version> 后,才一切正常

C++入门之引用与内联函数

一、引用 1、初步理解 引用在语法上的理解就是起别名&#xff0c;用法就是在类型后面加&&#xff0c;例子&#xff1a;int a 1; int& b a; 上例所示&#xff0c;执行后&#xff0c;b就是a的别名&#xff0c;它们代表同一块空间&#xff0c;a的改变会影响b&#xff0…

进阶JAVA篇-如何理解作为参数使用的匿名内部类与 Arrays 类的常用API(九)

目录 目录 API 1.0 Arrays 类的说明 1.1 Arrays 类中的 toString() 静态方法 1.2 Arrays 类中的 copyOfRange(int[] original, int from, int to) 静态方法 1.3 Arrays 类中的 copyOf(int[] original, int newLength) 静态方法 1.4 Arrays 类中的 setAll(do…

深入了解桶排序:原理、性能分析与 Java 实现

桶排序&#xff08;Bucket Sort&#xff09;是一种排序算法&#xff0c;通常用于将一组数据分割成有限数量的桶&#xff08;或容器&#xff09;&#xff0c;然后对每个桶中的数据进行排序&#xff0c;最后将这些桶按顺序合并以得到排好序的数据集。 桶排序原理 确定桶的数量&am…

Unity中用序列化和反序列化来保存游戏进度

[System.Serializable]标记类 序列化 [System.Serializable]是一个C#语言中的属性&#xff0c;用于标记类&#xff0c;表示该类的实例可以被序列化和反序列化。序列化是指将对象转换为字节流的过程&#xff0c;以便可以将其保存到文件、数据库或通过网络传输。反序列化则是将字…

C++桶排序算法的应用:存在重复元素 III

题目 给你一个整数数组 nums 和两个整数 indexDiff 和 valueDiff 。 找出满足下述条件的下标对 (i, j)&#xff1a; i ! j, abs(i - j) < indexDiff abs(nums[i] - nums[j]) < valueDiff 如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例…

日志技术快速入门

1、创建Maven项目 这里不再说如何创建Maven项目 2、导入相关依赖 <dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.12</version></dependency>3、创建配置文件 在re…

嵌入式系统学习路径:

嵌入式系统学习路径&#xff1a; 00001. 确保扎实的C语言基础&#xff0c;包括高级编程知识和数据结构算法。 00002. 00003. 学习Linux应用层开发&#xff0c;包括并发程序设计、网络编程和数据库开发。 00004. 00005. 探索无线通信领域&#xff0c;如Zigbee、低功…

【java学习—八】对象类型转换Casting(1)

文章目录 1. 数据类型转换1.1 基本数据类型的 Casting1.2. 对 Java 对象的强制类型转换(造型)2. 对象类型转换举例 1. 数据类型转换 数据类型转换分为基本数据类型转换和对象类型转换。 1.1 基本数据类型的 Casting (1) 自动类型转换&#xff1a;小的数据类型可以自动转换成…

使用eBPF加速阿里云服务网格ASM

背景 随着云原生应用架构的快速发展&#xff0c;微服务架构已经成为了构建现代应用的主要方式之一。而在微服务架构中&#xff0c;服务间的通信变得至关重要。为了实现弹性和可伸缩性&#xff0c;许多组织开始采用服务网格技术来管理服务之间的通信。 Istio作为目前最受欢迎的…

mac虚拟机安装homebrew时的问题

安装了mac虚拟机&#xff0c;结果在需要通过“brew install svn”安装svn时&#xff0c;才注意到没有下载安装homebrew。 于是便想着先安装homebrew&#xff0c;网上查的教程大多是通过类似以下命令 “ruby <(curl -fsSkL raw.github.com/mxcl/homebrew/go)” 但是都会出现…

Mac OS m1 下安装Gradle5.1

1. 下载、解压 1.1 下载地址 https://gradle.org 往下翻 选择 5.1 或者选择 任何 你想要的版本 ,点击 binary-only 即可下载 . 1.2 解压到指定目录 2. 配置环境变量 2.1 编辑环境文件 vi ~/.bash_profile #GRADLE相关配置 GRADLE_HOME/Users/zxj/Documents/devSoft/grad…

c语言小白如何入门?

c语言小白如何入门&#xff1f; 作为过来人&#xff0c;我觉得刚开始&#xff0c;先按照课本把每个知识点都弄懂&#xff0c;有不懂的地方&#xff0c;先尝试自己理解或借助互联网先搜一下&#xff0c;还是理解不了&#xff0c;就可以去找学得比较好的同学&#xff0c; 最近很…

HarmonyOS 远端状态订阅开发实例

IPC/RPC 提供对远端 Stub 对象状态的订阅机制&#xff0c; 在远端 Stub 对象消亡时&#xff0c;可触发消亡通知告诉本地 Proxy 对象。这种状态通知订阅需要调用特定接口完成&#xff0c;当不再需要订阅时也需要调用特定接口取消。使用这种订阅机制的用户&#xff0c;需要实现消…