当前位置: 首页 > news >正文

C语言柔性数组详解:让你的程序更灵活

柔性数组

    • 一、前言
    • 二、柔性数组的用法
    • 三、柔性数组的内存分布
    • 四、柔性数组的优势
    • 五、总结

一、前言

仔细观察下面的代码,有没有看出哪里不对劲?

struct S
{int i;double d;char c;int arr[];
};

还有另外一种写法:

struct S
{int i;double d;char c;int arr[0];
};

你应该一眼就看到了,结构体的最后一个成员数组的写法是int arr[];或者是int arr[0],这两种写法是等价的,意思是这个数组的大小是不确定的、未知的、可以变化的

C99允许这种特殊的结构体存在。这样的结构体满足下面两个条件:

  1. 最后一个成员变量是一个大小可以变化的数组。
  2. 这个成员数组前面至少有另外一个成员变量。

我们称这个大小可以变化的成员数组为柔性数组

注意,柔性数组不能是结构体里唯一一个成员,下面的代码是不允许的:

struct S
{int arr[0];
};

这篇文章里,我将重点探讨柔性数组的用法、内存分布以及和优势。

二、柔性数组的用法

我不建议在栈上直接定义有柔性数组的结构体,也就是这么写:

struct S s;

因为柔性数组的大小是可以变化的,我建议在堆上申请空间,采取动态内存管理的方法,这样就能发挥出柔性数组大小可以改变的优势。

假设我们使用malloc()函数来开辟空间,一开始应该malloc出多大的空间呢?要回答这个问题,首先我们要知道sizeof(struct S)是多少。

事实上,sizeof(struct S)计算出来的结果是该结构体不考虑柔性数组的大小。如果我们想要给柔性数组开辟空间,malloc出来的大小应该是sizeof(struct S)加上柔性数组的大小。

假设这个柔性数组在结构体中的声明是int arr[0];,我想给这个数组的大小是40个字节,这样这个数组就能存储10个int,那么一开始malloc的大小就应该是sizeof(struct S)+10*sizeof(int),具体的例子如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}return 0;
}

该结构体中的i,d,c等变量可以正常使用。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}ps->i = 10;ps->d = 3.14;ps->c = 'F';return 0;
}

柔性数组也可以像正常的数组一样访问,比如把1~10放进去。注意此时这个数组的容量是10个int,不能越界访问。使用的例子如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}ps->i = 10;ps->d = 3.14;ps->c = 'F';for (int i = 0; i < 10; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}printf("\n");return 0;
}

我们还可以对柔性数组扩容,如果我们想让这个柔性数组的容量是20个int,整个结构体的新的大小就是sizeof(struct S)+20*sizeof(int),因为sizeof(struct S)是不考虑柔性数组的大小时计算的结构体大小。只需要对ps进行realloc就行了。实现代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}ps->i = 10;ps->d = 3.14;ps->c = 'F';for (int i = 0; i < 10; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}printf("\n");struct S* tmp = (struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(int));if (tmp == NULL){printf("realloc()->%s\n", strerror(errno));return 1;}else{ps = tmp;}return 0;
}

扩容后的柔性数组的空间更大了,我们可以把11~20都放进去。实现代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}ps->i = 10;ps->d = 3.14;ps->c = 'F';for (int i = 0; i < 10; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}printf("\n");struct S* tmp = (struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(int));if (tmp == NULL){printf("realloc()->%s\n", strerror(errno));return 1;}else{ps = tmp;}for (int i = 10; i < 20; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 20; i++){printf("%d ", ps->arr[i]);}return 0;
}

当然最后别忘了free掉ps,否则会导致内存泄漏。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}ps->i = 10;ps->d = 3.14;ps->c = 'F';for (int i = 0; i < 10; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}printf("\n");struct S* tmp = (struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(int));if (tmp == NULL){printf("realloc()->%s\n", strerror(errno));return 1;}else{ps = tmp;}for (int i = 10; i < 20; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 20; i++){printf("%d ", ps->arr[i]);}free(ps);ps = NULL;return 0;
}

