C/C++指针与数组(二)

news2024/11/27 23:51:45

数组与运算符*、&和[],行指针和列指针的概念
一、一维数组

#include<iostream>
int main(int argc, char *argv[])
{
	int a[5] = { 1, 2, 3, 4, 5 };

	std::cout << "a    : " << a << "\t\t&a[0]: " << &a[0] << "\t\t*a\t: " << *a << "\ta[0]: " << a[0] << std::endl;
	std::cout << "a + 1: " << a + 1 << "\t\t&a[1]: " << &a[1] << "\t\t*(a + 1): " << *(a + 1) << "\ta[1]: " << a[1] << std::endl;
	std::cout << "a + 2: " << a + 2 << "\t\t&a[2]: " << &a[2] << "\t\t*(a + 2): " << *(a + 2) << "\ta[2]: " << a[2] << std::endl;
	std::cout << "a + 3: " << a + 3 << "\t\t&a[3]: " << &a[3] << "\t\t*(a + 3): " << *(a + 3) << "\ta[3]: " << a[3] << std::endl;
	std::cout << "a + 4: " << a + 4 << "\t\t&a[4]: " << &a[4] << "\t\t*(a + 4): " << *(a + 4) << "\ta[4]: " << a[4] << std::endl;

	return 0;
}

在这里插入图片描述

在这里插入图片描述

对于一维数组typename arrayname[n],数组名arrayname指向该数组中首元素的起始地址,其类型为typename*(列指针)

经验1:arrayname+i(i<n)指向该数组的第i个元素,对arrayname+i解引用即*(arrayname+i)得到数组中第i个元素的值,即*(arrayname+i)等价于arrayname[i]。

经验2:对于一维数组来说,重载运算符[i]作用于数组名arrayname上的含义是将指向数组首元素地址的指针向后移动i位,然后解引用。

经验:3:对数组名arrayname取地址即&arrayname得到的指针将指向整个一维数组,其类型为typename(*)[](行指针)。

有趣的是:虽然有些指针指向相同的地址,但其类型却完全不同。

对于其他类型,虽然类型大小不同,但行为完全相同。

二、二维数组

#include<iostream>
int main(int argc, char *argv[])
{
	int a[2][5] = {
		{ 1, 2, 3, 4, 5 },
		{ 6, 7, 8, 9, 10 }
	};

	std::cout << "打印每个元素的指针\t对数组名解引用\t      对数组名进行重载运算符[]\t对数组名解引用\t\t对数组名进行重载运算符[]" << std::endl;
	for(int i= 0; i < 2; ++i)
		for (int j = 0; j < 5; ++j)
		{
			if (i == 0)
			{
				std::cout << "&a[" << i << "][" << j << "]: " << &a[i][j] << "\t(*a)+" << j << ": " << (*a) + j << "\ta[0]+" << j << ": " << a[0] + j << "\t*(a+" << i << ")+" << j << ": " << *(a + i) + j << "\ta[1]-" << 5 - j << ": " << a[1]  - 5 + j << std::endl;
			}
			else if (i == 1)
			{
				std::cout << "&a[" << i << "][" << j << "]: " << &a[i][j] << "\t(*a)+" << 5 + j << ": " << (*a) + 5 + j << "\ta[0]+" << 5 + j << ": " << a[0] + 5 + j << "\t*(a+1)+" << j << ": " << *(a + 1) + j << "\ta[1]+" << j << ": " << a[i] + j << std::endl;
			}
		}
	std::cout <<"以上都是列指针,其类型为int*\n\n";
	std::cout << "a指向行\t\t对a[0]取地址即&a[0]也指向行\t对a[1]取地址即&a[1]也指向行\n";
	for (int i = 0; i < 10; ++i)
	{
		std::cout << "a+" << i << ": " << a + i << "\t&(a[0])+" << i << ": " << &(a[0]) + i;
		if (i < 1)
		{
			std::cout << "\t\t&(a[1])-" << 1 << ": " << &(a[1]) - 1 << std::endl;
		}
		else
		{
			std::cout << "\t\t&(a[1])+" << i - 1 << ": " << &(a[1]) + i - 1 << std::endl;
		}
	}
	std::cout << "以上都是行指针,其类型为int(*)[5]\n\n";

	std::cout << "对数组名取地址即&a,指向整个数组\n";
	std::cout << "(&a)-1: " << (&a) - 1 << std::endl;
	std::cout << "&a    : " << &a << std::endl;
	std::cout << "(&a)+1: " << (&a) + 1 << std::endl;
	std::cout << "以上都是数组指针,其类型为int(*)[2][5]\n\n";
	return 0;
}

