C语言——数组

一、数组介绍

C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。

ps:再C99之前的标准不支持变长数组,C99及之后的标准支持变长数组,及数组的长度可以是变量。

数组的声明并不是声明一个个单独的变量,比如 num0、num1、... 、num99,而是声明一个数组变量,比如 num[],然后使用 num[0]、num[1]、...、num[99] 来代表一个个单独的变量。

所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。

数组中的特定元素可以通过索引访问,第一个索引值为 0。

C 语言还允许我们使用指针来处理数组,这使得对数组的操作更加灵活和高效。

二、一维数组的创建

1、一维数组的声明

在 C 中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:

array_type array_name[array_size];

这叫做一维数组。array_size 必须是一个大于零的整数常量,array_type 可以是任意有效的 C 数据类型。例如,要声明一个类型为 int 的包含 10 个元素的数组 num,声明语句如下:

int num[10];

现在 num 是一个可用的数组,可以容纳 10 个类型为 int 的数据。

2、一维数组的初始化

在 C 中,您可以逐个初始化数组,如下所示:

int num[2];//逐个初始化
num[0] = 1;
num[1] = 2;

也可以使用一个初始化语句,如下所示:

int num[2] = {1,2};

大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。

如果省略掉了数组的大小,数组的大小则会是初始化时元素的个数。

因此,如果:

int num[] = {1,2};

这个数组与之前的数组是相同的。

在没有指定数组的大小的时候就必须初始化数组。

有一种情况是不完全初始化,例如:

int num[10] = {1,2};

这里的数组num有10个空间,而初始化时只填入了两个元素,所以空间没有完全被利用,是不完全初始化,这时数组num未初始化的位置是全部被初始化为0了的。

3、一维数组初始化中的知识

#include <stdio.h>int main()
{char ch[3] = {'a','b','c'};printf("%s",ch);return 0;
}

这里的运行结果会有乱码:

为什么呢,是因为这里是完全初始化,数组之中呢没有\0,所以打印完abc不会停止,直到遇见\0才会停止,而后面的数据是不确定的,打印的东西和结束也是不确定的。

#include <stdio.h>int main()
{char ch[10] = {'a','b','c'};printf("%s",ch);return 0;
}

这里的运行结果没有乱码:

原因是这里是不完全初始化,因为\0的ASCII码值为0,所以剩余的部分被初始化为0,故导致剩余的部分都被解析成\0,所以存储会在遇到剩余的部分解析成的\0时停止,就不会出现乱码。

也可以在数组的最后一个元素填入\0主动结束。

#include <stdio.h>int main()
{char ch[] = {'a','b','c','\0'};printf("%s",ch);return 0;
}

因为\0的ASCII码值是数字0,所以数字0与\0的作用一样。

#include <stdio.h>int main()
{char ch[] = {'a','b','c',0};printf("%s",ch);return 0;
}

这里的0是作为\0的ASIIC码,会转换为\0,依旧能实现结束的效果。

char ch[] = "abcde";//数组有6个空间,其中一个是\0

字符串的最后自带\0,也能实现结束的效果。

三、一维数组的使用

1、访问一维数组元素

数组元素可以通过数组名称加索引进行访问。元素的索引是放在方括号内,跟在数组名称的后边。例如:

int num[2] = {1,2};
int firstnum = num[0];

这里是访问num数组的第一个元素,将num数组的第一个元素赋值给firstnum。

下面是一个为数组中某个元素赋值的实例:

int num[2] = {1,2};
num[0] = 6;

上述的语句把数组num中第1个元素的值赋为 6。所有的数组都是以 0 作为它们第一个元素的索引,也被称为基索引,数组的最后一个索引是数组的总大小减去 1。以下是上面所讨论的数组的的图形表示:

2、数组的大小

对于数组,可以用sizeof()函数求出数组存储大小,再除以数组类型的大小,就是数组的大小。例如:

int num[] = {1,2,3,4,5,6};
int sz = sizeof(num) / sizeof(int);

也可以是除以数组的第一个元素。例如:

int num[] = {1,2,3,4,5,6};
int sz = sizeof(num) / sizeof(num[0]);

对于最后一个元素为\0的字符型数组可以用strlen()函数求字符串长度(不包含\0),数组的长度就是字符串长度加一。例如:

#include <stdio.h>
#include <string.h>int main()
{char ch[] = "abc";printf("%zu", strlen(ch) + 1);return 0;
}

3、数组的存储

