c中这个简单的printf输出背后的真正含义是什么?

时间:2015-12-13 23:16:27

标签: c memory

看两行c代码并输出: 代码:

char * str = "hello world!";
printf("h at heap memory address: %p\n",str);
printf("str pointer stack memory address: %p\n",&str);

并输出:

h at heap memory address: 0x4008a8
str pointer stack memory address: 0x7ffc9e7ceb90

堆和堆栈的内存地址长度分别为0x4008a8,0x7ffc9e7ceb90。为什么堆的内存地址是3个字节而堆栈的内存地址是6个字节?与虚拟内存和分页有关的东西?

3 个答案:

答案 0 :(得分:4)

请改为尝试:

char * str = "hello world!";
printf("h at heap memory address: %p (%zu bytes)\n", str, sizeof(str));
printf("str pointer stack memory address: %p (%zu bytes)\n", &str, sizeof(&str));

使用sizeof运算符,我们可以打印两个指针的实际大小。 (%zu是来自sizeof的无符号结果的格式说明符 - 它可能等同于您系统上的%lu。)

你会发现,在这两种情况下,指针实际占用8个字节(64位)。

printf显示的十六进制表示仅显示3或6个字节的原因是因为printf丢弃任何前导零。考虑这个类似的例子:

int i = 10;
printf("%x\n", i);

结果只是“a”,但这并不意味着i只占用一个字节。

答案 1 :(得分:0)

@JohnathanLeffler钉了它。 "字符串文字可能存储在代码 [data]段中,在那里它是不可写的。" 你可以看到这个更多的探索。

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

/* Do this in a function so I can verify what is stack and what is heap.
 * Try to return a variable and see if the compiler warns that it's
 * stack memory!
 */
static char *test_mem() {
    char *stack = "whom";
    char *heap = malloc(sizeof(char) * 5);

    printf("char *stack = \"%s\" at %p (size %zu) inner %p (size %zu)\n",
           stack, stack, sizeof(stack), &stack, sizeof(&stack));
    printf("char *heap = malloc at %p (size %zu) inner %p (size %zu)\n",
           heap, sizeof(heap), &heap, sizeof(&heap));

    return heap;
}

int main(void)
{
    char *ret = test_mem();
    printf("%s\n", ret);
    return 0;
}

char *stack = "whom" at 0x102fc0f28 (size 8) inner 0x7fff5cc3f4d8 (size 8)
char *heap = malloc at 0x7f9362404c80 (size 8) inner 0x7fff5cc3f4d0 (size 8)

请注意,只有字符串文字位于较低的内存地址。所有其余的基本上都在同一个位置。当我在十六进制编辑器中打开可执行文件时,我可以找到一个字符串块。

00000f20: dcff ffff 2573 0a00 7768 6f6d 0063 6861  ....%s..whom.cha
00000f30: 7220 2a73 7461 636b 203d 2022 2573 2220  r *stack = "%s" 
00000f40: 6174 2025 7020 2873 697a 6520 257a 7529  at %p (size %zu)
00000f50: 2069 6e6e 6572 2025 7020 2873 697a 6520   inner %p (size 
00000f60: 257a 7529 0a00 6368 6172 202a 6865 6170  %zu)..char *heap
00000f70: 203d 206d 616c 6c6f 6320 6174 2025 7020   = malloc at %p 
00000f80: 2873 697a 6520 257a 7529 2069 6e6e 6572  (size %zu) inner
00000f90: 2025 7020 2873 697a 6520 257a 7529 0a00   %p (size %zu)..

字符串foo未存储在堆中,它位于可执行文件的data segment中,正如您所猜测的那样,它被作为virtual memory访问,并被分配了一个特殊范围。

最后,输出显示那些指针的大小都相同。它们都是(在我的情况下)64位(8字节)指针。

答案 2 :(得分:0)

说明

请注意,指针仍然是C中的变量,唯一使它们变得特殊的是它们旁边有特殊的*符号。指针的值是它引用的地址,就像int的值是它赋给的值

char * str = "hello world!";
printf("h at heap memory address: %p\n",str);
printf("str pointer stack memory address: %p\n",&str);

它们都使用指针说明符(%p),用于打印值的内存地址。 请注意,这是实施定义。

  • 第一个打印字符串文字&#34; hello world!&#34;的内存地址,即指针str
  • 的值
  • 第二个打印指针的存储器地址,即str
  • 的存储器地址

至于为什么这些值相距甚远,@DaoWen已经回答了这个问题,它与虚拟页面或其他什么无关。