首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >理解C中数组元素中分配的内存地址( Windows 10中的gcc)

理解C中数组元素中分配的内存地址( Windows 10中的gcc)
EN

Stack Overflow用户
提问于 2018-11-26 10:30:04
回答 2查看 79关注 0票数 2

我正试图掌握C中的指针和数组,现在,我正试图弄清楚我的C编译器是如何为二维数组中的元素分配内存的。下面是我的示例代码:

代码语言:javascript
运行
复制
#include <stdio.h>

int main(void)
{
    int ar[2][2] = { {1, 2}, {3, 4} };

    printf("sizeof(int)      = %u\n-----\n", sizeof(int));

    printf("ar               = %p\n", ar);
    printf("ar + 1           = %p\n", ar + 1);
    printf("&ar              = %p\n", &ar);
    printf("&ar + 1          = %p\n\n", &ar + 1);

    printf("sizeof(ar)       = %u\n-----\n", sizeof(ar));

    printf("ar[0]            = %p\n", ar[0]);
    printf("ar[0] + 1        = %p\n", ar[0] + 1);
    printf("&ar[0]           = %p\n", &ar[0]);
    printf("&ar[0] + 1       = %p\n\n", &ar[0] + 1);

    printf("sizeof(ar[0])    = %u\n-----\n", sizeof(ar[0]));

    printf("ar[1]            = %p\n", ar[1]);
    printf("ar[1] + 1        = %p\n", ar[1] + 1);
    printf("&ar[1]           = %p\n", &ar[1]);
    printf("&ar[1] + 1       = %p\n\n", &ar[1] + 1);

    printf("sizeof(ar[1])    = %u\n-----\n", sizeof(ar[1]));

    printf("&ar[0][0]        = %p\n", &ar[0][0]);
    printf("&ar[0][0] + 1    = %p\n", &ar[0][0] + 1);
    printf("&ar[1][0]        = %p\n", &ar[1][0]);
    printf("&ar[1][0] + 1    = %p\n\n", &ar[1][0] + 1);

    printf("sizeof(ar[0][0]) = %u\n-----\n", sizeof(ar[0][0]));

    return 0;
}

我在我的系统上得到的输出是:

代码语言:javascript
运行
复制
sizeof(int)      = 4
-----
ar               = 0061FF20
ar + 1           = 0061FF28
&ar              = 0061FF20
&ar + 1          = 0061FF30

sizeof(ar)       = 16
-----
ar[0]            = 0061FF20
ar[0] + 1        = 0061FF24
&ar[0]           = 0061FF20
&ar[0] + 1       = 0061FF28

sizeof(ar[0])    = 8
-----
ar[1]            = 0061FF28
ar[1] + 1        = 0061FF2C
&ar[1]           = 0061FF28
&ar[1] + 1       = 0061FF30

sizeof(ar[1])    = 8
-----
&ar[0][0]        = 0061FF20
&ar[0][0] + 1    = 0061FF24
&ar[1][0]        = 0061FF28
&ar[1][0] + 1    = 0061FF2C

sizeof(ar[0][0]) = 4
-----

我理解为什么ar大小为16字节;它应该能够容纳4 ints,在我的系统中这是4x4 = 16字节。我猜,这也是为什么&ar + 1&ar之间字节的差异是(十六进制)30-20= 16。

我不明白为什么ar + 1ar之间的区别只有8个字节。这意味着数组只能容纳2个intsá4字节。

我在理解ar[0]ar[1]时遇到了与您在代码中看到的相同的问题。

ar + 1&ar + 1不应该产生同样的结果吗?

EN

回答 2

Stack Overflow用户

发布于 2018-11-26 10:40:52

ar在表达式中使用时,“衰变”到指向第一个元素的指针。在这种情况下,arr + 1给出了int (*)[2]类型指针的算术。它指向大小为8字节的int [2]

“阵列衰减”规则在C17 6.3.2.1§3中指定:

除非它是sizeof of操作符的操作数,或者是一元&运算符,或者是用于初始化数组的字符串文字,否则,具有“类型数组”类型的“数组”类型的表达式被转换为带有类型‘指针到类型’的表达式,该表达式指向数组对象的初始元素,而不是lvalue。

因此,当您键入&ar时,您将从数组衰减规则中得到一个特殊的异常,不会发生衰减,但是您实际上得到了一个预期的int (*)[2][2]。因此,&ar + 1给出了16个字节。

票数 2
EN

Stack Overflow用户

发布于 2018-11-26 10:51:26

所以:

代码语言:javascript
运行
复制
sizeof(int) == 4

以下内容如下:

代码语言:javascript
运行
复制
int ar[2][2];

是一个二维数组。

我们知道,a[b]等于*(a + b)。而&*被转换为一无所有。

所以:

代码语言:javascript
运行
复制
&ar[1]

等于

代码语言:javascript
运行
复制
(ar + 1)

在这里,ar“衰变”或“将被调整”(读为:神奇地转换)为指针。指向两个int元素数组的指针,即。int (*)[2]。所以它不是int *int[2][2]指针,而是int (*)[2]。我们知道

代码语言:javascript
运行
复制
sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)

所以

代码语言:javascript
运行
复制
(ar + 1)

等于(值):

代码语言:javascript
运行
复制
(uintptr_t)ar + sizeof(*ar) * 1 == 
    (uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
    (uintptr_t)ar + sizeof(int[2]) * 1) == 
    (uintptr_t)ar + sizeof(int) * 2 * 1)

即。它将ar指针值递增为2 * sizeof(int)

我不明白的是,为什么ar +1和ar之间的区别只有8个字节。

ar + 1等于

代码语言:javascript
运行
复制
(uintptr_t)ar + sizeof(*ar) + 1

arint[2][2]*arint[2]sizeof(*ar) = sizeof(int) * 2也是。

所以ar + 1等于

代码语言:javascript
运行
复制
(uintptr_t)ar + sizeof(int) * 2 * 1

所以(ar + 1) - ar等于

代码语言:javascript
运行
复制
((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
    sizeof(int[2]) == 
    sizeof(int) * 2

ar +1和&ar +1不应该产生相同的结果吗?

对于像int array[2];这样的数组,array指针值等于&array指针值。将address-of运算符应用于数组会导致指向同一内存的数组指针,这是C的一种怪癖。通过array有一种类型的int[2][2],但是&array有类型的int(*)[2][2],即。它是指向2d数组的指针。

由于类型改变,指针算法也会发生变化。typeof(ar)衰变为typeof(int(*)[2]),因此ar + 1等于

代码语言:javascript
运行
复制
`(uintptr_t)ar + sizeof(int[2]) * 1`. 

但是因为typeof(&ar) == typeof(int(*)[2][2]) &ar + 1等于

代码语言:javascript
运行
复制
`(uintrpt_t)ar + sizeof(int[2][2]) * 1`.

因此,当增加指针时,指针值的差异,因为sizeof(int[2][2])等于sizeof(int) * 2 * 2

我认为,如果是2d数组,“第一级”是由两个元素组成的一维数组,而不是整数。因此,typeof(ar[0])是一个由两个int元素组成的数组。

您的代码有UB,因为%p修饰符应该只与void*指针一起使用。最好记住(或者至少知道你应该知道)到printf("%p", (void*)&ar[1][0] + 1);抛出你的指针。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53479169

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档