首页 > 其他分享 >一维数组

一维数组

时间:2023-07-06 18:55:43浏览次数:35  
标签:p1 一维 int void 地址 数组 指针

一维数组

一维数组定义&形式

是一组数据类型相同的变量,可以存放一组数据

数组名[下标]

❗数组地址

  1. 数组在内存中的地址是连续的

  2. C++将数组名解释为数组首个元素的地址

    ⚠数组名为常量,不能更改,例如int类型数组a使用 a++❎

    1. 指针值可以改变,int *p = a使用 p++✅
  3. 数组第0个元素的地址等价于数组首个元素的地址

  4. 数组第n个元素的地址:地址首个元素的地址+n

  5. C++编译器将 数组名[下标]​ 解释为 *(数组首个地址+下标)

                        `地址[下标]`​    解释为 `*(地址+下标)`​
    

数组表示法&指针表示法

1.数组表示法

形式为 ***数组名[下标]  ​***地址形式为 ***(类型)&数组名[下标]***
int a[5]={0,4,5,8,2};
for ( int i=0 ; i < 5 ; i++ ){
	std::cout << "a[i]=" << a[i] <<  "地址为" <<  (long long)&a[i] << std::endl;  //使用long long类型是方便计算
}
//运行结果(相差4是因为int类型为4个字节)
a[i]=0地址为880790205704
a[i]=4地址为880790205708
a[i]=5地址为880790205712
a[i]=8地址为880790205716
a[i]=2地址为880790205720

2.指针表示法

使用指针来表示数组地址,定义形式为 `*指针名 = 数组地址(例如a或者a[下标])`​ 

取值形式为 *(指针名+下标)

地址形式为 指针名+下标

int a[5]={0,4,5,8,2};
int *p = a; //让指针指向数组首个元素的地址 
for ( int i=0 ; i < 5 ; i++ ){
	std::cout << "p=" << *(p+i) <<  "地址为" <<  (long long)(p+i) << std::endl;  //使用long long类型是方便计算
}
//运行结果(相差4是因为int类型为4个字节)
p=0地址为666805205224
p=4地址为666805205228
p=5地址为666805205232
p=8地址为666805205236
p=2地址为666805205240

⚛联系

C++编译器将 数组名[下标]​ 解释为 *(数组首个地址+下标)

                   `地址[下标]`​    解释为 `*(地址+下标)`​
int a[5]={0,4,5,8,2};
std::cout << a[2] << std::endl; 	// a[2]  ——>  *( a的首个元素地址 + 2 )
//输出结果为5
std::cout << &a[2] << std::endl;  
//输出结果为a[2]的地址
std::cout << (&a[2])[2] << std::endl;  // (&a[2])[2]——> *( a[2]的地址 + 2 )
//输出结果为2

//简化(指针表示法)
int *p = &a[2]
std::cout << *p << std::endl;
std::cout << p << std::endl;
std::cout << p[2] << std::endl; // p[2] ——> (&a[2])[2] ——> *( a[2]的地址 + 2 )

一维数组用于函数的参数

形式: void func (int * arr , int len);void func (int arr[] , int len);

当且仅当用于函数头函数原型中,int arr[]​和int *arr​ 才都意味着arr为一个int指针(在操作系统中,int指针为8字节)

⚠长度(int len)必须传入,除非数组中有最后一个元素的标志

int a[5]={0,4,5,8,2};
void func(int *arr){
	//std::cout << sizeof(arr) <<std::endl;				输出结果为8 (arr在函数参数中为int 指针,在操作系统中,int指针为8字节)
	//std::cout << sizeof(arr) /sizeof(int)<<std::endl;		输出结果为8/4=2
	for(int i=0 ; i<sizeof(arr) /sizeof(int); i++ ){
	std::cout << a[i] <<std::endl;
	}
}
void func(int *arr,int len){
	for(int i=0 ; i < len; i++ ){
	std::cout << a[i] <<std::endl;
	}
}
int main(){
	int a[5]={0,4,5,8,2};
	void func(a);   	//输出结果为 0  4
	void func(a,5);	//输出结果为 0  4  5  8  2
}

动态创建一维数组

栈内存很小,当有大量的数据需要存储时,应在堆上存储

语法

创建: 数据类型 *指针 = new 数据类型[数组长度]

