C语言数组全面解析:从初学到精通
数组
- 1. 前言
- 2. 一维数组的创建和初始化
- 3. 一维数组的使用
- 4. 一维数组在内存中的存储
- 5. 二维数组的创建和初始化
- 6. 二维数组的使用
- 7. 二维数组在内存中的存储
- 8. 数组越界
- 9. 数组作为函数参数
- 10. 综合练习
- 10.1 用函数初始化,逆置,打印整型数组
- 10.2 交换两个整型数组
- 10.3 三子棋
- 10.4 扫雷

1. 前言
大家好,我是努力学习游泳的鱼。今天我们来学习数组。

数组分为一维数组和二维数组,我们需要学习它们如何创建和初始化,如何使用,如何在内存中存储。话不多说,让我们开始对数组的学习吧。
2. 一维数组的创建和初始化
数组是一组相同类型元素的集合。
一维数组的创建格式如下:
数组的元素类型 数组名[常量表达式];
int arr[100]; // 表示数组能存放100个int类型的数据
我们使用大括号来初始化数组。
完全初始化:对数组的所有元素都进行初始化。大括号里初始化的元素个数和数组最多存放的元素个数相同。
int arr[10] = {1,2,3,4,5,6,7,8,9,10}; // 完全初始化:数组最多存放10个元素,大括号内初始化了10个元素
不完全初始化:只初始化数组的部分元素,剩下的被初始化成0。
int arr[100] = {0}; // 不完全初始化:第一个元素被手动初始化成0,剩下的元素默认被初始化为0
如果对数组初始化,数组大小可以省略,默认为初始化元素的个数。如下面两种写法效果是相同的。
int arr[5] = {1,2,3,4,5};
int arr[] = {1,2,3,4,5}; // 省略数组大小,默认是5
如果创建数组时不初始化,则数组大小不能省略,此时分为两种情况:
- 局部数组里存放的都是随机值。
- 全局数组会被默认初始化为
0。
int arr1[10]; // 默认初始化为0int main()
{int arr2[10]; // 存储的是随机值return 0;
}
对于一个变量,这两种情况也成立。
- 当一个局部变量不初始化时,存储的是随机值。
- 当一个全局变量或静态变量不手动初始化时,会被默认初始化成
0。
int a; // 默认初始化为0int main()
{static int b; // 默认初始化为0int c; // 存储的是随机值return 0;
}
本质上,这是存储位置的差异导致的。局部变量是存储在栈区的,栈区上的数据如果不初始化,存储的是随机值。全局变量和静态变量是存储在静态区的,静态区上的数据如果不手动初始化,会被默认初始化为0。
C99中引入了变长数组的概念,允许数组的大小用变量来指定,如果编译器不支持C99中的变长数组,那就不能使用。
int n = 10;
int arr[n]; // 变长数组
变长数组不能初始化。
int n = 10;
int arr[n] = {0}; // 不能像这样初始化
3. 一维数组的使用
数组通过下标来访问,数组的下标是从
0开始的。
[]是下标引用操作符。
比如,int arr[] = {10,20,30,40,50};,10的下标是0,20的下标是1,30的下标是2,40的下标是3,50的下标是4。
那么,arr[3]对应的就是40,如果我们想把40改成400,就这么写:arr[3] = 400;
我们如何计算数组的元素个数呢?很简单,用数组的总大小除以数组一个元素的大小就行了。比如对于arr数组,数组元素个数sz就可以这么算:int sz = sizeof(arr) / sizeof(arr[0]);
假设我们想存储1~100的整数并打印出来,就可以这么写:
#include <stdio.h>int main()
{int arr[100] = { 0 };int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (; i < sz; ++i){arr[i] = i + 1;}for (i = 0; i < sz; ++i){printf("%d ", arr[i]);}return 0;
}
4. 一维数组在内存中的存储
一维数组在内存中是连续存放的。
随着数组下标的增长,地址是由低到高变化的。
我们可以写个程序来验证。
#include <stdio.h>int main()
{int arr[10] = { 0 };int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (; i < sz; ++i){printf("&arr[%d] = %p\n", i, &arr[i]);}return 0;
}
我们把数组元素的地址按照下标从低到高打印出来。

