结构阵列存储器安排

时间:2013-10-28 05:02:46

标签: c

struct abc filled[]={{"aa",10},{"bb",20}};    
   printf("[%u,%u]\n",filled,&filled);
   printf("[%u,%u]\n",filled[0],&filled[0]);

   printf("[%u,%u]\n",filled+1,&filled+1);
   printf("[%u,%u]\n",filled[1],&filled[1]);

填充数组如何在内存中排列? 填充为数组的名称返回数组的基地址...类似&填充。但 fill [0]给出一些未知值,可能是地址和googly部分是& filled [0] 给出值10.我无法得到逻辑。以下是我得到的输出

[2293552,2293552]    
[4206592,10]    
[2293560,2293568]    
[4206595,20]    

2 个答案:

答案 0 :(得分:3)

%u中的格式说明符printf需要unsigned int类型的参数。您正在为它提供完全不相关类型的参数:指针和结构类型的对象。因此,您的代码会显示未定义的行为。代码被破坏,其输出完全没有意义。试图分析或解释它并没有多大意义。 (解释当然存在,但它与主要问题无关。)

至于如何在内存中排列数组... StackOverflow充满了对这个问题的重复答案。只需进行搜索。

答案 1 :(得分:2)

您的代码

struct abc filled[]={{"aa",10},{"bb",20}};    
printf("[%u,%u]\n",filled,&filled);
printf("[%u,%u]\n",filled[0],&filled[0]);

在我们进一步讨论之前,我们需要了解一下“struct”的含义。你没有提供一个定义,所以我假设它就像是

struct abc {
    const char* str;
    int i;
};

所以filled是这些对象的数组:

filled[] = {
    struct abc { str = "aa", i = 10 },
    struct abc { str = "bb", i = 20 }
};

filled[0]指的是空间中的第一个结构abc。

{ str = "aa", i = 10 }

在内存中,在32位版本中,这些将被布局,其中[...]表示一个字节:

[ptr][ptr][ptr][ptr][i][i][i][i]

在64位系统上,这些将按

布局
[ptr][ptr][ptr][ptr][ptr][ptr][ptr][ptr][i][i][i][i]

组成stri的字节的确切顺序取决于架构。

现在,您的代码......

struct abc filled[]={{"aa",10},{"bb",20}};    
printf("[%u,%u]\n",filled,&filled);
printf("[%u,%u]\n",filled[0],&filled[0]);

printf有一个限制。底层函数实际上看不到你的参数 - 它只是在堆栈上获取数据,它使用打印格式作为指南

最终,错误的是你将 struct 作为printf参数传递。

printf("[%u,%u]", filled[0], &filled[0]);

filled[0]解析为struct abc

正在发生的事情是程序将fill [0]的放到堆栈上以供printf使用。格式掩码中的第一个%u消耗str组件,第二个消耗i

如果这是您的完整计划:

#include <stdio.h>

struct abc {
    const char* str;
    int i;
};

int main() {
    struct abc filled[] = { { "aa", 16 }, { "bb", 20 } };
    printf("filled = %p\n", filled);
    printf("&filled = %p\n", &filled);
    printf("filled[0] = %p\n", filled[0]);
    printf("&filled[0] = %p\n", &filled[0]);
    printf("filled[0].str = %p\n", filled[0].str);
    printf("filled[0].i = %d\n", filled[0].i);
    return 0;
}

这是输出:

filled = 0xbfba5cb0
&filled = 0xbfba5cb0
filled[0] = 0x80485b0     <--+
&filled[0] = 0xbfba5cb0      | filled[0] actually printed the .str value
filled[0].str = 0x80485b0 <--+
filled[0].i = 16

您缺少的是以下编译器警告,因为您正在使用Visual Studio或没有-Wall进行编译:

prog.c: In function ‘main’:
prog.c:12:5: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘struct abc’ [-Wformat=]
     printf("filled[0] = %p\n", filled[0]);

当你这样做时

printf("[%u, %u]\n", filled[0], &filled[0]);

该计划执行以下操作:

push stack (const char*) "[%u, %u]\n"   // in 32-bit, 4-bytes of pointer.
push stack (struct abc) filled[0]       // pushes the entire of filled[0], str and i, 8 bytes.
push stack (struct abc*) &filled[0]     // pushes another 4 bytes.

结果堆栈看起来像这样

enter image description here

printf从不使用“&amp; filled [0]”的值,因为您没有指定正确的格式来读取堆栈上的数据。如果您改为使用

printf("filled[0].str=%p, filled[0].i=%u, &filled[0]=%p\n", filled[0], &filled[0]);

那么你会获得更有意义的数据,但这是一种实现结果的危险方式,因为它对数据布局和堆栈做了很多假设。

从根本上说,问题在于你是这样做的:

printf(“%u”,填充[0]);

其中fill [0]不是简单的数据类型。