释放: delete [] 指针

‼重点

1⃣动态创建的数组无数组名,不能用sizeof运算符(sizeof(指针)==8)

2⃣可以用数组表示法(arr[i])和指针表示法(*(arr+i))来使用动态创建的数组

3⃣释放动态分配的只能用delete [] 数组名,不能只用delete 数组名

4⃣不要用delete释放不是动态分配的内存(例如栈上内存、C语言malloc动态分配的内存)

5⃣不要用delete[]释放同一内存2次(第一次正常释放,第二次相当于释放野指针)

6⃣对空指针用delete[]是安全的(释放内存后,指针应置为nullptr,防止误操作)

7⃣如果内存不足,调用new 会发生异常,导致程序中止,如果在new关键词后面加**(std::nothrow)**,则返回nullptr,不会产生异常

int *p = new(std::nothrow) int [1000000001];
if(p==nullptr)
	std::cout << "分配内存失败" << std::endl;
else
	std::cout << "分配内存成功" << std::endl;
//运行结果
分配内存失败        //程序正常退出,保证了程序的健壮性

8⃣用delete[]释放数组时,不需要指定数组大小,因为系统会自动跟踪已分配的数组内存

数组排序qsort()函数

qsort()函数用于各种数据类型的数组进行排序

函数的原型为 **void qsort(void *base,size_t nmemb,size_t size,int (*compar)(const void ,const void ))

回调函数决定排序的顺序

int compar (const void *p1,const void *p2)

  • 如果函数的返回值<0,那么p1所指向元素会被排在p2所指向元素的前面。
  • 如果函数的返回值==0,那么p1所指向元素与p2所指向元素的位置不确定。
  • 如果函数的返回值>0,那么p1所指向元素会被排在p2所指向元素的后面。

❗其他细节

1⃣size_t是C标准库中定义的,在64位操作系统中为8字节的无符号整型(unsigned long long) ​, typedef unsigned long long size_t

2⃣形参的地址用void是为了支持所有类型,在回调函数中应具体化

//升序为例
int compasc (const void *p1, const void *p2){
	if (*((int *)p1) < *((int *)p2) )	return -1;		// (int*)p1 将p1转为int指针类型
	if (*((int *)p1) == *((int *)p2) )	return 0;		// *((int *)p1) 取p1中的值
	if (*((int *)p1) > *((int *)p2) )	return 1;
}
//简化
int compasc (const void *p1, const void *p2){
	return *((int *)p1) - *((int *)p2)
}

3⃣排序的需求除了升序和降序,还有很多不可预知的情况,只能用回调函数。

举例

#include <iostream>
//升序回调函数
int compasc(const void* p1, const void* p2) {
	return *((int*)p1) - *((int*)p2);
}
//升序回调函数
int compdesc(const void* p1, const void* p2) {
	return *((int*)p2) - *((int*)p1);
}
int main() {
	int arr[] = { 12,5,18,2,12,19,0,14,18,25,21 };
	//升序输出
	qsort(arr, sizeof(arr) / sizeof(int), sizeof(int), compasc);
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++) {
		std::cout << "arr[" << i << "]=" << arr[i] << std::endl;
	}
	std::cout << std::endl;
	//降序输出
	qsort(arr, sizeof(arr) / sizeof(int), sizeof(int), compdesc);
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++) {
		std::cout << "arr[" << i << "]=" << arr[i] << std::endl;
	}
	return 0;
}

⚠注意事项

1⃣当直接打印char类型a的地址时,std::cout​会把&a当做字符串来输出,导致乱码

解决办法:使用强制转换(void*)​明确告诉编译器&a为地址

char a;
std::cout << "a的地址为" << &a << std::endl;
//输出结果为
a的地址为烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫?蠆?
//改进方法
std::cout << "a的地址为" << (void*)&a << std::endl;
//添加(void*)明确告诉编译器&a为地址

2⃣由于数组申请内存用来存放某一类型的数据,可以通过强制类型转换来存放其他类型的数据

char a[20]; //申请20字节的内存用来存放char类型数据
int *p = (int*)a; //通过强制类型转换将上面申请的内存改存放int类型数据
for (int i = 0 ; i < 5 ; i++){
	*p = 100 + i; //赋值
}
!!!
for (int i = 0 ; i < 6 ; i++){  //报错,原因:20个字节的内存,1个int占4字节,最多能赋值5个整数
	*p = 100 + i; //赋值
}