我们发现,相邻两个元素之间的地址都差4,这是因为数组在内存中是连续存放的,相邻元素的地址就差一个int,即4个字节。
并且,随着下标的增长,地址是由低到高变化的。
5. 二维数组的创建和初始化
如我们想要创建一个三行五列的二维整型数组,就可以这么写:int arr[3][5];这个数组有三行五列,共15个元素,每个元素是int类型的。
int int int int int
int int int int int
int int int int int
对二维数组进行初始化要使用大括号,初始化时会一行一行放,一行放满后才会放下一行。若是不完全初始化,剩余元素会被默认初始化成0。
如:int arr[3][5] = { 1,2,3,4,5,6 };的效果是:
1 2 3 4 5
6 0 0 0 0
0 0 0 0 0
由于二维数组的每一行都可以看作一个一维数组,如果要对每一行分别初始化,可以在大括号里使用大括号。
这么说有点抽象,举个例子:int arr[3][5] = { {1,2}, {3,4}, {5,6} };的效果是:
1 2 0 0 0
3 4 0 0 0
5 6 0 0 0
如果对二维数组初始化,二维数组的行可以省略,但是列不能省略。如果省略二维数组的行,编译器会根据初始化的内容来确定有几行。
如:int arr[][5] = {1,2,3,4,5,6};的效果是:
1 2 3 4 5
6 0 0 0 0
由于两行就够放了,编译器会默认行数为2。
再比如:int arr[][5] = { {1,2}, {3,4}, {5,6} };的效果是:
1 2 0 0 0
3 4 0 0 0
5 6 0 0 0
由于3行就够放了,编译器会默认行数为3。
如果我们想给数组的所有元素都初始化成0,就可以这么写:
int arr[3][5] = {0};数组的第一个元素被初始化成0,剩下的元素会被默认初始化成0,效果是,数组的全部元素都被初始化成0。
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
6. 二维数组的使用
二维数组也是用下标来访问的。和一维数组的区别是,二维数组有两个下标,行标和列标。行标和列标都是从0开始的。比如说,一个3行5列的数组arr,每个位置的元素的访问方式如下:
arr[0][0] arr[0][1] arr[0][2] arr[0][3] arr[0][4]
arr[1][0] arr[1][1] arr[1][2] arr[1][3] arr[1][4]
arr[2][0] arr[2][1] arr[2][2] arr[2][3] arr[2][4]
如果我们想把这些元素打印出来,可以用一层循环产生行标,另一层循环产生列标。每行打印完后,记得换个行。
#include <stdio.h>int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7} };int i = 0;for (; i < 3; ++i){int j = 0;for (; j < 5; ++j){printf("%d ", arr[i][j]);}printf("\n");}return 0;
}
当然,二维数组有几行几列也是可以通过代码计算出来的。
计算行数的方法:sizeof(arr) / sizeof(arr[0]);即数组的总大小除以数组第一行元素的大小。
计算列数的方法:sizeof(arr[0]) / sizeof(arr[0][0]);即数组第一行元素的大小除以数组第一行第一列的元素的大小。
上面的代码就可这样改进:
#include <stdio.h>int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7} };int i = 0;for (; i < sizeof(arr) / sizeof(arr[0]); ++i){int j = 0;for (; j < sizeof(arr[0]) / sizeof(arr[0][0]); ++j){printf("%d ", arr[i][j]);}printf("\n");}return 0;
}
7. 二维数组在内存中的存储
我们用下面的程序把二维数组每个元素的地址打印出来。
#include <stdio.h>int main()
{int arr[3][5] = { 0 };int i = 0;for (; i < sizeof(arr) / sizeof(arr[0]); ++i){int j = 0;for (; j < sizeof(arr[0]) / sizeof(arr[0][0]); ++j){printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);}}return 0;
}