对于柔性数组的使用,在上面的例子中,可以总结出几个要点:

  1. malloc出来的大小是sizeof(struct S)加上柔性数组的大小,calloc同理。
  2. 扩容时realloc出来的新大小也是sizeof(struct S)加上柔性数组的新大小。
  3. 每次使用malloc和realloc等函数时,需要检查返回值,否则可能导致对NULL指针的解引用(这点是动态内存管理的常识了)。
  4. 一定要记得柔性数组的容量是多少,不要越界访问了,空间不够记得扩容。
  5. 记得free,防止内存泄漏。

三、柔性数组的内存分布

柔性数组是结构体的一个成员数组,在前面的例子中,整个结构体都是在堆上malloc出来的。此时,整个结构体都存储在堆上的一块连续的空间里,包括前面几个成员变量i,d,c和柔性数组arr。也就是这样:
在这里插入图片描述
只不过数组arr的大小是可以改变的,所以叫“柔性数组”。

有些朋友可能会说了,我不需要柔性数组也能实现类似这样的效果呀!我在结构体里存一个指针,指向一块malloc出来的空间,这块空间也是堆上的,可以动态管理。也就是说,像下面这样定义结构体:

struct S
{int i;double d;char c;int* arr;
};

这样似乎还简单一点,先malloc出一个struct S出来,malloc的大小就是sizeof(struct S),像这样:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}return 0;
}

然后再malloc出10个int的大小出来,用结构体中的arr指针来管理这块空间,像这样:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}ps->arr = (int*)malloc(10 * sizeof(int));if (ps->arr == NULL){printf("2: malloc()->%s\n", strerror(errno));return 1;}return 0;
}

此时arr就可以当成一个数组来使用了,比如把1~10放进去。同样还是要注意不要越界访问。示例代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}ps->arr = (int*)malloc(10 * sizeof(int));if (ps->arr == NULL){printf("2: malloc()->%s\n", strerror(errno));return 1;}for (int i = 0; i < 10; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}printf("\n");return 0;
}

你如果觉得空间不够,还可以扩容。比如,你可以把结构体中的arr进行realloc,新的大小能存放20个int。示例代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}ps->arr = (int*)malloc(10 * sizeof(int));if (ps->arr == NULL){printf("2: malloc()->%s\n", strerror(errno));return 1;}for (int i = 0; i < 10; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}printf("\n");int* tmp = (int*)realloc(ps->arr, 20 * sizeof(int));if (tmp == NULL){printf("realloc()->%s\n", strerror(errno));return 1;}else{ps->arr = tmp;}return 0;
}

此时,你就可以把11~20也放进去。实现代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}ps->arr = (int*)malloc(10 * sizeof(int));if (ps->arr == NULL){printf("2: malloc()->%s\n", strerror(errno));return 1;}for (int i = 0; i < 10; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}printf("\n");int* tmp = (int*)realloc(ps->arr, 20 * sizeof(int));if (tmp == NULL){printf("realloc()->%s\n", strerror(errno));return 1;}else{ps->arr = tmp;}for (int i = 10; i < 20; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 20; i++){printf("%d ", ps->arr[i]);}return 0;
}

最后别忘了把arr和ps都free掉,而且顺序不能错了。如果你先free掉了ps,结构体就没了,里面的arr就成为了野指针,内存就泄露了。实现代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S));if (ps == NULL){printf("malloc()->%s\n", strerror(errno));return 1;}ps->arr = (int*)malloc(10 * sizeof(int));if (ps->arr == NULL){printf("2: malloc()->%s\n", strerror(errno));return 1;}for (int i = 0; i < 10; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}printf("\n");int* tmp = (int*)realloc(ps->arr, 20 * sizeof(int));if (tmp == NULL){printf("realloc()->%s\n", strerror(errno));return 1;}else{ps->arr = tmp;}for (int i = 10; i < 20; i++){ps->arr[i] = i + 1;}for (int i = 0; i < 20; i++){printf("%d ", ps->arr[i]);}free(ps->arr);ps->arr = NULL;free(ps);ps = NULL;return 0;
}

