为什么堆栈上的char []而堆上的char*?

tgu*_*926 22 c memory pointers

我对发生的事情感到非常困惑.我一直以为char *并且char []可以互换,但是在查看内存地址后,它似乎char *在堆中分配空间,而char []在堆栈上分配内存.

char stack[] = "hello";
char *heap = "hello";

char *heap_string_malloc = malloc(5);
heap_string_malloc = "hello";

printf("Address of stack[0]: %p\n", stack);
printf("Address of heap[0]: %p\n", heap);
printf("Address of heap_string_malloc[0]: %p\n", heap_string_malloc);
Run Code Online (Sandbox Code Playgroud)

输出以下内容:

Address of stack[0]: 0x7fff8b0b85b0
Address of heap[0]: 0x400760
Address of heap_string_malloc[0]: 0x400760
Run Code Online (Sandbox Code Playgroud)

这是否意味着char *动态分配?

令我困惑的是,为什么malloc分配与已分配的内存地址相同的内存地址char *heap?我没有运行任何优化(简单gcc file.c).

Fre*_*Foo 36

数组不是指针.你的程序一行一行地做了什么

// Allocate 6 bytes in the stack and store "hello" in them
char stack[] = "hello";

// Allocate pointer on the stack and point it to a static, read-only buffer
// containing "hello"
char *heap = "hello";

// Malloc 5 bytes (which isn't enough to hold "hello" due to the NUL byte)
char *heap_string_malloc = malloc(5);

// Reset heap_string_malloc to point to a static buffer; memory leak!
heap_string_malloc = "hello";
Run Code Online (Sandbox Code Playgroud)

你看到两次相同指针的原因是因为编译器优化了包含的第二个静态缓冲区"hello".

  • @ user2018675是的,因为他还没有任何指向malloc分配的内存的东西.我喜欢用狗的类比来解释它.我从一家商店买了一条狗,然后把他带到公园,与他连在一起(为你的美国人绑带......).在公园的时候,我让他脱离了领先,把铅连接到别人的狗身上并回家.我还有一只狗,但不是我的狗."狗"是malloc返回的."lead"是heap_string_malloc.另一只狗是"你好". (3认同)

Som*_*ude 11

当你这样做的时候

char *heap = "hello";
Run Code Online (Sandbox Code Playgroud)

指针heap实际上并不指向堆,它指向由操作系统加载程序与其余程序一起加载的静态数据.事实上,应该是正确的

const char *heap = "hello";
Run Code Online (Sandbox Code Playgroud)

作为heap指向一个恒定只读一块内存.


此外,虽然数组衰减(并且可以用作)指针,而指针可以与数组语法一起使用,但它们并不相同.最大的区别在于,对于数组,您可以使用例如sizeof获取实际数组的字节大小,而指针则不可能.


作为第三件事,当你做的时候

char *heap_string_malloc = malloc(5);
heap_string_malloc = "hello";
Run Code Online (Sandbox Code Playgroud)

你有一个内存泄漏,因为你先分配东西,heap_string_malloc然后直接重新分配heap_string_malloc指向完全不同的东西.


至于原因,你会得到相同的地址都heapheap_string_malloc这是因为这两个点,以同样的文字字符串.


Joh*_*ode 7

字符串文字"hello"以这样的方式存储,即它们在程序的生命周期内保存.它们通常存储在可以是只读的单独数据段(不同于堆栈或堆)中.

当你写作

char stack[] = "hello";
Run Code Online (Sandbox Code Playgroud)

要创建一个新的auto("堆叠")型"的6个元素的数组的变量char(尺寸从字符串文字的长度所取)",而内容的字符串文字的"hello"被复制到它.

当你写作

char *heap = "hello";
Run Code Online (Sandbox Code Playgroud)

您正在创建auto"指向"指针类型的新("堆栈")变量char,并将字符串文字的地址"hello"复制到它.

以下是它在我的系统上的外观:

       Item        Address   00   01   02   03
       ----        -------   --   --   --   --
    "hello"       0x400b70   68   65   6c   6c    hell
                  0x400b74   6f   00   22   68    o."h

      stack 0x7fffb00c7620   68   65   6c   6c    hell
            0x7fffb00c7624   6f   00   00   00    o...

       heap 0x7fffb00c7618   70   0b   40   00    p.@.
            0x7fffb00c761c   00   00   00   00    ....

      *heap       0x400b70   68   65   6c   6c    hell
                  0x400b74   6f   00   22   68    o."h