#include <stdio.h>
#include <string.h>int main()
{int num[10] = {1,2,3,4,5,6,7,8,9,10};for (int i = 0; i < 10;i++){printf("num[%d]的地址是 %p\n",i,&num[i]);}return 0;
}

我们发现数组的地址差值正好是4,原因是这是整型数组,整型数据的大小是四个字节,每个字节一个地址,恰好每个元素地址差值是4。

这样我们能看到数组中的每个元素的存储大小以及存储内容。

随着数组下标增大,地址也在有规律增大,所以我们发现数组中元素是连续的。

四、二维数组的创建

1、二维数组的声明

格式:

type array_name[row_size][column_size];

例如:

int num[10][10];

2、二维数组的初始化

有多种初始化格式:

(1)

int num[3][3] = {1,2,3,4,5,6,7,8,9};

这样会按顺序放置

如果不完全初始化的话,没初始化的会被初始化为0

int num[3][3] = {1,2,3,4,5,6,7};

(2)

int num[3][4] = { {1,2,3,4},{1,2,3,4},{1,2,3,4} };

这个每一个花括号中是每一行的元素

int num[3][4] = { {1,2,3},{1,2},{1} };

这里不完全初始化也会被初始化为0,但位置是不一样的

(3)

char ch[3][4] = {'a','b','c','d','b','c','d','e','c','d','e','\0'};

char ch[3][4] = {'a','b','c','d','b','c','d','e','c'};

不完全初始化的会被初始化为0

这里与整型数组相似

(4)

char ch[3][4] = {"abc","bcd","cde"};

这里的\0是字符串最后自带的。

不完全初始化也会被初始化为0

char ch[3][4] = {"abc","bc","c"};

3、初始化中的小问题

ps:在初始化二维数组是必须指定列数,行数可忽略,及第二个方括号中必须有值,只要有列数,编译器可以推算出初始化需要几行。

其实可以把二维数组看为多个一维数组(看成一维数组的数组),你必须要指出这些的一维数组的大小(不然就不知道要分成几个数组,如果把全部数据都放到一个数组中,那就变成了一维数组,那就乱套了),可以不指出一维数组的数量,对应来看就是列数是必须的,而行数不是必须的。

在C语言中,当你在二维数组中初始化时指定列数是必须的,而行数是可选的,这是因为C语言的设计使得它在内存中按行顺序存储多维数组。

考虑以下情况:

int array[][3] = 
{{1, 2, 3},{4, 5, 6},{7, 8, 9}
};

在这个例子中,我们初始化了一个二维数组,但没有指定行数,只指定了列数。编译器可以从初始化器中看到每一行有三个元素,因此它知道每个子数组的大小。由于C是按行优先顺序存储数组的,编译器只需要知道每一行的大小就能计算整个数组需要多少内存,并正确地将元素放置在内存中。

然而,如果我们没有指定列数,如下所示:

int array[][] = 
{{1, 2, 3},{4, 5, 6},{7, 8, 9}
};

这个声明是非法的,因为编译器不知道每个子数组应该有多大。这会引起问题,例如在内存中分配空间时不知道该分配多少,以及在通过索引访问元素时不知道每一行的偏移量应该是多少。

因此,为了让编译器能够确定数组在内存中的布局,必须至少知道除了最外层之外的所有维度的大小。这允许编译器在内存中正确地布局数组,以及在需要时能够计算出到达任何指定元素需要跳过多少字节。这对于多维数组同样适用,当然,二维数组就是多维数组的最简单的情况。

而对于最外层的维度,即行数,它可以从初始化数据中推断出来,因为你已经提供了完整的初始化列表,编译器可以计算出有多少行。在上面的示例中,编译器会看到有三组花括号,意味着有三行。

五、二维数组的使用

1、二维数组的访问

二维数组的访问与访问一维数组相似,访问二维数组元素需要两个索引:

int value = num[2][2]; // 访问第3行第3列的元素

2、二维数组的打印

这样使二维数组更可视化。

打印二维数组是我们可以用两个变量,一个控制行一个控制列,使用嵌套循环。

#include <stdio.h>int main()
{int num[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };int i = 0, j = 0;for (i = 0; i < 3; i++){for (j = 0; j < 4; j++){printf("%d ",num[i][j]);}printf("\n");}return 0;
}

3、二维数组的存储

#include <stdio.h>int main()
{int num[3][4] = { {1,2,3,4},{2, 3, 4, 5},{3, 4, 5, 6} };int i = 0, j = 0;for (i = 0; i < 3; i++){for (j = 0; j < 4; j++){printf("num[%d][%d]的地址是 %p\n",i,j,&num[i][j]);}}return 0;
}