那这种实现的内存分布是怎么样的呢?这个结构体是存储在堆上的,用ps来管理,结构体里的一个指针arr又指向了堆上的另一块空间,如下图:
在这里插入图片描述
这种实现方式和柔性数组的方式感觉差不多呀!都是在堆上有个结构体,结构体里有个大小可以变化的数组。那为什么非要搞出来个柔性数组的概念呢?那是因为,柔性数组有它独特的优势。

四、柔性数组的优势

前面我们先用柔性数组实现了一种效果,又不使用柔性数组实现了相似的效果,对比两种实现方式,我们可以做一些总结:

  1. 使用上:柔性数组malloc了一次,free了一次;不使用柔性数组要malloc两次,free两次。柔性数组的使用更加简单,不容易出错。如果不使用柔性数组,可能会忘记free掉结构体里的arr指针,导致内存泄漏。
  2. 效率上:柔性数组的存储空间是连续的,访问时效率更高。

所以,虽然有相似的效果,我更推荐使用柔性数组的方式。

五、总结

在这篇博客里,重点需要掌握以下几点:

  1. 如果结构体里最后一个成员变量是一个数组,并且大小可以变化,这个成员数组就叫做柔性数组。一个结构体里,除了柔性数组外必须至少有一个成员变量。
  2. 使用sizeof计算含有柔性数组的结构体大小时,只计算除柔性数组之外的空间大小。
  3. 使用柔性数组,比不使用柔性数组操作更加简单,不易出错,且效率更高。

相关文章:

C语言柔性数组详解:让你的程序更灵活

柔性数组 一、前言二、柔性数组的用法三、柔性数组的内存分布四、柔性数组的优势五、总结 一、前言 仔细观察下面的代码&#xff0c;有没有看出哪里不对劲&#xff1f; struct S {int i;double d;char c;int arr[]; };还有另外一种写法&#xff1a; struct S {int i;double …...

Redis-带你深入学习数据类型list

目录 1、list列表 2、list相关命令 2.1、添加相关命令&#xff1a;rpush、lpush、linsert 2.2、查找相关命令&#xff1a;lrange、lindex、llen 2.3、删除相关命令&#xff1a;lpop、rpop、lrem、ltrim 2.4、修改相关命令&#xff1a;lset 2.5、阻塞相关命令&#xff1a…...

react拖拽依赖库react-dnd

注&#xff1a;对于表格自定义行可以拖拽和树自定义节点可以拖拽等比较适用&#xff0c;其余的拖拽处理可以使用dragstart&#xff0c;drop等js原生事件来实现 react-dnd使用方法很简单&#xff0c;直接上干货 第一步安装依赖并引入 import { DndProvider } from react-dnd;…...

win10环境安装使用docker-maxwell

目的&#xff1a;maxwell可以监控mysql数据变化&#xff0c;并同步到kafka、mq或tcp等。 maxwell和canal区别&#xff1a; maxwell更轻量&#xff0c;canal把表结构也输出了 docker bootstrap可导出历史数据&#xff0c;canal不能 环境 &#xff1a;win10&#xff0c;mysql5…...

Docker部署RabbitMQ

Docker部署RabbitMQ 介绍 RabbitMQ是一个开源的消息队列系统&#xff0c;它被设计用于在应用程序之间传递消息。它采用了AMQP&#xff08;高级消息队列协议&#xff09;作为底层通信协议&#xff0c;这使得它能够在不同的应用程序之间进行可靠的消息传递。 那么&#xff0c;…...

23个react常见问题

1、setState 是异步还是同步&#xff1f; 合成事件中是异步 钩子函数中的是异步 原生事件中是同步 setTimeout中是同步 相关链接&#xff1a;你真的理解setState吗&#xff1f;&#xff1a; 2、聊聊 react16.4 的生命周期 图片 相关连接&#xff1a;React 生命周期 我对 Reac…...

【python基础】——Anaconda下包更新的坑及安装与卸载、及安装后Jupyter Notebook没反应的解决方法

文章目录 前言一、起因:如何一步步走到卸载重装anaconda?二、卸载anaconda二、重新安装anaconda三、关于安装Anaconda后,打开Jupyter Notebook运行代码没反应且in[ ]没有*前言 本文主要用来记录自己近期踩坑的一些复盘。其中坑有: ‘.supxlabel’ 不起作用的解决pip list 与…...

