可视化多维数组如何放置在内存中的方法
Ways to visualize how multidimensional array is laid in memory?
这些都是我必须处理的类工作的一部分,当我身边总是有一个可靠的编译器来处理这些复杂的数组&指针算术对我来说,但遗憾的是事实并非如此。
就我个人而言,我想知道为了教育,事物是如何被放在电脑的记忆中的!
有没有为单曲&多维的,是什么让下面这个令人憎恶的代码如此不言自明?
如果我能找到,我将不胜感激。
//Here's where the classwork starts
//Given this declaration:
double points[3][4] = {};
//Surprisingly, these 6 lines of code contain same address!
points; //= 0012F5A4
&points; //= 0012F5A4
points[0]; //= 0012F5A4
&points[0]; //= 0012F5A4
*points; //= 0012F5A4
&points[0][0]; //= 0012F5A4
double *pd0 = points[0][1];
//-> error: incompatible type (cannot convert 'double' to 'double*' in initialization)
double *pd1 = &points[0][1];
//-> compatible type
double *pd2 = &points[5][2];
//-> compatible type (possible runtime error; points to the element out of bound)
double *pd3 = &**points;
//-> compatible type
double (*p4d0)[4] = points[0];
//-> error: incompatible type (cannot convert 'double*' to 'double (*)[4]' in initialization)
double (*p4d1)[4] = &points[0];
//-> compatible type
double (*p4d2)[4] = (double (*)[4])points[0];
//-> compatible type
double (*p4d2_1)[5] = (double (*)[5])points[0];
//-> compatible type (possible runtime error; out of bound)
double (*p4d3)[4] = (double (*)[4])&points[0][0];
//-> compatible type
double (*p4d4)[] = &points[0];
//-> error: incompatible type (cannot convert 'double (*)[4]' to 'double (*)[]' in initialization)
double (*p4d5)[3][4] = points;
//-> error: incompatible type (cannot convert 'double (*)[4]' to 'double (*)[3][4]' in initialization)
double (*p4d6)[3][4] = &points;
//-> compatible type
double (*p4d7)[][4] = &points;
//-> error: incompatible type (cannot convert 'double (*)[3][4]' to 'double (*)[][4]' in initialization)
double (*p4d8)[][] = &points;
//-> error: incompatible type (multidimensional array must have bounds for all dimensions except the first)
//End
这里有一种思考points[3][4]
数组的方法。它是一个由3行4列组成的数组。行的编号分别为0、1和2,列的编号分别是0、1、2和3。
让我们用值填充数组,以帮助可视化它
0 1 2 3
-- --
0 | 11 12 13 14 |
1 | 21 22 23 24 |
2 | 31 32 33 34 |
-- --
十二个值按以下顺序排列在存储器中。每一行连续放置在前一行之后:
11 12 13 14 21 22 23 24 31 32 33 34
尽管变量被定义为二维数组,但它在内存中的表现就像是一个由12个值组成的一维数组。
一个双字节占用8个连续字节。因此,每个数组元素的地址比前一个地址高8。因此,如果数组从地址0x0012F5A4开始,这里是所有元素的地址。
Address Value
------- -----
0012F5A4 11.0
0012F5AC 12.0
0012F5B4 13.0
0012F5BC 14.0
0012F5C4 21.0
0012F5CC 22.0
0012F5D4 23.0
0012F5DC 24.0
0012F5E4 31.0
0012F5EC 32.0
0012F5F4 33.0
0012F5FC 34.0
为了强调这些是double
值,我在上表中的每个值上都添加了".0"。在本文的剩余部分中,当提到这些值时,我将省略".0"一词。
现在让我们逐一分析每个案例。我只解释你问题中的前七种情况。
案例1
double *pd0 = points[0][1];
//-> error: incompatible type (cannot convert 'double' to 'double*' in initialization)
这里,pd0
被声明为指向双精度的指针。指针变量包含其他变量的地址。
在赋值语句的右侧,points[0][1]
包含示例数组中的双值12
。发生此错误的原因是您正试图将双值分配给指针变量。
情况2
double *pd1 = &points[0][1];
//-> compatible type
这很好,因为&
是引用运算符。它提供它前面的变量的地址。因此&points[0][1]
是存储在points[0][1]
的双值的地址。在我的示例数组中,此地址为0x0012F5AC。指针pd1
因此被分配地址0x0012F5AC。
案例3
double *pd2 = &points[5][2];
//-> compatible type (possible runtime error; points to the element out of bound)
如果编译器足够聪明,可以实现运行时数组边界检查,那么在执行语句时可能会产生异常,因为数组没有定义为具有行[5]。指针CCD_ 10将被分配远远超出12元素数组末尾的假设元素的地址。即使没有发生异常,如果使用该地址的数据,也肯定不会产生可预测的结果,并可能导致程序最终崩溃。
案例4
double *pd3 = &**points;
//-> compatible type
为了理解这一点,让我们在右手边添加一些括号,以强调运算符的应用顺序。
double *pd3 = &(*(*points));
现在从内到外工作
- 术语CCD_ 11标识整个二维阵列
- 术语
(*points)
标识阵列中第一行的地址 - 术语
(*(*points))
(或**points
)标识阵列的第一行中的第一个元素的值 - 术语
&(*(*points))
(或&**points
)标识该元素的地址
因此,我们将该单个元素的地址分配给指针变量pd3
。
案例5
double (*p4d0)[4] = points[0];
//-> error: incompatible type (cannot convert 'double*' to 'double (*)[4]' in initialization)
对于这种情况,我将参考John Bode在这篇文章中给出的答案。博德说,
当数组表达式出现在大多数上下文中时,其类型为从"T的N元素数组"隐式转换为"指向T的指针",并且其值被设置为指向数组中的第一个元素。这个此规则的例外情况是数组表达式是的操作数
sizeof
或(&
)运算符的地址,或者当数组是在声明中用作初始值设定项的字符串文字。
因此,points[0]
被隐式地从"双精度的四元数组"转换为"双精度指针"
CCD_ 21被明确声明为指向4个双精度数组的指针。出现不兼容的原因是"指向双精度的指针"与"指向4个双精度数组的指针"的类型不同。
案例6
double (*p4d1)[4] = &points[0];
//-> compatible type
与情况5一样,p4d1
是指向4个双精度数组的指针
CCD_ 23提供第0行的地址。回想一下,在John Bode的文章摘录中,他说当使用(&
)运算符的地址时,将数组表达式转换为指针的规则会出现异常。因此&points[0]
也是一个指向4个双精度数组的指针。在执行上述语句之后,p4d1
包含该地址。
案例7
double (*p4d2)[4] = (double (*)[4])points[0];
//-> compatible type
这解决了案例5的问题。它将points[0]
强制转换为与p4d2
相同的类型,从而有效地取消了对"指针到双精度"的隐式转换。
我把剩下的案子留给你处理。
内存中的布局:多维数组在内存中按行主顺序排列。
这意味着在顺序计算机内存中,它是一行接一行。。。这与初始化多维数组完全一样,例如:
int a[3][2] = { {1,2}, {2,3}, {4,5} };
关于:
points; //= 0012F5A4 // means the address of the first element
&points; //= 0012F5A4 // yields the address of the array
points[0]; //= 0012F5A4 // means: address of the first element of the first row of the array
&points[0]; //= 0012F5A4 // means: address of the first row of the array
*points; //= 0012F5A4 // yields the first row, which is an address
&points[0][0]; //= 0012F5A4 // yields adress of first element of first row.
在上文中,请记住a[2][2]
的意思是a+2*3+2
(a
加上2行的大小,再加上2个元素)。
所有其他编译器错误都不言自明。
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 在c++中为我自己的基于指针的数组分配内存的正确方法
- 使 std::vector 分配对齐内存的现代方法
- 内存效率表示最短路径的方法?
- 一种从内存中删除 UTF 字节的方法?
- 删除类成员的动态分配内存的最佳方法是什么
- 在指向现有内存地址的 hpp 文件中声明成员函数的最佳方法
- 释放 std::vector 中指针内存的最有效方法是什么?
- 有什么方法可以识别可用的内存地址吗?
- avcodec_open2方法中的 FFMPEG 内存泄漏
- 组织从内存读取的数据的最佳方法(用于调试)c++
- 识别打开的共享内存状态的方法
- 释放分配给大量矢量的内存的最有效方法是什么?
- 为大无符号整数分配内存的有效方法
- C ++中新分配的int的内存大小,有没有不同更好的方法来查看它?
- 将两位数字转换为低内存表示的最快方法
- 使用删除与智能指针释放内存以及释放内存的正确方法
- C ++中的几种分配内存方法有什么区别
- 游戏循环中的可变内存方法范围