我们发现每个元素的地址的大小相差4,所以二维数组也是连续的,是一行连一行的。

实际上应该是这样的:

六、更高维度的数组

对于更高维度的数组,声明和使用的方式类似,只是会有更多的索引。

可以将二维数组看作一维数组的数组,每一行就是二维数组的子数组,三维数组看作二维数组的数组,以此类推。

1、三维数组的声明

声明三维数组:

type arrayName[xSize][ySize][zSize];

例如,声明一个2x3x4的三维整数数组:

int threeDArray[2][3][4];

2、三维数组的初始化

初始化三维数组:

int threeDArray[2][3][4] = 
{{{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}},{{13, 14, 15, 16},{17, 18, 19, 20},{21, 22, 23, 24}}
};

3、三维数组的访问

访问三维数组元素

int value = threeDArray[0][1][2]; // 访问第一个2D数组,第2行第3列的元素

在使用多维数组时,务必注意数组的边界。在C语言中,数组索引是从0开始的,所以最后一个元素的索引总是比数组的长度小1。

还要注意的是,C语言中没有数组边界检查,所以如果你尝试访问数组外的元素,可能会导致未定义的行为,包括程序崩溃。

多维数组通常在内存中是连续存储的,对于二维数组,第一维通常对应行,第二维对应列。在内存中,这些数据是行优先存储的,也就是说,数组的第一行的元素在前,第二行的元素在后,以此类推。

更高维度的数组与这些相似。

一般使用一维数组和二维数组。

七、数组越界

C语言中的数组越界访问是当一个程序试图访问数组索引之外的内存位置时发生的。C语言本身不会检查数组的边界,因此当你尝试访问超出其声明大小的数组元素时,你可能会读取或写入相邻的内存区域。这可能导致不可预测的行为,包括数据损坏、程序崩溃或安全漏洞。

数组索引是从0开始的,如果数组的大小是n,则数组的最后一个元素的索引是n - 1。

如果访问小于0的索引对应的元素,或大于n - 1的索引对应的元素就会越界,这就是越界访问。

下面演示了一个数组越界访问的情况:

#include <stdio.h>int main()
{int num[5] = {1,2,3,4,5};for (int i = 0; i < 10; i++){printf("%d\n",num[i]);}return 0;
}

这里的数组num的大小是5,而循环打印会打印到第十个元素,及下标为9的元素,超过数组范围的值是不确定的。

为了避免数组越界,你应该总是确保你的索引在数组的有效范围内。下面是一些常见的做法来避免数组越界错误:

  1. 使用常量或宏定义数组的大小。
  2. 使用循环时,确保循环计数器不会超过数组的边界。
  3. 在对数组进行索引之前,检查索引值是否在有效范围内。

八、数组作为函数参数

如果想要在函数中传递一个一维数组作为参数,必须以下面三种方式来声明函数形式参数,这三种声明方式的结果是一样的,因为每种方式都会告诉编译器将要接收一个整型指针。同样地,也可以传递一个多维数组作为形式参数。

(1)数组名加[]

void BubbleSort(int num[], int length)

(2)指针

void BubbleSort(int *num, int length)

(3)数组名加[size]

void BubbleSort(int num[size], int length)

冒泡排序:

#include <stdio.h>void BubbleSort(int num[], int length)
{for (int step = 0; step < length - 1; step++){for (int i = 0; i < length - step - 1; i++){if (num[i] > num[i + 1]){int temp = num[i];num[i] = num[i + 1];num[i + 1] = temp;}}}
}int main()
{int num[10] = { 1,23,2,45,22,19,23,45,98,37 };int length = sizeof(num) / sizeof(int);BubbleSort(num, length);for (int j = 0; j < 10; j++){printf("%d ",num[j]);}return 0;
}

这里传参的形参是数组名加[]。

九、数组名

1、正常情况

在C语言中,数组名通常代表数组首元素的地址

普通使用下的数组名:当数组名用在大多数表达式中时,它会被编译器解释为数组首元素的地址。例如,如果有一个数组 int arr[10],那么表达式 arr 就会被转换为指向 arr[0] 的指针。

数组名作为函数参数:当数组名作为参数传递给一个函数时,它实际上是传递了指向数组首元素的指针,而不是整个数组的拷贝。这意味着在函数内部,数组名代表的是首元素的地址。

2、两个特殊情况

(1)sizeof 运算符:

