【问题标题】:C pointers (arrays) memory allocation (hexadecimal)C 指针(数组)内存分配(十六进制)
【发布时间】:2015-05-25 03:55:57
【问题描述】:

我在玩 C 中的内存寻址,遇到了一个我无法完全解释的情况。

编辑:代码由 c++ 编译器编译。 (g++)

#include <cstdlib>
#include <cstdio>
int main()
{

    int* array[10]; //array of pointers to integers

    for(int i = 0; i < 10; i++)
        {
            array[i] = (int*)malloc(sizeof(int));
            *(array[i]) = i;
        }


    printf("\n");
    for(int i = 0; i < 10; i++)
       {
            printf("%d:%p\n", *(array[i]), array[i]);
       }
    printf("\n");




    int arr[10]; //array of integers

    int* start = arr; //pointer to the first element (array decay)
    for(int i = 0; i < 10; i++)
        arr[i] = i;

    printf("\n");
    for(int i = 0; i < 10; i++)
    {
        printf("%d:%p\n", *(start + i), start + i);
   }
   printf("\n");

 return 0;
 }

一切都可以编译并且可以工作,但是我得到了奇怪的内存地址。 对于第一个数组,我得到类似:

0:0x23e4010
1:0x23e4030 (32 bits between the addresses which is correct)

但是对于我得到的第二个数组:

0:0x7ffdaf876290
1:0x7ffdaf876294 (only 4 bits? or maybe they are bytes - but why the long addresses???)

有人能解释一下吗? (还有一个函数可以毫不费力地将十六进制转换为十进制吗?)

【问题讨论】:

  • 不清楚为什么你会期待你所期待的。因此很难解释它,因为对我们来说它并不像你那样“奇怪”。无论如何,我已经尝试回答了。
  • 顺便说一句,请修正你的问题的标题:它一点也不突出。
  • 另外,那些%p 打印内存地址,它们是字节而不是位。所以前两个相隔 32 个字节,后两个相隔 4 个字节。
  • Patrick Roberts 您的评论很有道理。但我以 32 字节的差异得到所有这些(也许这就是我的平台分配它们的方式)。
  • 是的,这就是每个人的观点。所有这一切都取决于平台,您不应期望或依赖任何特定行为,因为如果您安全且正确地编写程序,它永远不会直接影响您。

标签: c arrays pointers memory


【解决方案1】:

首先,您的数组是一个指针数组。每个元素都是一个指针,当您为每个指向的指针分配内存时,它与您为该数组中的其他指针分配的内存完全无关。在这种情况下,它们实际上相距 32 字节,但这只是偶然。

在后一种情况下,您正在创建一个整数数组,这些整数在内存中都聚集在一起或“连续”。它们将是相邻的,因此当您打印它们的地址时您会看到这种模式,它们相隔 4 个字节。显然,您系统上的int 是 4 字节宽(这仍然很常见)。

“长地址”是由于您使用了动态分配:这将是您的系统碰巧持有堆的虚拟内存区域。没什么好担心的。

所以没有什么“奇怪”的。

【讨论】:

  • 你确定你没有混合数组吗?据我所知,第一个是指针数组,第二个是整数数组。我没有说我需要它们在内存中是连续的(尽管它们是连续的,并且在第二种情况下它提出了问题) - 为什么整数之间只有 4 位(或者它们是字节,如果是,为什么?)
  • @SlowTrout:你说得对,我把它们翻过来了。但答案是一样的:它们是 bytes,这是因为 ints 在您的系统上是 4 个字节宽。
【解决方案2】:

Int for Array 使用 1byte。

让地址: - 数组[0]=5000

然后 - 数组[1]=5001 - 数组[2]=5002 - 数组[3]=5003 - 数组[4]=5004 - 数组[5]=5005 - 数组[6]=5006 - 数组[7]=5007 - 数组[8]=5008 - 数组[9]=5009

现在,您正在分配指针。 那么Pointer的地址:

  • *(数组[0])=5010
  • *(数组[1])=5011
  • *(数组[2])=5012
  • *(数组[3])=5013
  • *(数组[4])=5014
  • *(数组[5])=5015
  • *(数组[6])=5016
  • *(数组[7])=5017
  • *(数组[8])=5018
  • *(数组[9])=5019

在这里你可以很容易地看到 array[i] 和 *(array[i]) 之间的差异总是 10 字节。 这是因为当任何 Array 被调用时,它只会一次分配内存总大小。

现在第二个地址: 数组 arr 已定义但未调用。 因此,在您调用 arr 之前不会分配内存 这里,调用是为了定义它

现在,第一行说:

int arr[10];

那只定义了基地址。 然后,您将该基址提供给 *start by:

int* start=arr;

因此指针获取该地址。 显然,让: 地址:

  • arr[0]=5020 然后:
  • *(start+0)=5020

因为它是一个指针(不是数组),所以需要 4 个字节。 同样,所有地址范围将是:

  • arr[0]=5020 - 5023
  • arr[1]=5024-5028 等等……

分配说明:

  • 每当我们定义一个数组时,它只定义基地址。 例如:

    int a[10];

将分配基地址,即起始地址,即a[0]的地址;

  • 当你定义一个指针时,它也只会分配基地址。

  • 区别仅在于分配,即数组分配1byte,指针分配4byte(GCC/Linux/32bit Compiler)给Pointer。

【讨论】:

  • 如果有人没有听懂我说的话。简单理解,地址的所有分配都取决于何时调用它们来分配值。否则只定义基地址。
  • 在解释第一个数组时一定有一些错误,因为我解释了一个 16 位编译器。很抱歉。
  • 但是分配过程是一样的。只有没有。字节数会有所不同。所以,请注意分配过程。
  • 对不起,为什么? Turbo C 比 C++ 更早!!!它已有二十多年的历史,专为 MS DOS 设计!!!!
  • 是的..你知道,我没有明白这一点。.DOS是主要原因,因为内存分配类似于FCFS..
猜你喜欢
  • 1970-01-01
  • 2014-11-20
  • 2013-01-29
  • 1970-01-01
  • 2018-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多