在堆和栈上分配的数组的内存地址

如何解决在堆和栈上分配的数组的内存地址

我刚刚完成了大学的С语言课程。有人告诉我变量是如何存储在 pc 内存中的,并且数组 是如何连续存储的。 这可以在以下示例中看到:

#include <stdio.h>
void main(){
 char a[3][6];
 printf("[0][0]->%p \t[1][0]->%p\t [0][5] %p \n",&a[0][0],&a[1][0],&a[0][5]);
 printf("%p %p",a,&a[0][0]);
}

输出如下:

[0][0]->0061FF06        [1][0]->0061FF0C         [0][5] 0061FF0B
0061FF06 0061FF06

而且! a地址将与 a[0][0] 的地址相同。 而 sizeof(a) 是 18(在这个例子中)。 但是...当涉及到动态数组时...在这里,您自己看看。

#include <stdio.h>
#include <stdlib.h>
void main()
{
    char **a = (char **)malloc(3 * sizeof(char*));
    for(int i=0; i < 3; i++)
        a[i] = (char *)malloc(6 * sizeof(char));

    printf("[0][0]:%p [1][0]%p [0][5]%p\n",&a[0][5]);
    printf("a:%p [0][0]: %p\n",&a[0][0]);
    printf("[1][0] - [0][5] = %d \n",&a[1][0] - &a[0][5]);
    printf("%d",sizeof(a) );
}

结果如下:

[0][0]:00AD1588 [1][0]00AD1598 [0][5]00AD158D
a: 00AD15D8 [0][0]: 00AD1588
[1][0] - [0][5] = 11
4
  1. 为什么在动态 [1][0] - [0][5] 中不等于 1(如在静态数组中)?
  2. 为什么在动态 sizeof(a) 中是 4 ?
  3. 为什么a&a[0][0]的动态地址中没有决定?

解决方法

在您的第一个示例中,a 是一个具有 3 个元素的一维数组,其中每个元素都是一个 char[6] 数组。由于给定数组的元素在内存中是连续的,因此整个数组是连续的:

-------------------------------------------------------------------------------------
| ------------------------- | ------------------------- | ------------------------- |
| | 0 | 1 | 2 | 3 | 4 | 5 | | | 0 | 1 | 2 | 3 | 4 | 5 | | | 0 | 1 | 2 | 3 | 4 | 5 | |
| ------------------------- | ------------------------- | ------------------------- |
-------------------------------------------------------------------------------------
             a[0]                        a[1]                        a[2]

但是,在您的第二个示例中,a一个指针,指向具有 3 个元素的一维数组,其中每个元素是一个指针,指向一个位于内存中其他位置的单独 char[6] 数组,无论 malloc() 决定将它们分配到何处:

                                 -------------------------
                                 | 0 | 1 | 2 | 3 | 4 | 5 |
-------------------------        -------------------------
| 0 | 1 | 2 | 3 | 4 | 5 |        ^
-------------------------        a[1]
^                                |
a[0]              ----------------
|                 |
|                 |     -------------------------
|                 |     | 0 | 1 | 2 | 3 | 4 | 5 |
|                 |     -------------------------
|                 |     ^
|__________       |     a[2]
           |      |     |
         -------------------
         |  0  |  1  |  2  |
         -------------------
         ^
         a
,

您声明了一个名为 a

的指针
char **a = (char **)malloc(3 * sizeof(char*));

在您的系统中,与 sizeof( char ** ) 相同的 sizeof( a ) 等于 4。

即指针的大小与动态分配的数组的大小没有任何共同之处。它只存储为数组分配的extent的地址。

至于其他问题,您没有分配二维数组。您分别分配了四个数组。一个数组具有 char * 类型的元素,并且该数组的每个元素都指向一个单独分配的具有 char 类型元素的数组。

例如这个问题的答案

为什么在 a 和 &a[0][0] 的动态地址中没有确定

如下。

变量 a 有一个地址。它与元素类型为 char * 的动态分配的一维数组没有任何共同之处,只是变量 a 存储了已分配数组的地址。

顺便说一下,这与动态内存分配没有什么共同之处。

考虑以下演示程序。

#include <stdio.h>

int main(void) 
{
    char a[3][6];
    char ( *p )[6] = a;
    
    printf( "a = %p\n",( void * )a );
    printf( "p = %p\n",( void * )p );
    printf( "&p = %p\n",( void * )&p );

    return 0;
}

它的输出可能看起来像

a = 0x7ffc08157b50
p = 0x7ffc08157b50
&p = 0x7ffc08157b48

如您所见,变量p (&p) 的地址与数组占用的extent 地址不同,因为变量p 是一个单独的变量,占用其自己的内存范围。

对于数组,表达式中使用的数组指示符被隐式转换为指向其第一个元素的指针。

如果你确实会分配一个二维数组,你可以获得预期的结果(除了相对于 sizeof 运算符的结果)

char ( *a )[6] = malloc( sizeof( char[3][6] ) );
,

如果您了解数组与指向数组的指针在内存中的表示方式,将会有所帮助。

// This can be on the heap or on the stack,the representation is the same:
char a[3][6];

如果 a 在 0x1000 处,则它看起来像这样:

  • char[6] 的每个子数组都分组在方括号中:[00 00 00 00 00 00],并且所有子数组都具有相同的值,如下所示:
    • a[0][0..n] = 0x00
    • a[1][0..n] = 0x11
    • a[2][0..n] = 0x22
           0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
------------------------------------------------------------------------
0x1000   [00  00  00  00  00  00][11  11  11  11  11  11][22  22  22  22     
0x1010    22  22] 00  00  00  00  00  00  00  00  00  00  00  00  00  00
0x1020    00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00

您可以看到从 0x10000x1011 的 18 个连续元素。


现在这个:

char **a = (char **)malloc(3 * sizeof(char*));
for(int i=0; i < 3; i++) {
    a[i] = (char *)malloc(6 * sizeof(char));
}

...看起来像这样:

  • 假设是 32 位大端指针(为了清楚起见是大端,实际上 x86 是小端)。
  • a 存在于 0x1000
    • a[0] 指向 0x1030
    • a[1] 指向 0x1040
    • a[2] 指向 0x1050
  • 每个子数组元素都具有相同的值,如上,并用方括号表示:
    • a[0][0..n] = 0x00
    • a[1][0..n] = 0x11
    • a[2][0..n] = 0x22
           0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
------------------------------------------------------------------------
0x1000   [00  00  10  30][00  00  10  40][00  00  10  50] 00  00  00  00 
0x1010    00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
0x1020    00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
0x1030   [00  00  00  00  00  00] 00  00  00  00  00  00  00  00  00  00
0x1040   [11  11  11  11  11  11] 00  00  00  00  00  00  00  00  00  00
0x1050   [22  22  22  22  22  22] 00  00  00  00  00  00  00  00  00  00

现在您看到 a(本身)的分配大小为 12 个字节,整个二维数组结构在内存中不再连续 - 这就是为什么您的指针减法结果毫无意义。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?