sizeof(数组名)

当数组名与 sizeof 运算符一起使用时,它不是首元素的地址。例如,sizeof(arr) 会返回整个数组的大小,而不是数组首元素的大小。

(2)& 运算符:

&数组名

&arr 会给出整个数组的地址,其类型是指向整个数组的指针,而不仅仅是首元素的地址。这里的整个数组的地址虽然与数组首元素地址数值上相等,但是它们的类型不同。

如果 int arr[10],那么

printf("%p\n", arr);

printf("%p\n",&arr);

输出的值看起来会是一样的,不过它们的类型是不同的:

&arr 得到的是整个数组的地址,它的类型是指向整个数组的指针,即 int (*)[10]。
arr 会退化成指向数组首元素的指针,它的类型是 int*。

在内存中,数组的起始地址与它的第一个元素的地址确实是相同的位置。但从类型系统的角度来看,&arr 和 arr 的类型是不同的,这在一些特定的情况下(比如传递给需要类型精确匹配的函数参数时)会变得重要。

3、arr和&arr[0]和&arr

#include <stdio.h>int main()
{int arr[10] = {0};printf("%p\n", arr);printf("------------------\n");printf("%p\n", &arr[0]);printf("------------------\n");printf("%p\n", &arr);return 0;
}

运行结果:

我们发现数值是一样的,但其实类型是不一样的,下面我们开始证明:

printf("%p\n", &arr[0]);
printf("%p\n", &arr[0] + 1);

我们知道这样操作会打印两个地址,加一是跳到下一个元素,所以运行结果是:

C转化为十进制为12,所以两个十六进制数字差值为4,恰好是一个整型的大小,刚好是整型数组,数组的一个元素的大小是4,所以跳了一个元素,这里的元素是一个数组的元素,所以这里的&arr[0]是数组的首元素的地址。

#include <stdio.h>int main()
{int arr[10] = {0,1,2,3,4,5,6,7,8,9};printf("%p\n", arr);printf("%p\n", arr + 1);printf("------------------\n");printf("%p\n", &arr[0]);printf("%p\n", &arr[0] + 1);printf("------------------\n");printf("%p\n", &arr);printf("%p\n", &arr + 1);return 0;
}

运行结果:

我们发现,这里的arr和&arr[0]都是跳了一个数组的元素,正好是4字节,所以他们两个是一样的,都是表示数组的首元素地址。

而&arr跳的不是4个字节,而是40十个字节,实际上是跳了一个数组,这个数组是十个元素,有是整型数组,正好是40个字节,有此可说明&arr的类型是int(*)[10],它是一个指向整个数组的指针。

十、高维数组数组名

1、正常情况

二维数组的数组名一般也是作为首元素的地址,但与一维数组不同的是,二维数组的首元素是它的子数组,及二维数组的首元素也是数。更高维数组的数组名仍然可以看作是指向数组首元素的指针。但对于高维数组来说,首元素本身还是一个数组。所以,对于高维数组,数组名表示的是指向第一个子数组的指针。

所以高维数组与一维数组不同的就是(这里用二维数组举例):

int arr[3][4] = {0};
arr;

这里的arr是高维数组的首元素地址,但首元素地址指向的是一个子数组(这里可以看作高维数组是数组的数组)

#include <stdio.h>int main()
{int arr[3][4] = {0};printf("%p\n", arr);printf("%p\n", arr + 1);printf("------------------\n");printf("%p\n", &arr[0]);printf("%p\n", &arr[0] + 1);return 0;
}

运行结果:

这里的arr和&arr[0]是高维数组的首元素地址,但首元素地址指向的是一个子数组。所以会跳一个子数组,这里一个子数组是四个整型,所以跳了16个字节。

2、两种特殊情况

一维数组的理论对于一维数组是正确的,对于二维及其他高维数组也是适用的,高维数组的数组名也有这两个特殊情况。

(1)sizeof(数组名)会输出整个数组的大小

int arr[3][4] = {0};
int sz = sizeof(arr);
printf("%d\n", sz);

运行结果:

(2)&arr是指向整个数组的指针

printf("%p\n", &arr);
printf("%p\n", &arr + 1);

运行结果:

两个地址相差了48个字节,正好跳了一个数组。

3、二维数组的行列

#include <stdio.h>int main()
{int arr[3][4] = {0};int row = sizeof(arr) / sizeof(arr[0]);//总大小除以行的大小,得到有几行int column = sizeof(arr[0]) / sizeof(arr[0][0]);//一行的大小除以单个元素的大小,得到一行有几个,即有几列printf("%d %d",row,column);return 0;
}

