- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我的问题真的很简单(这并不意味着答案会很简单..:D)
为什么 C++ 中的数组将大小作为类型的一部分,而 Java 中却没有?
我知道 Java 数组引用变量只是指向堆上数组的指针,但 C++ 指向数组的指针也是如此,但即使那样我也需要提供一个大小。先分析一下C++:
// in C++ :
// an array on the stack:
int array[*constexpr*];
// a bidimensional array on the stack:
int m_array[*constexpr1*][*constexpr2*];
// a multidimensional array on the stack:
int mm_array[*constexpr1*][*constexpr2*][*constexpr3*];
// a dynamic "array" on the heap:
int *array = new int[n];
// a dynamic bidimensional "array" on the heap:
int (*m_array)[*constexpr*] = new int[n][*constexpr*];
// a dynamic multidimensional "array" on the heap:
int (*mm_array)[*constexpr*][*constexpr*] = new int [n][*constexpr1*][*constexpr2*];
n 不必是编译时常量表达式,所有元素都默认初始化。动态分配的“数组”不是数组类型,但新表达式产生指向第一个元素的指针。
所以当我创建一个动态数组时,除了第一个维度之外的所有维度都必须是常量表达式(否则我无法声明指针来保存它们的元素)。对不对??
现在转到 Java。我只能在堆上分配数组,因为这是 Java 的工作方式:
// a dynamic array on the heap:
int[] array = new int[n];
// a dynamic bidimensional array on the heap:
int[][] m_array = new int[n][];
// a dynamic multidimensional array on the heap:
int[][][] mm_array = new int [n][][];
在Java中,定义数组引用变量时似乎并不关心数组大小(在Java中显式提供大小是错误的),所以我只需要在创建时提供第一个维度的大小阵列。这允许我创建锯齿状数组,我不确定我是否可以在 C++ 中创建它(不是指针数组)。
谁能给我解释一下这是怎么回事?也许幕后发生的事情应该清楚。谢谢。
最佳答案
那是因为在 Java 中,所有数组都是一维的。 Java 中的二维数组仅仅是对一维数组的引用的数组。 Java 中的三维数组只是对数组的引用的一维数组,对数组的引用是对您想要的任何基本类型的数组的引用。
或者在 C++ 中,Java 中的数组,如果它不是原始数组,它就是“指针数组”。
例如,这段代码:
int[][][] arr3D = new int [5][][];
System.out.println(Arrays.deepToString(arr3D));
将产生输出:
[null, null, null, null, null]
You can decide to initialize one of its elements:
arr3D[2] = new int[3][];
来自同一个 println
的输出现在是:
[null, null, [null, null, null], null, null]
Still no ints here... Now we can add:
arr3D[2][2] = new int[7];
现在的结果是:
[null, null, [null, null, [0, 0, 0, 0, 0, 0, 0]], null, null]
So, you can see that this is an "array of pointers".
In C++, when you allocate a multi-dimensional array the way you described, you are allocating a contiguous array which actually holds all the dimensions of the array and is initialized all the way through to the ints. To be able to know whether it's a 10x10x10 array or a 100x10 array, you have to mention the sizes.
Further explanation
In C++, the declaration
int (*mm_array)[5][3];
表示“mm_array 是一个指向 5x3 整数数组的指针”。当您向它分配某些内容时,您希望该内容是指向连续内存块的指针,该内存块至少大到足以包含 15 个整数,或者可能是多个此类 5x3 数组的数组。
假设您没有提到“5”和“3”。
int (*mm_array)[][]; // This is not a legal declaration in C++
现在,假设你得到了一个指向新分配的数组的指针,我们有如下语句:
mm_array[1][1][1] = 2;
或者
mm_array++;
为了知道把数字放在哪里,它需要知道数组的索引 1 在哪里。元素 0 很简单 - 它就在指针处。但是元素 1 在哪里?之后应该是 15 个整数。但是在编译时,你不会知道,因为你没有给出大小。 ++
也是如此。如果它不知道数组的每个元素都是 15 个整数,它如何跳过那么多字节?
再者,什么时候是3x5或者5x3的数组呢?如果它需要转到元素 mm_array[0][2][1]
,它需要跳过两行五个元素,还是两行三个元素?
这就是为什么它需要在编译时知道其基本数组的大小。由于指针中没有关于大小的信息,而只是指向一个连续的整数 block ,因此需要提前知道该信息。
在 Java 中,情况有所不同。数组本身及其子数组都是 Java 对象。每个数组都是一维的。当你有这样的表达时
arr3D[0][1][2]
arr3D
已知是对数组的引用。该数组具有长度和类型信息,以及一维引用。它可以检查 0
是否为有效索引,并取消引用第 0
元素,该元素本身是对数组的引用。
这意味着现在它再次具有类型和长度信息,然后是引用的单一维度。它可以检查 1
是否是该数组中的有效索引。如果是,它可以转到该元素,取消引用它,并获取最里面的数组。
由于数组不是连续的 block ,而是对对象的引用,因此您不需要在编译时知道大小。一切都是动态分配的,只有第三层(在本例中)有实际连续的整数——只有一个维度,不需要预先计算。
关于java - C++ 和 Java 数组声明/定义 : differences,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32767077/
我在覆盖 ReSwift Pod 中的函数时遇到问题。我有以下模拟类(class): import Foundation import Quick import Nimble import RxSwi
我有一个类似于下面的继承结构。我正在采用 Printable 协议(protocol)并努力覆盖 description 属性。我遇到了一个谷歌此时似乎不知道的奇怪错误,提示为第三类,并引用了第二类和
我有一个类“Cat”和 Cat 类的一个子类“DerivedCat”。 Cat 有一个函数 meow(),而 DerivedCat 覆盖了这个函数。 在应用程序中,我声明了一个 Cat 对象: Cat
Kotlin 变量 变量是用于存储数据值的容器。 要创建一个变量,使用 var 或 val,然后使用等号(=)给它赋值: 语法 var 变量名 = 值 val 变量名 = 值 示例 va
C 中的所有标识符在使用前都需要声明,但我找不到它在 C99 标准中表示的位置。 我觉得也是指宏定义,不过定义的只是宏展开顺序。 最佳答案 C99:TC3 6.5.1 §2,脚注 79 明确指出: T
今天我的博客提要显示错误: This page contains the following errors: error on line 2 at column 6: XML declaration
在编写 IIF 语句、表和下面给出的语句时出现错误。 陈述: SELECT IIF(EMP_ID=1,'True','False') from Employee; table : CREATE TAB
我正在创建一个登录 Activity ,我希望它在按下登录按钮时显示进度对话框,我声明、初始化并调用了它,但它没有显示。但是当我在创建时调用进度对话框时,它出现了 这是我的代码: public cla
当我输入声明语句时: Vector distance_vector = new Vector(); 我收到错误(在两种情况下都在“双”下划线): Syntax error on token "doub
我正在本地部署在docker-for-desktop中。这样我将来可以迁移到kubernetes集群。 但是我面临一个问题。使用永久卷时,docker容器/ pod中的目录将被覆盖。 我正在拉最新的S
我有一个 MyObject 类型的对象 obj,我声明了它的实例。 MyObject obj; 但是,我没有初始化它。 MyObject 的类看起来像: public class MyObject {
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 9 年前。 Improv
这个问题已经有答案了: Android: Issue during Arraylist declaration (1 个回答) 已关闭 9 年前。 有时我会看到 ArrayList 声明如下 Arra
我对java比较陌生,经过大量搜索,我无法将相关问题的任何解决方案与我的解决方案配对。我正在尝试实现一种非常简单的方法来写入/读取数组,但编译器无法识别它。 “键盘”也是一个“无法识别的变量”。这是数
简短:何时分配内存 - 在声明或初始化时? 长整型:int x;将占用与int z = 10;相同的内存。 此外,这对于包含更多数据的自定义对象将如何工作。假设我有这个对象: public class
我需要使用此程序更好地理解函数定义、声明和正确调用。我真的需要了解如何使用它们。您能否向我展示编写此程序的正确方法(所有三个都正确并进行解释)? #include #include quad_eq
这是我的主要功能以及我要传递的内容。 int main(void){ struct can elC[7]; // Create an array of stucts Initiali
我想知道是否有更好的方法来完成此任务; 我有一个对象 - 其中一个属性是字典。我有一组逗号分隔值。我需要过滤 Dictionary 并仅获取 Dictionary 值至少与其中一个值匹配的那些元素 这
下面的using-declarations有什么意义 using eoPop::size; using eoPop::operator[]; using eoPop::back; using eoPo
我的问题更像是一个关于 for 循环样式的好奇问题。在阅读别人的一些旧代码时,我遇到了一种我以前从未见过的风格。 var declaredEarlier = Array for(var i=0, le
我是一名优秀的程序员,十分优秀!