通过在C中分配整数数组来了解此行为

时间:2017-07-19 22:58:25

标签: c arrays pointers

我知道我应该使用realloc来生成一个数组,但是在一瞬间的想法中,我就这样做了。我意识到这种方法是错误的,因为我在不分配数组的情况下通过增加它来破坏堆。所以我基本上写垃圾。但是当代码很小而没有其他事情发生时,我不明白为什么这不应该起作用。我为前几个值得到垃圾

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int **p = NULL;
    int i=0;
    int size = 5;
    int *n = NULL;

    p = malloc(sizeof(int*));

    printf("p = %p \n", p);

    for( i=0; i < size; i++ )
    {
        int *k;
        k = malloc(sizeof(int));
        *k = i;
        p[i] = k;
        printf("%p, %p, val = %d \n", k, p[i], *k);
    }

    printf("Now print the array -- \n");
    for( i=0; i < size; i++ )
    {
        int *k;
        k = p[i];
        printf("value at mem %p == %d \n", p[i], *k);
    }

    printf("now print the next values in p \n");
    for( i=0; i < size; i++ )
    {
        printf("value at %p = %p \n", p+i, *(p+i) );
    }

    return 0;
}

以下是代码的输出 -

p = 0x7f8ffbc031c0
0x7f8ffbc031d0, 0x7f8ffbc031d0, val = 0
0x7f8ffbc031e0, 0x7f8ffbc031e0, val = 1
0x7f8ffbc031f0, 0x7f8ffbc031f0, val = 2
0x7f8ffbc03200, 0x7f8ffbc03200, val = 3
0x7f8ffbc03210, 0x7f8ffbc03210, val = 4
Now print the array --
value at mem 0x7f8ffbc031d0 == -71290384
value at mem 0x7f8ffbc031e0 == -71290352
value at mem 0x7f8ffbc031f0 == 2
value at mem 0x7f8ffbc03200 == 3
value at mem 0x7f8ffbc03210 == 4
now print the next values in p
value at 0x7f8ffbc031c0 = 0x7f8ffbc031d0
value at 0x7f8ffbc031c8 = 0x7f8ffbc031e0
value at 0x7f8ffbc031d0 = 0x7f8ffbc031f0
value at 0x7f8ffbc031d8 = 0x7f8ffbc03200
value at 0x7f8ffbc031e0 = 0x7f8ffbc03210

我无法解释为什么前两个值都是垃圾,即使p和p + 1指向的内存地址是我放在那里的。

3 个答案:

答案 0 :(得分:1)

声明

p = malloc(sizeof(int*));

仅将单个元素分配给p; p[1]p[4]不存在(或者更恰当地说,您不拥有与这些元素相对应的内存)。要分配size - int *元素数组,该行必须为

p = malloc( size * sizeof *p ); // sizeof *p == sizeof (int *)

另外,

int *k;
k = malloc(sizeof(int));
*k = i;
p[i] = k;

可以简单地写成

p[i] = malloc( sizeof *p[i] ); // sizeof *p[i] == sizeof (int)
if ( p[i] ) // **always** check the result of a malloc, calloc, or realloc call!
  *p[i] = i;

答案 1 :(得分:0)

你的代码错了。您将p声明为指针的单个指针,但随后将其用作size项的数组。为此,您必须分配所需大小的数组。您当前的p = malloc(sizeof(int*))只分配一个指针,正确的代码为p = (int**)malloc(size * sizeof(int*))

我在Visual Studio中测试了你的代码,我在p [0]和p [1]中看不到任何垃圾。我假设它基于您的编译器和/或操作系统如何组织堆。由于您未在问题中指定它们,因此很难发表评论。

因此,您不会将p[1]的内存分配给p[4]。但是你在那里写价值。那么你认为这些价值实际上去了哪里?这些值写入RAM,但它不是p []数组拥有的内存。这两个奇怪的数字-71290384和-71290352实际上是您写给p[2]p[4]的值。 (它分别是ff8ffbc031f0十六进制和ff8ffbc03210十六进制,高位设置但不相关。)这是因为当您写入p[2]时,实际上写入为其他本地k分配的内存。此行为取决于具体的堆组织,因此它在其他操作系统和/或编译器上有所不同。

此外,虽然p [2]和p [4]被意外写入分配给其他变量的内存中,但似乎通过写入未分配的p [1]和p [3]来破坏堆。

答案 2 :(得分:0)

该程序具有未定义的行为。不过我可以解释这个程序运行的结果。

通常当内存分配请求小于段落的大小(通常等于16个字节)时,函数malloc会分配一个与段落大小完全相等的内存块。

在此声明之后

p = malloc(sizeof(int*));

在地址

分配了16个字节
p = 0x7f8ffbc031c0

因此你可以使用地址

0x7f8ffbc031c00x7f8ffbc031c8属于已分配的范围。

语句

在循环中分配的第一个和第二个块
k = malloc(sizeof(int));

0x7f8ffbc031d0
0x7f8ffbc031e0

由于语句

而在同一循环中
    p[i] = k;

存在超出指针p指向的分配范围的内存。

所以你必须按顺序使用表达式p[i]

0x7f8ffbc031c0   - p[0] 
0x7f8ffbc031c8   - p[1]
0x7f8ffbc031d0   - p[2]  - Oops! the address 0x7f8ffbc031d0 is overwritten
0x7f8ffbc031d8   - p[3]  
0x7f8ffbc031e0   - p[4]  - Oops! the address 0x7f8ffbc031e0 is overwritten!

因此,存储前两个整数的前两个地址将被覆盖。