编程语言学习(五) 三种编程语言的数组
2018-02-23 22:47
204 查看
(一) C/C++语言当中的数组:
1. 定义: <类型>变量名[元素数量]定义的同时,分配栈空间,得到内存。
在C99之后,元素数量可以是变量了,之前要求的是编译时就要确定值的常量 //我对于变长数组VLA仍然不清楚,DEVc++在调成C99情况下仍然出问题。
2. 取值 变量名[下标],所取的一个元素可以作为左值使用,左值在指针那一节会讨论,等待修改补充,下标越界编译器不会检查,但是运行时会发生数组下标越界
3. 初始化:
(1) 默认初始化:静态生存期的数组自动初始化为0,动态生存期的数组垃圾值
(2) 全部初始化:直接大括号给出所有值,可以不写元素数量
(3) 部分初始化:给出部分值并且给出数组大小,未赋值的元素自动为0
(4) 定位初始化:在大括号中,以方括号小标等于一个值的形式赋值:
int a[]={[2]=8,[6]=6}; //最后一个是a[6],可见有7个元素,不用标个数
printf("%d\n",a[6]);
printf("%d\n",sizeof(a)/sizeof(a[0])); //显示 6 7 以此获得数组大小
(4)强制初始化:数组若加上const修饰,代表其中每个元素都是常量,所以数组定义时就要初始化:
const int a[]={1,2,3,4,5,6};
4. 复制:由于数组名本身是指针常量,所以不能对其赋值,应该遍历逐个赋值,也正是因为数组名本身是指针,所以数组当做参数传入时,sizeof(a)/sizeof(a[0])不可用,应当额外传入数组长度。
5. 二维数组: 行列排列与矩阵相同,内存上也是连续存放,排列顺序与n进制递增是一致的:003-010
(1) 定义 <类型>变量名[行下标][列下标]
(2) 遍历:两层循环,对行列分别遍历
(3) 初始化:可以指明行列数后直接按一维对的方式写,比如:
int a[][3]={1,2,3,4,5,6};
printf("%d",a[1][2]);
也可以如下方法:
int a[3][5]={
{1,2,3,4,5}, //逗号不能忘记了
{6,7,8,9,10},
{11,12,13,14,15}
};
printf("%d",a[2][4]);
6. 数组作参数:C/C++当中数组名本质不仅仅是地址,也标明数组的属性,但是数组名在表达式当中进行运算时,编译器会将其转化成一个指针常量,但在两种情况下,这种包含数量信息、作为数组整体的属性会被保留:(1)sizeof(数组名):返回数组长度(所占的字节数,不是数组元素个数),而不是指向数组的指针的长度。 (2)&数组名:产生一个指向数组的指针,而不是一个指向某个指针常量的指针。C/C++当中除了取地址和sizeof运算符的情况下,会有整体的数组概念,但是做参数传递时,实际传递的只是一个内存单元的地址,导致了在传递至函数里面时,sizeof运算符失效了,所以C/C++需要额外传递数组的长度进入函数。
数组作参数分为两个情况讨论:
(1) 形参中的数组,我们可以对行列数进行规定,也可以不规定
(2) 实参当中的数组:实际上传的是地址,函数操作可能修改各个元素
例如:
void inc(int a[][3],int nRow){ //对数组的列数给出了要求 行数需额外传入
for(int i=0;i<nRow;i++){
for(int j=0;j<3;j++){
a[i][j]++;
}
}
}
int main() {
int a[][3]={1,2,3,4,5,6};
inc(a,2);
for(int i=0;i<2;i++){
for(int j=0;j<3;j++){
printf("%d ",a[i][j]); //输出2 3 4 5 6 7,可见已经改变原先元素
}
}
return 0;
}:
7. 对象数组(C++独有)
对象数组的定义和普通数组相同,初始化的实质是调用构造函数对每个元素都进行构造的过程,例如:
Location a[2]={Location(1,2),}; //另一对象元素是通过调用默认构造函数构造的
对象数组消亡时,也是对所有元素逐一调用析构函数完成的。
8. 利用动态内存分配创建数组
与java一致,需要先申请内存,但C/C++用指针变量去接收,java用引用去接收。
int a[]=new int [5]();// 这样是不可以的,因为实际上只返回了首地址
比如:
int *a = new int[5](); //带上小括号,全部初始化为0,与java相同。
cout << sizeof(a) / sizeof(a[1]) << endl; //输出1,可见sizeof(a)实质是sizeof(a[0])
delete[] a;
若希望创建多维数组,则实际上是返回T类型数组的指针 //此处强调数组
实际上返回是 int[4](*a),也就是指向具有4个元素的数组的指针
int (*a)[4]=new int[5][4]();
int (*a)[4][8]=new int [7][4][8]();
PS:java的数组和这个还是不一样的,java当中其实是一个数组当中装了n个指针,应该是 int**a=new int*[10](); 指针指向指针,C/C++是指针指向数组。
(二) Java语言当中的数组
Java当中的数组与C/C++的数组完全不同,java当中的数组完全建立在堆内存上,声明得到的数组变量实际是一个引用类型。
1. 声明一个数组:
类型[]数组名,或者 类型 数组名[],后者为C/C++风格,java程序里前者居多。
本质是声明一个数组的引用,不占用内存。
这里浅谈java当中的变量名,C/C++当中,所有变量/函数名都是地址,而JAVA当中除了基本数据类型外,其他的类型的名字本质都是引用,但是又区别于C++,java的引用实际上是可以先声明不立即赋值的。
2. 取值
取值方法与C/C++相同,但是C/C++对于数组下标越界是不会检查的,内存读写会跨过数组边界,java在编译时也是不能找出数组下标越界的,但是在运行的时候会报异常。
3. 初始化一个数组:
由于java的数组都要在堆中申请内存,所以初始化较C/C++多了一步申请内存,所以有两步:
第一步:申请内存 :
new 类型名 [数组大小]
第二步:赋初值
(1) 默认初始化:Java当中帮助完善了对于一个数组的初始化,数组对象建立起来的时候就已经全部元素分配为0了,字符串数组会自动赋值null
(2) 自己动手赋值 也可以两步合成一步,有两种方法:(1) int []a={1,2,3,4,5,6}(2) Int []a=new int[]{1,2,3,4} //构造时给出数量反而报错
4. 复制:java当中的数组名,本质是引用,带有C++的指针的性质,所以数组变量可以互相赋值,但是两个引用指向同一个数组对象,两个管理员管一个对象,会出类似于C++当中类似浅复制的问题。
5. 二维数组区别与C/C++,C++当中,数组名可以充当地址来使用,通过数组名和下标确定具体哪个元素,由于java数组名实际是一种对象的引用,因此这种管理关系是可以改变的;java当中实际上没有多维数组,二维数组的本质是数组的数组,数组元素在内存当中的排列并不连续,这个概念较C++数组为宽泛,对应有了不规则数组:(1) 实现二维数组行之间的交换(2) 实现不规则数组 public class hello { public static void main(String[] args) { int a[][]= { {1,2,3,4}, {5,6,7}, //a[0]引用{1,2,3,4,} a[1]引用{5,6,7} }; int b[]=a[1]; a[1]=a[0]; a[0]=b; System.out.println(a[1].length); //输出4 可见所引用的元素已经变化 }} 6. 数组作参数:Java当中,数组不是基本数据类型,而是引用类型(类类型),因此数组类当可以有自己的特有的数据成员,java当中数组类具有length成员,可以用数组名.length得到,因此不再需要额外传入数组的长度。 7. Java提供了数组的几个API,看着眼熟即可:int []a=new int[4];Arrays.fill(a, 55);System.out.println("填值"+Arrays.toString(a));
a77c
//填值[55, 55, 55, 55]for (int i = 0; i < a.length; i++) { a[i]=88-i; }System.out.println("赋值 "+Arrays.toString(a)); //赋值 [88, 87, 86, 85]Arrays.sort(a);System.out.println("升序排序 "+Arrays.toString(a));//升序排序 [85, 86, 87, 88]/* java当中并没有降序排序的API*/System.out.println("二分查找"+Arrays.binarySearch(a, 86)); //二分查找1int b[]=Arrays.copyOf(a, 2);System.out.println("按长度截取"+Arrays.toString(b)); //按长度截取[85, 86]int []c=Arrays.copyOfRange(a, 1, 3);System.out.println("按范围截取"+Arrays.toString(c)); //按范围截取[86, 87]
System.out.println( "比较"+Arrays.equals(a, b)); //比较false
相关文章推荐
- 编程语言学习(一) 三种编程语言概述、语言特点与IDE配置
- 编程语言学习(二) 三种编程语言的数据类型、变量常量定义
- 一个无聊男人的疯狂《数据结构与算法分析-C++描述》学习笔记 用C++/lua/python/bash的四重实现(7)习题2.8 随机数组的三种生成算法
- Java学习笔记-数组的三种初始化方式
- JAVA学习笔记-数组的三种初始化方式
- 学习笔记之js数组去重的方法三种
- 编程语言学习(六) 三种编程语言的字符串
- 一个无聊男人的疯狂《数据结构与算法分析-C++描述》学习笔记 习题2.8 随机数组的三种生成算法(补) 将bash的实现翻译成比较纯正的bash风格
- Swift编程语言学习3.1——数组
- 编程语言学习(三) 三种编程语言的基本输入输出
- java学习之旅53--数组_数组的三种初始化方式
- 今天学习了用三种不同的方法处理数组的边界
- JavaScript学习笔记-数组(1)
- 你应该学习哪门编程语言
- 最大子数组问题的三种方法:分治法、暴力法和非递归方法
- 黑马程序员_Java学习日记1_关于数组的相关应用
- JS判断一个数组中是否有重复值的三种方法
- 为什么JavaScript是你应当学习的下一个(或第一个)编程语言
- C语言学习之字符数组简析.
- 学习札记--uC/OS-II处理临界区代码的三种方法小结