字符串字面量(如"hello"
)存储在程序整个生命周期中,通常被存储在一个单独的数据段(与堆栈或堆不同),该数据段可能是只读的。
当您编写代码时:
char stack[] = "hello";
你正在创建一个新的auto
(“stack”)变量,其类型为“6个元素的char
数组”(大小取决于字符串文字的长度),并且字符串文字"hello"
的内容被复制到该变量中。
当你编写:
char *heap = "hello";
你正在创建一个类型为“指向char
的指针”的新的auto
(“堆栈”)变量,然后将字符串字面值"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
如您所见,字符串常量
"hello"
有自己的存储空间,从地址0x400b70开始。
stack
和
heap
变量都被创建为
auto
("stack")变量。
stack
包含字符串常量内容的一个副本,而
heap
包含字符串常量的地址。
现在,假设我使用
malloc
来分配字符串的内存,并将结果分配给
heap
:
heap = malloc( sizeof *heap * strlen( "hello" + 1 ));
strcpy( heap, "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 10 10 50 00 ..P.
0x7fffb00c761c 00 00 00 00 ....
*heap 0x501010 68 65 6c 6c hell
0x501014 6f 00 00 00 o...
heap
变量现在包含不同的地址,该地址指向另一个含有字符串 "hello" 的 6 字节内存块。
编辑
对于 byteofthat,这是我用来生成上面地图的代码:
dumper.h:
#ifndef DUMPER_H
#define DUMPER_H
void dumper(char **names, void **addrs, size_t *lengths, size_t count, FILE *stream);
#endif
dumper.c:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "dumper.h"
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);
}
}
如何使用它的示例:
#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;
}
char *heap_string_malloc = malloc(5); heap_string_malloc = "hello";
这是一个即时内存泄漏。这不是Java。考虑一下:int a=5; a=6;
那么5去哪了? - WhozCraigchar []
的字符数组。但是,一个char *
指针同样可以指向它。 - Sadiqueconst char[]
地址分配给非constchar*
指针,最近的C编译器会对此发出警告(例如我的clang)。 - WhozCraigMyStruct **str_params
中,我试图赋值类似于str_params->some_char_arr = some_char_ptr
的东西),显然没有起作用。 - Elias Van Ootegem