我们发现,每两个元素之间都差4个字节,每当发生换行,如第一行最后一个元素arr[0][4]到第二行第一个元素arr[1][0]也差4个字节。arr是一个整型数组,每两个元素之间差1个int类型的大小。这说明:
二维数组在内存中也是连续存放的。
随着下标的增长,地址也是由低到高变化的。
除此之外,我们还可以把二维数组的每个元素理解成一维数组。如:对于三行五列的二维数组arr,arr[0]就是这个二维数组的第一个元素,同时arr[0]也是一个有五个元素的一维数组,这五个元素分别是arr[0][0],arr[0][1],arr[0][2],arr[0][3],arr[0][4]。
8. 数组越界
数组的下标是有范围限制的。
数组的下标规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。
所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。
C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,所以程序员写代码时,最好自己做越界的检查。
如下面的程序,当i为10时就越界了。
int main()
{int arr[10] = {0};int i = 0;for (; i<=10; ++i){arr[i] = i;}return 0;
}
二维数组的行和列也可能存在越界。
9. 数组作为函数参数
数组名表示什么?看看下面的代码:
#include <stdio.h>int main()
{int arr[10] = { 0 };printf("arr = %p\n", arr);printf("arr + 1 = %p\n", arr + 1);printf("&arr[0] = %p\n", &arr[0]);printf("&arr[0] + 1 = %p\n", &arr[0] + 1);printf("&arr = %p\n", &arr);printf("&arr + 1 = %p\n", &arr + 1);printf("sizeof(arr) = %d\n", sizeof(arr));return 0;
}
运行结果:

由运行结果可知,数组名(arr)和数组首元素地址(&arr[0])是完全相同的,且+1之后也是完全相同的,都跳过了4个字节(1个int)。数组的地址(&arr)和前两者值是相同的,但+1之后跳过了40个字节(即跳过了整个数组),这是因为,如果写arr或&arr[0]都表示首元素地址,即第一个整型元素的地址,+1会跳过一个整型;如果写&arr,取出的是整个数组的地址,+1自然也跳过了整个数组。注意:以上所有计算都是十六进制的计算,如所谓的跳过40个字节其实是+0x28,再转换成十进制后得到的40。
并且,sizeof(arr)计算的是整个数组的大小,即40。
数组名一般表示数组首元素的地址。但是有两个例外:
- sizeof(数组名),数组名不是数组首元素的地址,数组名表示整个数组,计算的是整个数组的大小。
- &数组名,数组名不是数组首元素的地址,数组名表示整个数组,取出的是整个数组的地址。
题目:写一个函数,对一个整型数组进行冒泡排序。
冒泡排序:对数组中
2个相邻的元素进行比较,如果不满足就交换。
比如,一个数组里存放的是
9 8 7 6 5 4 3 2 1 0
我想把它排成升序,也就是左边的数要比右边的数小。
首先比较9和8,因为9比8大,不满足升序,就交换。
8 9 7 6 5 4 3 2 1 0
接着比较9和7,因为9比7大,不满足升序,就交换。
8 7 9 6 5 4 3 2 1 0
接着比较9和6,因为9比6大,不满足升序,就交换。
8 7 6 9 5 4 3 2 1 0
……
这一趟冒泡排序下来,数组就排序成
8 7 6 5 4 3 2 1 0 9
9的位置就正确了。接下来进行下一趟冒泡排序。由于9的位置处在正确的位置上,下一趟冒泡排序就不需要考虑9了,只需排序除了9之外的数字。
首先比较8和7,因为8比7大,不满足升序,就交换。
7 8 6 5 4 3 2 1 0 9
接着比较8和6,因为8比6大,不满足升序,就交换。
7 6 8 5 4 3 2 1 0 9
……
这一趟冒泡排序下来,数组就排序成
7 6 5 4 3 2 1 0 8 9
8的位置就正确了。
有没有发现,一趟冒泡排序,可以使一个数字的位置正确。那么,假设有10个数字,总共需要几趟冒泡排序呢?答案:10个数字需要9趟冒泡排序。因为一趟冒泡排序搞定一个数字,9趟冒泡排序就搞定9个数字,最后一个数字的位置自然也是正确的。
那么一趟内部又需要多少次比较呢?假设有10个数字,第一趟就需要比较9次,第一趟结束后就搞定了其中一个数字,只需排序剩下9个数字,所以第二趟需要比较8次。由于每趟排序都能够搞定一个数字,每趟排序都会比上一趟少一次比较,这样就知道每一趟需要几次比较了。
有了以上的分析,我们需要写两层循环。外层循环负责控制冒泡排序的趟数,假设数组有sz个元素,就需要排序sz-1趟;内层循环控制一趟内部冒泡排序的比较,第一趟需要sz-1次比较,第二趟需要sz-2次比较,后面每趟都比前一趟少一次比较,如果外层循环的循环变量(假设是i)是从0开始的,那第i趟就需要sz-1-i次比较。
如果一趟比较完后没有发生交换,则数组就已经有序了,就不需要继续排序了。我们可以定义一个flag并初始化为1,假设数组已经有序。如果发生交换,则把flag改成0。如果一趟冒泡排序中没有发生交换,则flag仍然是1,就已经有序了,不需要继续排序了。
数组元素个数怎么知道呢?一定要在数组创建的局部范围内计算数组的元素个数int sz = sizeof(arr) / sizeof(arr[0]);因为如果传参给别的函数后,我们使用数组名传参,由前面的知识可知,数组名表示数组首元素的地址,传递过去的是一个指针,所以sizeof(arr)就是4或者8,sizeof(arr) / sizeof(arr[0])这个表达式是无法计算出数组元素个数的。
#include <stdio.h>void bubble_sort(int arr[], int sz)
{int i = 0;for (; i < sz - 1; ++i){// 一趟冒泡排序int flag = 1; // 假设已经有序int j = 0;for (; j < sz - 1 - i; ++j){if (arr[j] > arr[j + 1]){flag = 0;// 交换int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}if (1 == flag)return;}
}int main()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);// 冒泡排序bubble_sort(arr, sz);int i = 0;for (; i < sz; ++i){printf("%d ", arr[i]);}return 0;
}
当然,就一种情况是无法代表所有场景的。我写了个测试代码,在不同场景下测试这个冒泡排序是否正确,供大家参考。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>int test_bubble_sort()
{srand((unsigned int)time(NULL));const int sz = 100; // 数组元素个数int* arr = (int*)malloc(sz * sizeof(int));if (NULL == arr){perror("test_bubblesort::malloc");return 0;}int i = 0;for (; i < 1000; ++i){// 生成随机数组int j = 0;for (; j < sz; ++j){arr[j] = rand();}// 冒泡排序bubble_sort(arr, sz);// 检验排序是否成功for (j = 0; j < sz - 1; ++j){if (arr[j] > arr[j + 1]){free(arr);return 0; // 排序失败}}}free(arr);return 1; // 检验成功
}int main()
{int ret = test_bubble_sort();if (1 == ret)printf("检验成功\n");elseprintf("检验失败\n");return 0;
}
10. 综合练习
10.1 用函数初始化,逆置,打印整型数组
初始化和打印应该相当简单了吧,只需要产生所有的下标,遍历数组,就能够访问整个数组并初始化或打印了。唯一需要注意的是,整型数组无法在函数内部使用sizeof(arr) / sizeof(arr[0])计算元素个数,因为数组作为函数参数传递时,传递的是首元素的地址。
初始化函数(假设初始化为全0):
void init(int arr[], int sz)
{int i = 0;for (; i < sz; ++i){arr[i] = 0;}
}
打印函数:
#include <stdio.h>void print(int arr[], int sz)
{int i = 0;for (; i < sz; ++i){printf("%d ", arr[i]);}printf("\n");
}
接下来讲讲如何逆置。类似字符串的逆置,整型数组的逆置只需交换第一个元素和最后一个元素,再交换第二个元素和倒数第二个元素,接着交换第三个元素和倒数第三个元素……
如果用下标来访问数组,我们需要一个左下标left指向第一个元素,一个右下标right指向最后一个元素,交换后,left向后走,right向前走,当left还在right左边时,说明还有元素可以交换,否则就跳出循环。
void reverse(int arr[], int sz)
{int left = 0;int right = sz - 1;while (left < right){int tmp = arr[left];arr[left] = arr[right];arr[right] = tmp;++left;--right;}
}
10.2 交换两个整型数组
如何交换两个整型数组arr1和arr2(假设两个数组一样大)呢?
很简单,只需要遍历两个数组,把对应位置的元素交换就行了!
#include <stdio.h>int main()
{int arr1[] = { 1,3,5,7,9 };int arr2[] = { 2,4,6,8,0 };int i = 0;int sz = sizeof(arr1) / sizeof(arr1[0]);printf("交换前:\n");printf("arr1: ");for (i = 0; i < sz; ++i){printf("%d ", arr1[i]);}printf("\narr2: ");for (i = 0; i < sz; ++i){printf("%d ", arr2[i]);}printf("\n");// 交换arr1和arr2for (i = 0; i < sz; ++i){int tmp = arr1[i];arr1[i] = arr2[i];arr2[i] = tmp;}printf("交换后:\n");printf("arr1: ");for (i = 0; i < sz; ++i){printf("%d ", arr1[i]);}printf("\narr2: ");for (i = 0; i < sz; ++i){printf("%d ", arr2[i]);}printf("\n");return 0;
}
10.3 三子棋
我们可以用已有的知识,实现一个三子棋小游戏。详细讲解戳这里
10.4 扫雷
再来实现一个扫雷小游戏。详细讲解戳这里
相关文章:
C语言数组全面解析:从初学到精通
数组 1. 前言2. 一维数组的创建和初始化3. 一维数组的使用4. 一维数组在内存中的存储5. 二维数组的创建和初始化6. 二维数组的使用7. 二维数组在内存中的存储8. 数组越界9. 数组作为函数参数10. 综合练习10.1 用函数初始化,逆置,打印整型数组10.2 交换两…...
2024-02-28(Kafka,Oozie,Flink)
1.Kafka的数据存储形式 一个主题由多个分区组成 一个分区由多个segment段组成 一个segment段由多个文件组成(log,index(稀疏索引),timeindex(根据时间做的索引)) 2.读数据的流程 …...
Window下编写的sh文件在Linux/Docker中无法使用
Window下编写的sh文件在Linux/Docker中无法使用 一、sh文件目的1.1 初始状态1.2 目的 二、过程与异常2.1 首先获取标准ubuntu20.04 - 正常2.2 启动ubuntu20.04容器 - 正常2.3 执行windows下写的preInstall文件 - 报错 三、检查和处理3.1 评估异常3.2 处理异常3.3 调整后运行测试…...
第16章-DNS
目录 1. 域名 1.1 产生背景 1.2 概述 1.3 域名的树形层次化结构 2. DNS 2.1 概述 2.2 工作机制 3. DNS查询模式 3.1 递归查询: 3.2 迭代查询: 4. 相关知识点 4.1 集中式DNS 4.2 国内通用DNS 4.3 配置DNS代理 1. 域名 1.1 产生背景 ① IP…...
Leetcoder Day27| 贪心算法part01
语言:Java/Go 理论 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。 什么时候用贪心?可以用局部最优退出全局最优,并且想不到反例到情况 贪心的一般解题步骤 将问题分解为若干个子问题找出适合的贪心策略求解每一个子…...
SpringBoot自动配置中bean的加载控制
🙈作者简介:练习时长两年半的Java up主 🙉个人主页:程序员老茶 🙊 ps:点赞👍是免费的,却可以让写博客的作者开心好久好久😎 📚系列专栏:Java全栈,…...
Linux系统运维脚本:根据菜单选择要登录到的Linux主机,方便维护多个linux服务器
目 录 一、要求 二、解决方案 (一)解决思路 (二)方案 三、脚本程序实现 (一)脚本代码和解释 1、定义hosts.txt文件 2、脚本代码 3、代码解释 (二)脚本验证 1…...
蓝桥杯练习题——二分
1.借教室 思路 1.随着订单的增加,每天可用的教室越来越少,二分查找最后一个教室没有出现负数的订单编号 2.每个订单的操作是 [s, t] 全部减去 d #include<iostream> #include<cstring> using namespace std; const int N 1e6 10; int d[…...
Java面试——Redis
优质博文:IT-BLOG-CN 一、Redis 为什么那么快 【1】完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中。 【2】数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的。 【3】采用单线…...
信号系统之复数傅立叶变换
1 实数DFT 傅里叶变换系列的所有四个成员(DFT、DTFT、傅里叶变换和傅里叶级数)都可以用实数或复数进行。由于DSP主要关心的是DFT,所以就以它为例。 可以根据以下方程定义离散傅里叶变换的实数版本: 一个 N 个样本时域信号 被分解…...
Unity - 相机画面为黑白效果
一、 在Hierarchy中创建一个Global Volume,并设置它为局部作用 二、 将场景出现的作用域范围缩小至相机所在位置,将相机包含即可。 三、添加覆盖组件Color Adjustments,并将Saturation直接拉为-100 。 此时,相机拍摄画面为黑白,场景视图中…...
哈啰Java 春招 24届
时长 1h 3. 为什么使用分布式ID,解决了什么问题 4. Leaf算法了解吗?讲一下原理和工作流程以及优缺点 5. 有没有可能导致id重复?该如何解决? 6. 项目中redis是如何运用的? 7. 项目中分布式锁是如何实现的? 8…...
《剑指 Offer》专项突破版 - 面试题 68 : 查找插入位置/ 69 : 山峰数组的顶部(C++ 实现)
目录 面试题 68 : 查找插入位置 面试题 69 : 山峰数组的顶部 面试题 68 : 查找插入位置 题目: 输入一个排序的整数数组 nums 和一个目标指 t,如果数组 nums 中包含 t,则返回 t 在数组中的下标;如果数组 nums 中不包含 t&#…...
赖迪思软件 lattice Diamond
问题1:工程编译好后,git上传,变更分支又切换回来,再次编译有时候失败,所以配置好的管脚变成默认的,生成的IP核变成名变粗(顶部文件,管脚配置显示IP核输入输出信号配置)。…...
ROS开发基础-Linux基础第四部(开发板设置本地IP)
一 、网线连接设备 使用网线连接jetson NX与机械臂,如下图所示: 二、 修改上位机IPV4 IP ①测试是否可连接。网线连接机械臂之后,在桌面打开终端输入命令“ping 192.168.1.18”,如不可正常通信,可按照下述步骤进行设置。 ②在U…...
TSINGSEE青犀AI智能分析网关V4智慧油田安全生产监管方案
一、方案背景 随着科技的不断发展,视频监控技术在油田行业中得到了广泛应用。为了提高油田生产的安全性和效率,建设一套智能视频监控平台保障安全生产显得尤为重要。本方案采用先进的视频分析技术、物联网技术、云计算技术、大数据和人工智能技术&#…...
C++基于多设计模式下的同步异步日志系统day3
C基于多设计模式下的同步&异步日志系统day3 📟作者主页:慢热的陕西人 🌴专栏链接:C基于多设计模式下的同步&异步日志系统 📣欢迎各位大佬👍点赞🔥关注🚓收藏,&am…...
Cypher语句查询neo4j数据库教程
文章目录 Cypher介绍执行Cypher语句查询总结 Cypher介绍 NodeMatcher和RelationshipMatcher能够表达的匹配条件相对简单,更加复杂的查询还是需要用Cypher语句来表达。 Py2neo本身支持执行Cypher语句的执行,可以将复杂的查询写成Cypher语句,…...
【ESP32 IDF快速入门】点亮第一个LED灯与流水灯
文章目录 前言一、有哪些工作模式?1.1 GPIO的详细介绍1.2 GPIO的内部框图输入模式输出部分 二、GPIO操作函数2.1 GPIO 汇总2.2 GPIO操作函数gpio_config配置引脚reset 引脚函数设置引脚电平选中对应引脚设置引脚的方向 2.3 点亮第一个灯 三、流水灯总结 前言 ESP32…...
再见,Visual Basic——曾经风靡一时的编程语言
2020年3月,微软团队宣布了对Visual Basic(VB)的“终审判决”:不再进行开发或增加新功能。这意味着曾经风光无限的VB正式退出了历史舞台。 VB是微软推出的首款可视化编程软件,自1991年问世以来,便受到了广大…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...