在这里插入图片描述

在这里插入图片描述

对于二维数组typename arrayname[i][j],数组名arrayname指向该二维数组中第一个一维数组的起始地址或者说指向该二维数组中第一个整个一维数组,其类型为typename(*)[](行指针)。
类似于经验1, 对数组名取地址,即&arrayname,指向整个二维数组,其类型为typename(*)[][](数组指针)。
对数组名解引用,即*arrayname,指向二维数组中首个元素的地址,其类型为typename*(列指针)。

arrayname+i(i<n)指向该二维数组的第i个整个一维数组(行指针),对arrayname+i解引用即*(arrayname+i)指向该二维数组的第i个一维数组的首元素即arrayname[i][0],其类型为typename*(列指针)等价于&arrayname[i][0]。

类似于经验2,对于二维数组来说,重载运算符[i]作用于数组名arrayname上的含义是将指向该二维数组中首个一维数组的指针(typename(*)[](行指针))向后移动i位,然后解引用(typename*(列指针))。

对于其他类型,虽然类型大小不同,但行为完全相同。

三、三维数组
在头文件中定义一个三维数组

//header.h
int a[3][3][3] =
	{
		{
			{ 1,2,3 },
			{ 4,5,6 },
			{ 7,8,9 }
		},
		{
			{ 10,11,12 },
			{ 13,14,15 },
			{ 16,17,18 }
		},
		{
			{ 19,20,21 },
			{ 22,23,24 },
			{ 25,26,27 }
		}
	};

首先,对数组名取地址

#include"header.h"
int main(int argc, char *argv[])
{
	std::cout << "&a: " << &a << "\t&a+1:" << &a + 1 << "\t&a即" << &a << "移动了" << (int)(&a + 1) - (int)(&a) << "个字节后到达&a+1即" << &a + 1 << std::endl;
	return 0;
}

在这里插入图片描述
输出结果表明对数组名a取地址,从&a+1移动的长度来看,它指向a[3][3][3]整个数组,类型是int(*)[][][]。这表明数组名携带了整个数组的信息。所以,&a的类型是int(*)[3][3][3]。

然后对数组名做算术运算

#include"header.h"
int main(int argc, char *argv[])
{
	std::cout << "该数组元素a[0][0][0]的地址&a[0][0][0]:" << &a[0][0][0] << "\n该数组元素a[2][0][0]的地址&a[2][0][0]:" << &a[2][0][0] << std::endl << std::endl;
	for (int i = 0; i < 3; ++i)
	{
		std::cout << "a+" << i << ":" << a + i;
		if (i > 0)
		{
			std::cout << "\ta+" << i - 1 << "即" << a + i - 1 << "移动了" << (int)(a + i) - (int)(a + i - 1) << "个字节后到达a+" << i << "即" << a + i;
		}
		std::cout << std::endl;

		std::cout << "a[" << i << "]:" << a[i];
		if (i > 0)
		{
			std::cout << "\ta[" << i - 1 << "]即" << a[i - 1] << "移动了" << (int)(a[i]) - (int)(a[i - 1]) << "个字节后到达a[" << i << "]即" << a[i];
		}
		std::cout << std::endl;

		std::cout << "&a[" << i << "]:" << &a[i];
		if (i > 0)
		{
			std::cout << "\t&a[" << i - 1 << "]即" << &a[i - 1] << "移动了" << (int)(&a[i]) - (int)(&a[i - 1]) << "个字节后到达&a[" << i << "]即" << &a[i];
		}
		std::cout << std::endl << std::endl;
	}
	return 0;
}

