数组的总结————超详细

目录

数组简介

数组数据结构特点

数组特点

数组存储结构

数组指针

数组在函数中的传递形式

函数返回数组指针

数组指针和指针数组

函数返回数组指针

前言:数组操作比较简单而作为及其常用的一种数据结构,除了初始化和销毁外,只可以进行存取和修改的操作,特此总结一下。


数组简介

数组数据结构特点

数组特点

1、数组内元素有一个共同类型

2、数组下标限定后则其维度和维界无法改变

3、数组操作简单,除创建和销毁外,数组只有存取和修改元素的操作。

4、数组所有元素占用内存中的连续空间

数组存储结构

数组占用连续空间,则一维数组相当于一个顺序存储的线性表,例如int arr[5],含有5个int类型的一维数组

对于一个二维数组,可以看成一维数组的一维数组,例如 int arr[2][3],包括两行三列,可以看成一个2个单元的数组,每个单元是一个3个int的数组。


数组指针

对于一维数组而言 folat p[5];   则p为首地址即&p[0],p+1为&p[1] 但p=p+1 ; p++;这样的操作算错误,首地址一旦确定,无法赋值修改。

 对于二维数组指针,则相对复杂一些。例如我们定义一个int a[2][3]的一个数组。

 我们定义一维数组时int p[3],我们把p看作a[2],就方便理解了,因此a[0],a[1]就指向a[0][0],a[1][0]的首地址,继续套娃,a就是指向a[0]的地址,a+1指向a[1]首地址,因此它一加1就直接加载了一行所以行地址:a+i

而对于a[0],a[1]看待指针是按照列移动,因此列地址:*(a+i)=a[i] (对于*(a+i)是对行地址解引用),然后举一个代码例子

#include<iostream>
using namespace std;
int main()
{
	int pt[2][3] = { 1,2,3,10,20,30 };

    //普通方式取出元素和地址
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{

			cout << pt[i][j] << "\t" << &pt[i][j] << "\t";
		}
		cout << endl;
	}
	//行地址取出元素
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << *(pt[i] + j) << "\t" << pt[i]+j << "\t";		
				//*(*(a + i) + j)
		}
		cout << endl;
	}

	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << *(*(pt + i) + j) << "\t" << *(pt + i) + j << "\t";
		}
		cout << endl;
	}
	return 0;
}

运行结果:


数组在函数中的传递形式

举一个例子,数组作为形参传递,第一个输出12,第二个输出4,第三个4,原因是再传数组时,传递的其实时数组的首地址,指针的大小为4,因此数组作为形参本质上传递的是地址

#include<iostream>
using namespace std;
void ShowSize(int a[3])
{
	cout << sizeof(a) << endl;
}
void ShowSize1(int* a)
{
	cout << sizeof(a) << endl;
}
int main()
{
	int pt[3] = { 1,2,3 };
	cout << sizeof(pt) << endl;//12
	ShowSize(pt);//4
	ShowSize1(pt);//4
	return 0;
}


函数返回数组指针

数组指针和指针数组

数组指针:指向数组的指针,(*p)[n]

指针数组:指针构成的一个数组,*p[n]

需要明确一个优先级顺序:()>[]>*,所以:

(*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n,这是“数组的指针”,即数组指针;

*p[n]:根据优先级,先看[],则p是一个数组,再结合*,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组。

 数组指针代码案例:

#include<iostream>
using namespace std;

//一维数组指针测试
void test01()
{
	//一个一维数组
	int a[5] = { 1,2,3,4,5 };

	//数组指针
	int(*p)[5];
	p= &a;//赋值a的地址,*p=a
	
	cout <<"a:" <<a << endl;//输出首元素地址
	cout << "p:" << p << endl;//p表示数组地址,输出首元素地址
	cout << "*p:" << *p << endl;//解引用为a
	cout << "&a[0]:" << &a[0] << endl;//&a[0]地址
	cout << "p[0]:" << p[0] << endl;//数组首元素地址
	cout << "&a[1]:" << &a[1] << endl;//a[1]地址
	cout << "p[1]:" << p[1] << endl; //p[1]地址并不和&a[1]相等
	cout << sizeof(p) << endl;//p指针 4
	cout<<sizeof(*p) << endl;//*p=a 20
	cout << sizeof(p[1]) << endl;//20
	//输出函数内容
	for (int i = 0; i < 5; i++)
	{
		cout << (*p)[i] << " ";
        //cout << *(*p + i) << endl; 两种一样可以输出 把*p看成a
	}
}
void test02()
{
	//指针数组,一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2],所以要分别赋值
	int (*pp)[3]; 
	int c[2][3] = { 1,2,3,4,5,6 };
	pp = &c[0];

	//将二维数组赋给指针数组
	int* p[3]; //一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2],所以要分别赋值
	int m[3][4];
	for (int i = 0; i < 3; i++)
		p[i] = m[i];//m[i]行地址储存3个变量
}
int main()
{
	    test01();
		test02();

		return 0;
}

指针数组案例:

void test03()
{
	int a = 1, b = 2;
	int*p[2];
	p[0] = &a;
	p[1] = &b;

	cout << a << "\t"<< & a << endl;//a  a地址
	cout << *p[0] << "\t" << p[0] << endl;//a  a地址

	cout << b << "\t"<<&b<<endl;//b b地址
	cout << *p[1] << "\t" << p[1] << endl; //b b地址

	cout << p << endl;//与a不相等
}

函数返回数组指针

想清楚上面细节后,接下来函数返回数组指针

1、可以给数组起别名,后声明函数。

方式a:typedef int arr[5];

方式b:using arr=int [5];

2、可以定义为 类型说明符 (*函数名(参数表))[数组维度]

3、C++11标准中 可以  auto 函数(参数表)->(*)[数组维度] 

 decltype关键字可以返回声明对象的类型,因此比较方便

 //例如构建一个float[5]类型的数组指针函数为Func,方式1

typedef float arr[5];
//或者using arr=float[5]

arr* Func(int x)

{
float a[5]={1,2,3,4,5}
return &a;
}

方式2,

1、Func为函数,需要一个int x作为参数,

2、(*Func(int x))表示对函数结果进行取地址

3、(*Func(int x))[5]表示返回一个大小为5的数组

4、int放在最前面,限定返回数组的类型

int(*Func(int x))[5]
{
	int a[5] = {1,2,3,4,5};
    return &a;
}

方式3,尾置返回类型

auto Func(int x)->int(*)[5]
{
	int a[5] = {1,2,3,4,5};
    return &a;
}

方式4,decltype

int a[] = { 0,1,2,3,4 };
int b[] = { 5,6,7,8,9 };
decltype(a)* Func(int x)
{
	return (x % 2) ? &a : &b;

}

返回后输出数组

#include<iostream>
using namespace std;
auto Func(int x)->int(*)[5]
{
	static int a[5] = {1,2,3,4,5};
	return &a;
}
int main()
{
	int(*p)[5] ;
	//首地址
	p = Func(2);

	for (int i = 0; i < 5; i++)
	{
		cout <<"地址为:"<< * p + i<<" 值为:"<<*(*p+i) << endl;
	}
	return 0;
}

把数组设置为静态变量后就不会因为局部变量的原因无法返回,如果没有static,那么数组a在函数返回a就不存在,生命期结束,每个内存单元永远都在,只不过数据不再受保护,将无法输出,输出结果

 但加入static后

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值