求二维数组的行数就是求二维数组的二维的尺寸,求二维数组的列数就是求二维数组的一维的尺寸。这就是通过sizeof求高维数组的每一维的尺寸。

4、高维数组的每一维的尺寸

对于更高维度的数组,可以用类似的方式计算每个维度的尺寸,只要是针对静态分配的数组进行操作。例如,对于一个三维数组int arr[2][3][4]可以按以下方式计算各个维度的尺寸:

#include <stdio.h>int main()
{int arr3D[2][3][4] = {0};int depth = sizeof(arr3D) / sizeof(arr3D[0]);       // 总大小除以第一层的大小,得到深度int row = sizeof(arr3D[0]) / sizeof(arr3D[0][0]);   // 第一层大小除以第一行的大小,得到行数int column = sizeof(arr3D[0][0]) / sizeof(arr3D[0][0][0]); // 第一行大小除以单个元素的大小,得到列数return 0;
}

请注意,这种方法只适用于数组的尺寸在编译时是已知的情况。对于动态分配的数组或者通过指针传递到函数的数组,您无法使用 sizeof 来获取它们的尺寸,因为 sizeof 对指针来说只能得到指针本身的大小,而不是它指向的数据的大小。

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

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

相关文章

软件系统质量保证计划书

本计划描述了信息系统项目质量保证工作相关的一些情况&#xff0c;是软件质量保证过程和方针在项目中的具体实施计划。 计划中阐述了质量保证工作的基本目标&#xff1b;项目的基本情况&#xff1b;质量保证工作所需的资源&#xff1b;质量保证的主要工作&#xff1b;工作量估算…

openGuass:极简版安装

目录 一、openGauss简介 二、初始化安装环境 1.创建安装用户 2.修改文件句柄设置 ​3.修改SEM内核参数 4.关闭防火墙 6.禁用SELINUX 7.安装依赖软件 8.重启服务器 三、安装数据库 1.下载安装包 2.创建安装目录 3.解压安装包 4.执行安装 5.验证安装 四、gsql工具…

循环神经网络中的梯度消失或梯度爆炸问题产生原因分析(二)

上一篇中讨论了一般性的原则&#xff0c;这里我们具体讨论通过时间反向传播&#xff08;backpropagation through time&#xff0c;BPTT&#xff09;的细节。我们将展示目标函数对于所有模型参数的梯度计算方法。 出于简单的目的&#xff0c;我们以一个没有偏置参数的循环神经…

医院设置反馈投诉建议二维码的好处

将投诉建议的记录单制作成二维码,放在导医台、挂号窗口、门诊门口、电梯等公共区域,群众在就医过程中遇到的种种难点、堵点&#xff0c;皆可通过扫码进行评价、投诉,医院会及时收到信息安排员工第一时间与投诉人联系沟通解决&#xff0c;做到“码”上建议&#xff0c;马上落实。…

什么牌子的猫罐头健康又实惠?五大猫罐头推荐排行榜

新手养猫很容易陷入疯狂购买的模式&#xff0c;但有些品牌真的不能乱买&#xff01;现在的大环境不太好&#xff0c;我们需要学会控制自己的消费欲望&#xff0c;把钱花在刀刃上&#xff01;现在宠物市场真的很内卷&#xff0c;很多品牌都在比拼产品的数据和营养成分。很多铲屎…

PyQt6 基类QObject类介绍以及应用

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计51条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

Ubuntu 22.04 LTS上安装Docker-ce

在Ubuntu 22.04 LTS上安装Docker-ce Docker是一个开源平台&#xff0c;用于自动化应用程序的部署、扩展和管理。它使用容器技术&#xff0c;使开发、测试和部署过程更加简化和可靠。本文将介绍在Ubuntu 22.04 LTS上安装Docker-ce的步骤。 步骤1&#xff1a;更新软件包列表 …

qt-C++笔记之使用QLabel和QPushButton实现一个bool状态的指示灯

qt-C笔记之使用QLabel和QPushButton实现一个bool状态的指示灯 code review! 文章目录 qt-C笔记之使用QLabel和QPushButton实现一个bool状态的指示灯1.QPushButton实现2.QLabel实现2.QLabel实现-对错符号 1.QPushButton实现 运行 代码 #include <QtWidgets>class Ind…

学习Java第74天,Ajax简介

