C 中奇怪的数组长度行为(内存损坏?)

问题描述 投票:0回答:1

我完全意识到,当传递给函数时,数组只会衰减为指针,因此您不能使用

sizeof(x)/sizeof((x)[0])
来计算它们的大小。然而,我发现可以使用
(&x)[1]-x
,即指针算术,因此,出于好奇,我尝试创建一个函数,它接受两个数组,计算出它们的长度,然后连接它们(使用
malloc
动态分配一块内存,其大小是其长度之和乘以 int 的大小)。

这有效:

#define ARR_LEN(a) ((&(a))[1]-(a))

void join (int a[], int b[]) {
  printf("%zu %zu", ARR_LEN(a), ARR_LEN(b));
}

int main() {
    int a[3] = {0, 1, 2};
    int b[5] = {0, 1, 2, 3, 4};
    
    join(a, b);

    return 0;
}

它打印

3 5
。但是,更改
join
的主体以将
ARR_LEN(a)
存储在局部变量
n
中,即使在我们第一次打印
ARR_LEN(a)
后也是如此:

int n;
    
printf("%zu %zu", ARR_LEN(a), ARR_LEN(b));
n = ARR_LEN(a);

导致看似伪随机的结果,例如

18446708891292021383 5
。最奇怪的是,当
3 5
是全局而不是本地时,它工作正常,打印
n
。此外,打印
n
的内容会得到与第一个不同的数字。

我的猜测是,当

a
b
位于堆栈上时,将
n
放在那里会以某种方式导致 C 编译器对它们的大小感到困惑,尽管当我将
n
声明为
int __attribute__ ((aligned (256))) 时,这个问题仍然存在
尝试强制它远离其他两个(以及任何奇怪的缓存问题)。当我打印
&a
&b
&n
时,我得到类似以下内容:

0x7ffd680a8df8 0x7ffd680a8df0 0x7ffd680a8e00

而当

n
为全局时,
&n
0x404200
,因为
.data
位于堆栈下方。此外,当
n
是全局变量而我改为放置局部变量
m = ARR_LEN(b)
时,
a
会“损坏”,而
ARR_LEN(b)
会再次正确打印。

arrays c pointers stack memory-corruption
1个回答
0
投票

这有效:

不,不是。你很幸运。

int a[]
int *a
的意思完全一样。

没有办法获取传递数组的大小,并且存在“黑客技巧”。

© www.soinside.com 2019 - 2024. All rights reserved.