在这里插入图片描述

从输出结果来看,数组名a指向的是该数组中第一个元素,可是第一个元素是一个二维数组,所以a+1移动了36个字节。a[i]表示取数组a中第i个元素,a[1]取数组a中的第二个元素,可是第二个元素也是一个二维数组,所以a[1]+1也移动了36个字节。对a[1]取地址后,从&a[1]+1移动36个字节来看,&a[1]指向第二个二维数组整个数组。与数组名a不同的是,a[1]只携带了一个二维数组的信息,但是类似于数组名a,a[1]相当于数组
{
{ 10,11,12 },
{ 13,14,15 },
{ 16,17,18 }
}
的数组名,它指向这个数组中的第一个元素即一维数组{ 10,11,12 }(这个紧接着就会讨论到),对它取地址即&a[1]就指向整个数组。
综上所述,a和&a[0]具有共同的类型int(*)[3][3],而a[0]的类型是int(*)[3](这个紧接着就会讨论到)。

接着,进入第一个二维数组

#include"header.h"
int main(int argc, char *argv[])
{
	std::cout << "该数组元素a[0][0][0]即" << a[0][0][0] << "的地址&a[0][0][0]:" << &a[0][0][0]
		<< "\n该数组元素a[0][1][0]即" << a[0][1][0] << "的地址&a[0][1][0]:" << &a[0][1][0]
		<< "\n该数组元素a[0][2][0]即" << a[0][2][0] << "的地址&a[0][2][0]:" << &a[0][2][0] << std::endl << std::endl;
	for (int i = 0; i < 3; ++i)
	{
		std::cout << "a[0][" << i << "]:" << a[0][i] << "\t对a[0][" << i << "]解引用即*a[0][" << i << "]得到" << *a[0][i];
		std::cout << std::endl;

		std::cout << "a[0]+" << i << ":" << a[0] + i;
		if (i > 0)
		{
			std::cout << "\t\t\t\t\t\ta[0]+" << i - 1 << "即" << a[0] + i - 1 << "移动了" << (int)(a[0] + i) - (int)(a[0] + i - 1) << "个字节后到达a[0]+" << i << "即" << a[0] + i;
		}
		std::cout << std::endl;

		std::cout << "*(a+0)+" << i << ":" << *(a + 0) + i;
		if (i > 0)
		{
			std::cout << "\t\t\t\t\t*(a+0)+" << i - 1 << "即" << *(a + 0) + i - 1 << "移动了" << (int)(*(a + 0) + i) - (int)(*(a + 0) + i - 1) << "个字节后到达*(a+0)+" << i << "即" << *(a + 0) + i;
		}
		std::cout << std::endl << std::endl;
	}
	return 0;
}

在这里插入图片描述

注意,a[0]相当于第一个二维数组的数组名,对数组名取地址指向整个二维数组,但是它本身却指向数组内的第一个一维数组,从a[0]+1移动12个字节就可以验证这一点。
那么取a[0]这个二维数组中的第一个元素a[0][0],可是第一个元素是一个一维数组 {1,2,3 },类似地,a[0][i](0<i<3)相当于一维数组的数组名,它只携带了这个一维数组的信息,&a[0][i](0<i<3)指向整个一维数组,但是它本身指向一维数组中的第一个元素,所以对a[0][i](0<i<3)解引用即*a[0][i](0<i<3),分别取值1、4、7,得证。
既然a+0指向第一个二维数组,那么对a+0解引用即*(a+0)+0它就指向第一个二维数组中的第一个一维数组{ 1,2,3 },从*(a+0)+0移动了12个字节到*(a+0)+1可以验证这一点。
综上所述,a[0]、*a和&a[0][i](0<i<3)具有相同的类型int(*)[3],而a[0][i]的类型是int(*)。