3⃣在栈上申请内存时,注意栈溢出

大多数Linux发行版的GCC编译器,栈上内存为8M,即2^23^ 字节 = 8388608字节

Windows的Visual C++编译器,栈上内存为1M,即2^20^ 字节 = 1048576字节

在Windows栈上分配int类型的数组理论上最多有2^20^ 字节/4字节=262144个元素,但是栈上还会存储局部变量、函数参数、函数调用的上下文,所以实际上应少于262144个元素

int a[262144];
a[262143]=1;
//栈溢出

标签:p1,一维,int,void,地址,数组,指针
From: https://www.cnblogs.com/huajianyizou/p/one-dimensional-array-z1opjgu.html

相关文章

  • <数组中选取子集达到某一目标>问题总结
    这类问题主要分为两种类型:目标值明确,可以把目标值看出背包容量,数组值看做物品,转成背包问题目标值不明确,容量不知道,不能用背包,只能枚举子集的和类型一:类型二:Leetcode1555题目描述给你一个整数数组nums和一个目标值goal。你需要从nums中选出一个子序列,使子序列元素......
  • 结构体,指针函数和数组初始化
    struct_m_malloc_dev{void(*init)(uint8_t);//初始化函数uint8_t(*perused)(uint8_t);//内存使用率uint8_t*membase[SRAMBANK];//内存池管理srambank个区域的内存uint16_t*memmap[SRAMBANK];//内存管理状态表uint8_tmemrdy[SRAMBANK];//内存管理......
  • 【树状数组】 POJ 2155 Matrix
    水水的二维树状数组,代码写搓了,找了好久的错。。。#include<iostream>#include<sstream>#include<algorithm>#include<vector>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#include<cst......
  • 【树状数组】 HDOJ 3743 Frosh Week
    简单的树状数组求逆序数,不过要用到离散化。。。。刚开始没用离散化,就跪了。。#include<iostream>#include<sstream>#include<algorithm>#include<vector>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#in......
  • 数组计算阶乘
    voidfactoral(intN){intarr[5120]={};intmax=0;arr[0]=1;for(inti=0;i<N;i++){for(intj=0;j<5120;j++)arr[j]*=(i+1);for(intj=0;j<5120;j++){if(0<......
  • linux 中 数组的常见操作
     001、创建数组[root@PC1test02]#ay=(1234)##生成数组[root@PC1test02]#echo${ay[*]}##输出数组1234[root@PC1test02]#echo${#ay[*]}##输出数组的长度4 002、[root@PC1test02]#ay=("a","b","c","x&......
  • 两个数组最小的异或值之和
    1.状态压缩+动态规划顺序不重要,依次枚举数组1的每个数,和数组2进行组合计算classSolution{public:intminimumXORSum(vector<int>&nums1,vector<int>&nums2){intn=nums1.size();if(judge(nums1)||judge(nums2)){intres=0;......
  • 24届秋招专场 · 数组如何用双指针解题呢?
    你好,我是安然无虞。文章目录删除有序数组中的重复项删除排序链表中的重复元素移除元素移除零大家好,近期主要更新数组相关的解题算法咯,感兴趣的老铁可以一起看过来啦。今天更新使用双指针解决数组部分题型,注意哦,这里所说的双指针不是C语言中“指针”的概念,指的是数组的索引下标,......
  • 第3章-栈、队列和数组
    3.1栈顺序栈的基本操作#defineMaxSize10typedefstruct{ //栈的顺序存储类型Elemtypedata[MaxSize]; //静态数组存放栈中元素 inttop; //栈顶指针}SqStack;//Sq:sequence--顺序//初始化栈voidInitStack(SqStack&S){S.top=-1; //初始化栈顶指针......
  • LeetCode 周赛 352(2023/07/02)一场关于子数组的专题周赛
    本文已收录到AndroidFamily,技术和职场问题,请关注公众号[彭旭锐]和[BaguTreePro]知识星球提问。往期回顾:LeetCode单周赛第350场·滑动窗口与离散化模板题单周赛352概览T1. 最长奇偶子数组(Easy)标签:滑动窗口、枚举T2. 和等于目标值的质数对(Medium)标签:质......