Run Code Online (Sandbox Code Playgroud)

如您所见,字符串文字"hello"有自己的存储空间,从地址0x400b70开始.两个stackahd heap 变量都被创建为auto("堆栈")变量. stack包含字符串文字内容的副本,同时heap包含字符串文字的地址.

现在,假设我使用malloc为字符串分配内存并将结果分配给heap:

heap = malloc( sizeof *heap * strlen( "hello" + 1 ));
strcpy( heap, "hello" );
Run Code Online (Sandbox Code Playgroud)

现在我的内存映射如下所示:

       Item        Address   00   01   02   03
       ----        -------   --   --   --   --
    "hello"       0x400b70   68   65   6c   6c    hell
                  0x400b74   6f   00   22   68    o."h

      stack 0x7fffb00c7620   68   65   6c   6c    hell
            0x7fffb00c7624   6f   00   00   00    o...

       heap 0x7fffb00c7618   10   10   50   00    ..P.
            0x7fffb00c761c   00   00   00   00    ....

      *heap       0x501010   68   65   6c   6c    hell
                  0x501014   6f   00   00   00    o...
Run Code Online (Sandbox Code Playgroud)

heap变量现在包含一个不同的地址,该地址指向另一个包含字符串"hello"的6字节内存块.

编辑

对于byteofthat,这是我用来生成上面地图的代码:

dumper.h:

#ifndef DUMPER_H
#define DUMPER_H

/**
 * Dumps a memory map to the specified output stream
 *
 * Inputs:
 *
 *   names     - list of item names
 *   addrs     - list of addresses to different items
 *   lengths   - length of each item
 *   count     - number of items being dumped
 *   stream    - output destination
 *
 * Outputs: none
 * Returns: none
 */
void dumper(char **names, void **addrs, size_t *lengths, size_t count, FILE *stream);

#endif
Run Code Online (Sandbox Code Playgroud)

dumper.c:

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

#include "dumper.h"

/**
 * Dumps a memory map to the specified output stream
 *
 * Inputs:
 *
 *   names     - list of item names
 *   addrs     - list of addresses to different items
 *   lengths   - length of each item
 *   count     - number of items being dumped
 *   stream    - output destination
 *
 * Outputs: none
 * Returns: none
 */
void dumper(char **names, void **addrs, size_t *lengths, size_t count, FILE *stream)
{
  size_t i;
  int maxlen = 15;

  for ( size_t j = 0; j < count; j++ )
  {
    if (strlen(names[j]) > maxlen && strlen(names[j]) < 50)
      maxlen = strlen(names[j]);
  }

  fprintf(stream,"%*s%15s%5s%5s%5s%5s\n", maxlen, "Item", "Address", "00", "01",
    "02", "03");
  fprintf(stream,"%*s%15s%5s%5s%5s%5s\n", maxlen, "----", "-------", "--", "--",
    "--", "--");

  for (i = 0; i < count; i++)
  {
    size_t j;
    char *namefield = names[i];
    unsigned char *p = (unsigned char *) addrs[i];
    for (j = 0; j < lengths[i]; j+=4)
    {
      size_t k;

      fprintf(stream,"%*.*s", maxlen, maxlen, namefield);
      fprintf(stream,"%15p", (void *) p);
      for (k = 0; k < 4; k++)
      {
        fprintf(stream,"%3s%02x", " ", p[k]);
      }
      fprintf(stream, "    ");
      for ( k = 0; k < 4; k++)
      {
        if (isgraph(p[k]))
          fprintf(stream,"%c", p[k]);
        else
          fprintf(stream, ".");
      }
      fputc('\n', stream);
      namefield = " ";
      p += 4;
    }
    fputc('\n', stream);
  }
}
Run Code Online (Sandbox Code Playgroud)

以及如何使用它的示例:

#include <stdio.h>

#include "dumper.h"

int main(void)
{
  int x = 0;
  double y = 3.14159;
  char foo[] = "This is a test";

  void *addrs[] = {&x, &y, foo, "This is a test"};
  char *names[] = {"x", "y", "foo", "\"This is a test\""};
  size_t lengths[] = {sizeof x, sizeof y, sizeof foo, sizeof "This is a test"};

  dumper(names, addrs, lengths, 4, stdout);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)