什么是ajax AJAX Asynchronous JavaScript and XML&#xff08;异步的 JavaScript 和 XML&#xff09;。 AJAX 不是新的编程语言&#xff0c;而是一种使用现有标准的新方法。 AJAX 最大的优点是在不重新加载整个页面的情况下&#xff0c;可以与服务器交换数据并更新部分网页…

Web前端-JavaScript(对象)

文章目录 1.对象1.1 概念1.2 创建对象三种方式**对象字面量创建对象**&#xff1a;new Object创建对象构造函数创建对象 1.3 遍历对象 2.作用域1.1 概述1.2 全局作用域1.3 局部作用域1.4 JS没有块级作用域1.5 变量的作用域1.6 作用域链1.7 预解析 1.对象 1.1 概念 什么是对象 …

如何衡量和提高测试覆盖率?

衡量和提高测试覆盖率&#xff0c;对于尽早发现软件缺陷、提高软件质量和用户满意度&#xff0c;都具有重要意义。如果测试覆盖率低&#xff0c;意味着用例未覆盖到产品的所有代码路径和场景&#xff0c;这可能导致未及时发现潜在缺陷&#xff0c;代码中可能存在逻辑错误、边界…

通讯录应用程序开发指南

目录 一、前言 二、构建通讯录应用程序 2.1通讯录框架 (1)打印菜单 (2) 联系人信息的声明 (3)创建通讯录 (4)初始化通讯录 2.2功能实现 (1)增加联系人 (2)显示联系人 (3)删除联系人 (4)查找联系人 (5)修改联系人 (6)排序联系人 三、通讯录的优化 3.1 文件存储 …

2. 创建型模式 - 抽象工厂模式

亦称&#xff1a; Abstract Factory 意图 抽象工厂模式是一种创建型设计模式&#xff0c; 它能创建一系列相关的对象&#xff0c; 而无需指定其具体类。 问题 假设你正在开发一款家具商店模拟器。 你的代码中包括一些类&#xff0c; 用于表示&#xff1a; 一系列相关产品&…

yum install net-tools 命令报错,无法安装成功

编辑网卡文件 插入数据&#xff0c;输入&#xff1a; i 保存编辑&#xff1a;输入 Esc 然后:wq

初学gitrepo的种种

经过各种折腾之后&#xff0c;发现git其实还是很简单的&#xff1b; 首先你需要两台机器&#xff0c;一台作为服务器&#xff0c;一台作为开发机器&#xff0c;开发机器从服务器上拉取代码。 目 目录 git建仓 开发机器拉取代码 初始化仓代码 repo管理 repo工具的下载 …

如何使用Docker搭建青龙面板并结合内网穿透工具发布至公网可访问

文章目录 一、前期准备本教程环境为&#xff1a;Centos7&#xff0c;可以跑Docker的系统都可以使用。本教程使用Docker部署青龙&#xff0c;如何安装Docker详见&#xff1a; 二、安装青龙面板三、映射本地部署的青龙面板至公网四、使用固定公网地址访问本地部署的青龙面板 正文…

腾讯云发布升级版金融音视频解决方案,提供全新架构、安全和特性

远程银行、视频尽调、全媒体客服、路演直播……近年来&#xff0c;音视频技术支撑下的非接触式金融服务&#xff0c;成为了金融机构数字化转型和探索服务创新的重要方向。 12月21日&#xff0c;腾讯云正式发布升级版金融级音视频解决方案。新方案在架构、安全和特性上进行全面…

设计模式分类

不同设计模式的复杂程度、 细节层次以及在整个系统中的应用范围等方面各不相同。 我喜欢将其类比于道路的建造&#xff1a; 如果你希望让十字路口更加安全&#xff0c; 那么可以安装一些交通信号灯&#xff0c; 或者修建包含行人地下通道在内的多层互通式立交桥。 最基础的、 底…

性能压测工具:wrk

一般我们压测的时候&#xff0c;需要了解衡量系统性能的一些参数指标&#xff0c;比如。 1、性能指标简介 1.1 延迟 简单易懂。green:一般指响应时间 95线&#xff1a;P95。平均100%的请求中95%已经响应的时间 99线&#xff1a;P99。平均100%的请求中99%已经响应的时间 平均…

linux 上安装 minio

第一步&#xff0c;下载 wget https://dl.minio.org.cn/server/minio/release/linux-amd64/minio 第二步&#xff0c;修改权限 chmod x minio 第三步&#xff0c;设置 Path mv minio /usr/local/bin/ 第四步&#xff0c;创建 minio mkdir minio 第五步&#xff0c;启动 …