CSS 中的 display 和 visibility

CSS 中的 display 和 visibility 都可以设置一个元素在浏览器中的显示或隐藏效果。 display: 隐藏某个元素时&#xff0c;不会占用任何空间。换句话讲&#xff0c;不会影响布局。visibility: 隐藏某个元素时&#xff0c;仍需占用与未隐藏之前一样的空间。换句话讲&#xff0c;…...

解决mysql报错this is incompatible with DISTINCT

环境 centos 9 php7.4 mysql5.7 问题 mysql查询报如下错误&#xff1a; SQLSTATE[HY000]: General error: 3065 Expression #1 of ORDER BY clause is not in SELECT list, references column hst_csc.q.timestamp which is not in SELECT list; this is incompatible with…...

C++-map和set

本期我们来学习map和set 目录 关联式容器 键值对 pair 树形结构的关联式容器 set multiset map multimap 关联式容器 我们已经接触过 STL 中的部分容器&#xff0c;比如&#xff1a; vector 、 list 、 deque 、forward_list(C11)等&#xff0c;这些容器统称为序列式…...

微信小程序AI类目-深度合成-AI问答/AI绘画 互联网信息服务算法备案审核通过教程

近期小程序审核规则变化后&#xff0c;很多使用人类小徐提供的chatGPT系统的会员上传小程序无法通过审核&#xff0c;一直提示需要增加深度合成-AI问答、深度合成-AI绘画类目&#xff0c;该类目需要提供互联网信息服务算法备案并上传资质&#xff0c;一般对企业来说这种务很难实…...

蓝桥杯官网练习题(星期一)

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 整个 2020 世纪&#xff08;1901 年 1 月 1 日至 2000 年 12 月 3131 日之间&#xff09;&#xff0c;一共有多少个星期一&#xff1f;(不要告诉我你不知道今天是星…...

centos7更新podman

实验环境&#xff1a;centos7.7.1908 1.安装podman并查看版本 yum install podman podman -v 当前podman版本信息是1.6.4 2.更新podman版本 通过查看资料显示centos 7 支持最高版本为 3.4.4&#xff0c;更新podman大致有以下四步&#xff1a; golang 安装(本次使用版本: 1.…...

Java特性之设计模式【抽象工厂模式】

一、抽象工厂模式 概述 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式 在抽象工厂模式中&#xff0c;接口是…...

机器学习简介

引言 为何现在机器学习如此热门&#xff1f; 主要原因是由于“人类无论如何也做不到在短时间内实现从大量的数据中自动的计算出正确的结果操作”。 什么是机器学习&#xff1f; 所谓的机器学习&#xff0c;就是通过对数据进行反复的学习&#xff0c;来找出其中潜藏的规律和模式…...

linux之perf(2)list事件

Linux之perf(2)list事件 Author&#xff1a;Onceday Date&#xff1a;2023年9月3日 漫漫长路&#xff0c;才刚刚开始… 参考文档: Tutorial - Perf Wiki (kernel.org)perf-list(1) - Linux manual page (man7.org) 1. 概述 perf list用于列出可用的性能事件&#xff0c;这…...

将多个EXCEL 合并一个EXCEL多个sheet

合并老版本xls using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using NPOI.HSSF.UserModel; …...

【送书活动】揭秘分布式文件系统大规模元数据管理机制——以Alluxio文件系统为例

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…...

微信小程序——数据绑定

在微信小程序中&#xff0c;可以通过以下代码实现数据绑定&#xff1a; 在WXML中&#xff0c;使用双大括号{{}}绑定数据&#xff0c;将数据渲染到对应的视图中。 <view>{{message}}</view>在JS中&#xff0c;定义一个数据对象&#xff0c;并将其绑定到页面的data…...

libbpf-bootstrap安卓aarch64适配交叉编译

1.为什么移植 疑惑 起初我也认为&#xff0c;像libbpf-bootstrap这样在ebpf程序开发中很常用的框架&#xff0c;理应支持不同架构的交叉编译。尤其是向内核态的ebpf程序本身就是直接通过clang的-target btf直接生成字节码&#xff0c;各个内核上的ebpf虚拟机大同小异&#xf…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...