接着进入这个三维数组中的第一个二维数组中的第一个一维数组

#include"header.h"
int main(int argc, char *argv[])
{
	std::cout << "该数组元素a[0][0][0]即" << a[0][0][0] << "的地址&a[0][0][0]:" << &a[0][0][0]
		<< "\n该数组元素a[0][0][2]即" << a[0][0][2] << "的地址&a[0][0][2]:" << &a[0][0][2] << std::endl << std::endl;

	for (int i = 0; i < 3; ++i)
	{
		std::cout << "a[0][0][" << i << "]:\t" << a[0][0][i] ;
		std::cout << std::endl;

		std::cout << "a[0][0]+" << i << ":\t" << a[0][0] + i;
		if (i > 0)
		{
			std::cout << "\ta[0][0]+" << i - 1 << "即" << a[0][0] + i - 1 << "移动了" << (int)(a[0][0] + i) - (int)(a[0][0] + i - 1) << "个字节后到达a[0][0]+" << i << "即" << a[0][0] + i;
		}
		std::cout << std::endl;

		std::cout << "*(a[0][0]+" << i << "):\t" << *(a[0][0] + i);
		std::cout << std::endl;

		std::cout << "*(*(a+0)+0)+" << i << ":\t" << *(*(a + 0) + 0) + i;
		if (i > 0)
		{
			std::cout << "\t*(*(a+0)+0)+" << i - 1 << "即" << *(*(a + 0) + 0) + i - 1 << "移动了" << (int)(*(*(a + 0) + 0) + i) - (int)(*(*(a + 0) + 0) + i - 1) << "个字节后到达*(*(a+0)+0)" << i << "即" << *(*(a + 0) + 0) + i;
		}
		std::cout << std::endl;

		std::cout << "*(*(*(a+0)+0)+" << i << "):" << *(*(*(a + 0) + 0)  + i);
		std::cout << std::endl << std::endl;
	}
}

在这里插入图片描述

a[0][0]相当于这个三维数组中的第一个二维数组中的第一个一维数组的数组名,&a[0][0]即指向这个一维数组整个数组(读者可以自行验证),但是a[0][0]却指向一维数组中的第一个元素,而这个第一个元素是一个整型数值1,对a[0][0]进行移动并且解引用即可验证它的指向。直接取值即a[0][0][0]、a[0][0][1]、a[0][0][1]分别得到1、2、3,这符合通常的取值。
既然*(a+0)+0指向第一个二维数组中的第一个一维数组的第一个元素,而这个元素是一个整型值,那么对(*(a+0)+0)进行移动并且解引用也能验证它的指向。
综上所述,&a[0][0][i](0<i<3)与(*(a+0)+0)+i(0<i<3)具有相同的类型int(*)。

四、四维数组
现在,只要对[]、*和&熟练地运用,就能很快速地解析出指针的类型与它的指向。

首先在头文件中定义一个四维数组

//header.h
int a[2][4][3][3] =
{
 {
  {
   { 1,2,3 },
   { 4,5,6 },
   { 7,8,9 }
  },
  {
   { 10,11,12 },
   { 13,14,15 },
   { 16,17,18 }
  },
  {
   { 19,20,21 },
   { 22,23,24 },
   { 25,26,27 }
  },
  {
   { 28,29,30 },
   { 31,32,33 },
   { 34,35,36 }
  }
 },


 {
  {
   { 51,52,53 },
   { 54,55,56 },
   { 57,58,59 }
  },
  {
   { 60,61,62 },
   { 63,64,65 },
   { 66,67,68 }
  },
  {
   { 69,70,71 },
   { 72,73,74 },
   { 75,76,77 }
  },
  {
   { 78,79,80 },
   { 81,82,83 },
   { 84,85,86 }
  }
 }
};

例如
*(*(*(*(a + 0) + 1) + 1) + 2),由内向外解析:(a + 0)表示指向这个四维数组的第一个三维数组,类型为int(*)[3][3][3],对它解引用后即*(a + 0)就指向三维数组中的第一个二维数组,类型为int(*)[3][3],+1表示移动“一位”,即*(a + 0) + 1指向这个三维数组中的第二个二维数组,类型为int(*)[3][3],解引用后即*(*(a + 0) + 1) 就指向这个二维数组中的第一个一维数组,类型为int(*)[3],+1表示移动“一位”,即(*(*(a + 0) + 1) + 1指向这个二维数组中的第二个一维数组,类型仍然为int(*)[3],解引用后即*(*(*(a + 0) + 1) + 1)指向这个一维数组中的第一个元素,类型为int(*),+2表示移动“两位”,即*(*(*(a + 0) + 1) + 1) + 2指向这个一维数组中的第三个元素即15。

验证:

#include"header.h"
int main(int argc, char *argv[])
{
	std::cout << *(*(*(*(a + 0) + 1) + 1) + 2) << std::endl;
	return 0;
}

在这里插入图片描述

注意数组的表示形式,再例如:
(*(*(a[1]+2)+2))[2],
a[1]指向这个四维数组中的第二个三维数组的第一个二维数组,类型为int(*)[3][3]。
a[1]+2指向这个四维数组中的第二个三维数组中的第三个二维数组,类型仍为int(*)[3][3]。
*(a[1]+2)指向这个四维数组中的第二个三维数组中的第三个二维数组的第一个一维数组,
类型为int(*)[3]。
*(a[1]+2)+2指向这个四维数组中的第二个三维数组中的第三个二维数组的第三个一维数组,
类型仍为int(*)[3]。
*(*(a[1]+2)+2)指向这个四维数组中的第二个三维数组中的第三个二维数组的第三个一维数组的第一个元素,类型为int(*)。
(*(*(a[1]+2)+2))[2]取这个四维数组中的第二个三维数组中的第三个二维数组的第三个一维数组的第三个元素的值即77。

验证:

#include"header.h"
int main(int argc, char *argv[])
{
	std::cout << (*(*(a[1] + 2) + 2))[2] << std::endl;
	return 0;
}

在这里插入图片描述
五、n维数组
对于n维数组的情形:

第一点是对数组名取地址,类型是typename(*)[]…(总共n个[])它指向这个n维数组整个数组。数组名携带了整个数组的全部信息,数组名指向这个n维数组中的第一个(n-1)维数组,(数组名+i)指向这个n维数组中的第i个(n-1)维数组。

第二点是重载运算符[],传入参数i即[i],它的含义是取n维数组中的第i个元素(不妨设这个元素是m维数组),相当于指向这个m维数组中的第一个(m-1)维数组。(数组名[i])的类型是typename(*)[]…(总共m-1个[]),(数组名[i])也可以理解成是这个n维数组中第i个(n-1)维数组的数组名,类型是typename(*)[]…(总共n-2个[])

第三点是要牢记运算符*和运算符&互为逆操作。*解引用当然是根据地址取值,&取地址当然是根据变量的值取址。

第四点是优先级与结合性,当分不清优先级时一个有用的技巧就是加小括号。

参考
《C语言程序设计》(第3版)(谭浩强,清华大学出版社)
《C++程序设计教程》(第3版)(王珊珊,臧洌,张志航,机械工业出版社)
《C++ Primer Plus》(Six Edition)(Stephen Prata)
《C和指针》(Kenneth A. Reek)
广大的CSDN社友们的文章

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

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

相关文章

day23_关键字static丶代码块丶native关键字

static关键字 static是静态的意思&#xff0c;可以用来修饰成员变量、成员方法&#xff1a; 修饰成员变量 我们称为类变量&#xff0c;或静态变量&#xff0c;&#xff08;类变量&#xff1a;属于类、加载一次&#xff0c;内存中只有一份&#xff09;可以被类的所有对象共享…

windows+Anaconda环境下安装BERT成功安装方法及问题汇总

前言 在WindowsAnaconda环境下安装BERT&#xff0c;遇到各种问题&#xff0c;几经磨难&#xff0c;最终成功。接下来&#xff0c;先介绍成功的安装方法&#xff0c;再附上遇到的问题汇总 成功的安装方法 1、创建虚拟环境 注意&#xff1a;必须加上python3.7.12以创建环境&a…

C语言运算符优先级以及记忆方式

C语言运算符优先级 C语言中运算符的优先级从高到低如下&#xff1a; 一元运算符&#xff1a;! – &#xff08;正数&#xff09;-&#xff08;负数&#xff09;& &#xff08;取地址&#xff09;*&#xff08;指针值&#xff09; 乘除模运算符&#xff1a;* / % 加减运…

2023年系统集成项目管理工程师【计算要点和常用公式】

一、常用缩写缩写含义PV计划费用AC实际费用EV挣值SV进度偏差CV成本偏差SPI进度绩效指数CPI成本绩效指数BAC完工预算EAC完工估算ETC完工尚需估算VAC完工偏差EMV预期货币价值分析EVA挣值分析EVM挣值管理CPM关键路径法二、主要公式1. 成本管理计算内容公式要点成本偏差 CVCVEV-AC&…

Spring Cloud (Consul注册、发现)

操作步骤&#xff1a; 安装Consul服务端在服务内添加客户端依赖修改配置类&#xff0c;添加注解编写yml文件一、安装Consul服务端 链接&#xff1a;https://www.consul.io/downloads.html&#xff0c;解压 开启cmd&#xff0c;进入你的Consul解压路径&#xff0c;我是在E盘 …

JVM篇之类加载机制

目录JVM篇之类加载机制类加载过程1.加载2.验证3.准备4.解析5.初始化类加载器类的加载双亲委派模型JVM篇之类加载机制 类加载过程 JVM类的加载过程分为五个部分&#xff1a;加载&#xff0c;验证&#xff0c;准备&#xff0c;解析&#xff0c;初始化&#xff0c;其中验证&#…

通用数据类型链表C语言实现

通用链表是一种动态内存分配的数据结构&#xff0c;其中每个节点包含一个指向下一个节点的指针和一个指向任意类型数据的指针。因此&#xff0c;通用链表可以容纳任意类型的数据&#xff0c;这是其与其他数据结构不同的地方。 通用链表的实现可以分为以下几个步骤&#xff1a;…

《百万在线 大型游戏服务端开发》前两章概念笔记

第1章 从角色走路说起 游戏网络通信的流程则是服务端先开启监听&#xff0c;等待客户端的连接&#xff0c;然后交互操作&#xff0c;最后断开。 套接字 每个Socket都包含网络连接中一端的信息。每个客户端需要一个Socket结构&#xff0c;服务端则需要N1个Socket结构&#xff…

直击2023云南移动生态合作伙伴大会,聚焦云南移动的“价值裂变”

作者 | 曾响铃 文 | 响铃说 2023年3月2日下午&#xff0c;云南移动生态合作伙伴大会在昆明召开。云南移动党委书记&#xff0c;总经理葛松海在大会上提到“2023年&#xff0c;云南移动将重点在‘做大平台及生态级新产品&#xff0c;做优渠道转型新动能&#xff0c;做强合作新…

利用canvas给图片添加水印

前言前两天给个人网站添加了一个小功能&#xff0c;就是在文章编辑上传图片的时候自动给图片加上水印。给网页图片添加水印是个常见的功能&#xff0c;也是互联网内容作者保护自己版权的方法之一。本文简单记录一下借助canvas在前端实现图片添加水印的实现方法。canvas元素其实…

学python的第七天---基础进阶

一、数组翻转写法一&#xff1a;myselfa[:size]a[:size][::-1]写法二&#xff1a;函数写法三&#xff1a;二、复制数组写法一:写法二&#xff1a;写法三&#xff1a;三、最小公倍数写法一&#xff1a;写法二&#xff1a;写法三&#xff1a;gcd写法四&#xff1a;其他&#xff1…

visual studio 2019创建一个项目的详细步骤

引言&#xff1a;本着边学边记录的原则&#xff0c;把学习的过程给记录下来&#xff0c;自己回顾的同时也分享给大家&#xff0c;转载请注明出处哈。 1、首先在桌面上双击打开visual studio 2019&#xff0c;看到如下界面&#xff1a; 2、点击1红框中的创建新项目&#xff0c;…

[hive]执行计划

https://www.bilibili.com/video/BV1g84y147sX/?p126&spm_id_from333.1007.top_right_bar_window_history.content.click&vd_source51f694f71c083955be7443b1d75165e0一、概述Explain呈现的执行计划&#xff0c;由一系列Stage组成&#xff0c;这一系列Stage具有依赖关…

Easy Deep Learning——全连接层

什么是全连接层?它的作用是什么? 我们还是回到之前的草地场景中,假设现在的问题变成让机器判断该草地上是不是有一只猫存在,由于之前做的卷积操作,将草地分成了许多网格,如果场地上只有一只猫,那么只有一个网格是有猫的,而其他的网格都不存在猫,一个卷积核运算可以得到…

java-泛型介绍

介绍 泛型是jdk5的时候出现的一种特性&#xff0c;可以在编译阶段约束操作的数据结构&#xff0c;并进行检查。 泛型只能用引用数据类型&#xff0c;如果是基本数据类型得使用包装类。 如ArrayList中的toArray(T[] a),是不可用转换为int[]的只能转换为Integer[] 好处 统一了…

Mysql的数据存储

Mysql的数据存储 对于mysql而言&#xff0c;数据是存储在文件系统中的&#xff0c;不同的存储存储引擎会有不同的文件格式和组织形式 1、InnoDB数据存储 InnoDB存储格式由大到小&#xff1a;表空间 → 段 → 区 → 页 → 行 对于innodb而言&#xff0c;数据是存储在表空间&…

linux系统整理一些工作中常用关于用户,用户组以及文件权限操作的相关命令

文章目录问题&#xff1a;前言&#xff1a;用户和用户组概念前言一、用户前言二、用户组一、添加用户和用户组二、查看用户所属组命令、三、管理用户组方法一、gpasswd命令方式二、newgrp命令方式三、usermod命令用户组实战&#xff1a;赋予用户root权限四、文件修改权限命令ch…

数字孪生与 UWB 技术创新融合:从单点测量到全局智能化

人员定位是指利用各种定位技术对人员在特定场所的位置进行准确定位的技术。人员定位技术主要应用于需要实时监控、管理和保障人员安全的场所&#xff0c;如大型厂区、仓库、医院、学校、商场等。人员定位技术的应用范围非常广泛&#xff0c;例如&#xff1a;-在工厂生产线上&am…

服务器Nginx安装实战

因为Vue项目发布在Tomcat中出现跨域为&#xff0c;所以需要Nginx进行反向代理&#xff0c;所以特此在云服务器中安装Nginx&#xff0c;本文章记录安装过程及解决安装过程中的错误处理。 一、Nginx 安装 登录服务器后&#xff0c;执行命令 yum info gcc-c pcre pcre-devel zl…

keras lstm

keras lstm的参数&#xff08;1&#xff09;units&#xff1a;LSTM层的单元个数&#xff0c;即LSTM网络中隐藏节点的数量。&#xff08;2&#xff09;activation&#xff1a;激活函数&#xff0c;用于更新内部状态的函数&#xff08;即门的决策函数&#xff09;。&#xff08;3…