为什么指向 Char 的指针并不总是需要 Malloc?
为什么下面的代码有效:
char *p;
p="hello";
printf("%s\n",p);
虽然这个不行:
char *p;
strcpy(p,"hello");
printf("%s\n",p);
我知道添加 p=malloc(4);在第二个示例中将使代码正常工作,但这正是我的问题。为什么第二个示例需要 malloc 而第一个示例不需要呢?
我在 SO 上寻找类似的问题,但没有人准确回答这个问题。
Why the following code works:
char *p;
p="hello";
printf("%s\n",p);
While this one doesn't:
char *p;
strcpy(p,"hello");
printf("%s\n",p);
I know that adding p=malloc(4); on the second example would make the code work, but that is exactly my question. Why malloc is needed in the second example but not in the first?
I looked for similar questions on SO but none answer this exactly.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
p
是一个指针。您需要使其指向某物。在第一种情况下,使
p
指向运行时位于程序内存中某处的字符串文字。在第二种情况下,您没有使
p
指向任何内容,因此执行任何查看p
指向位置的操作都是无效的。使
p
指向一块可以容纳some_size
字符的(未初始化的)内存。如果你保留了足够的空间,你就可以做类似strcpy(p, "hello")
的事情,因为p
确实指向一个有效的内存区域,所以复制到内存中指向 -通过p
就可以了。请注意,some_size
必须至少与您要复制到其中的内容一样大,包括'\0'
字符串终止符。请注意,这样做:
将无效,因为
"hello"
可以存储在只读存储器中,因此您无法覆盖它。p
is a pointer. You need to make it point to something. In the first case,makes
p
point to that string literal which is located somewhere in your program's memory at runtime.In your second case, you didn't make
p
point to anything, so doing anything that looks at wherep
points to is invalid.makes
p
point to a piece of (uninitialized) memory that can holdsome_size
chars. If you reserved enough, you can then do things likestrcpy(p, "hello")
becausep
does point to a valid memory area, so copying into the memory pointed-to byp
is ok. Note thatsome_size
must be at least as big as what you want to copy into it, including the'\0'
string terminator.Note that doing:
would be invalid because
"hello"
can be stored as in a read-only memory, so you can't overwrite it.p="hello";
将字符串文字“hello”的地址分配给p
,而scanf
需要一个地方来放置扫描的输入,所以你需要为其分配一些内存(静态、动态或自动)。p="hello";
assigns the address of the string literal "hello" top
, whilescanf
requires a place to put the scanned input, so you need to allocate some memory (static, dynamic or automatic) for it.对于要复制的字符串文字
hello
,p必须指向有效的内存位置,但在本例中并非如此。For string literal
hello
to be copied, p must point to a valid memory location which in this case isn't.因为
p
的值是随机的,任何复制字符串的尝试都会导致崩溃。通过使用 malloc,您可以确保p
的值适合进行复制(只要缓冲区足够大)Because the value that
p
has is going to be random and any attempts to copy the string there will result in a crash. By using malloc you ensure that the value ofp
will be ok for a copy to occur (as long as the buffer is big enough)"hello"
是一个字符串文字,将存在于输出程序的一部分中。内存是由编译器分配的,在编译的时候和实际代码在同一个地方*也就是说
"hello"<的类型/code> 将是
const char[6]
,它会自动转换为char *
。 (使用const char*
而不是char*
作为字符串文字是一个好习惯)在第二种情况下,
p
未初始化:您调用strcpy
,因此结果是未定义的。p=malloc(4);
也不足以解决这个问题,字符串“hello”由 6 个字符组成 - 5 个来自单词 hello 本身加上'\0'
来终止字符串。* 实际上,在现代系统上这并不完全正确,它与代码接近相同的位置。
"hello"
is a string literal and will live in part of your output program. The memory is allocated by the compiler, at compile time, in the same place as the actual code*That is to say that the type of
"hello"
will beconst char[6]
, which is converted automatically intochar *
. (Usingconst char*
instead ofchar*
for string literals is a good habit to get into though)In the second case
p
is uninitalised when you callstrcpy
, thus the result is undefined.p=malloc(4);
is not sufficient to fix this either, the string "hello" is made of 6 characters -- 5 from the word hello itself plus'\0'
to terminate the string.* Actually on modern systems that's not quite true, it's near the same place as the code.
我发现在这种情况下,图片会派上用场。
让我们结合上面的两个片段:
这是一个假设的内存映射,显示了
p
、q
以及字符串"Hello"
和之间的关系>"goodbye"
:"Hello"
和"goodbye"
是字符串文字,它们是char
数组 (常量字符
中C++),存储方式使得它们在程序的整个生命周期内都处于活动状态。文字“Hello”
存储在地址0x00080000开始,文字“goodbye”存储在地址0x00080008开始。p
和q
是指向具有auto
范围的char
的指针,这意味着它们仅在块的生命周期内存在其中声明了它们。在本例中,它们分别位于地址 0x01010000 和 0x01010004(在本例中我们假设为 32 位指针)。当您编写
char *p = "Hello";
时,数组表达式"Hello"
会转换为指针表达式,其值是数组第一个元素的位置,并且该指针值被复制到p
,如上面的内存映射所示。当您写入
char *q;
时,q
的初始值是不确定的1,如0x??
字节值。该值可能对应也可能不对应于可写地址;很可能事实并非如此。所以基本上,当您编写strcpy(q, "goodbye");
时,您正在尝试将"goodbye"
字符串文字的内容复制到记忆。通常,这会导致运行时错误。如果为字符串分配缓冲区,缓冲区必须足够长才能存储整个字符串加上 0 终止符;仅分配 4 个字节是不够的,因为这样你的字符串将溢出到你不“拥有”的内存中,可能会破坏一些重要的东西(从技术上讲,行为是未定义的,意味着任何事情都可能发生)。 IOW,您不必为指针分配内存(在声明指针时已经完成),您必须为所指向的对象分配内存。
如果我们将代码片段更改为类似的内容
,那么我们的内存映射将如下所示:
在本例中,
malloc
从 0x40000000 开始留出 10 个字节的内存,并将该地址复制到q
。然后,对strcpy
的调用会将字符串文字“goodbye”的内容复制到该位置。1If
q
had been declared asstatic
or at file scope (outside of any function) , then it would have been initialized to 0 (0x00000000).I've found that in situations like this, a picture comes in handy.
Let's combine your two snippets above:
Here's a hypothetical memory map showing the relationships between
p
,q
, and the strings"Hello"
and"goodbye"
:"Hello"
and"goodbye"
are string literals, which are arrays ofchar
(const char
in C++), stored in such a way that they are active over the lifetime of the program. The literal"Hello"
is stored beginning at address 0x00080000, and the literal "goodbye" is stored beginning at address 0x00080008.p
andq
are pointers tochar
withauto
extent, meaning that they only exist for the lifetime of the block in which they are declared. In this case, they are located at addresses 0x01010000 and 0x01010004, respectively (we're assuming 32-bit pointers in this example).When you write
char *p = "Hello";
, the array expression"Hello"
is converted to a pointer expression whose value is the location of the first element of the array, and that pointer value is copied top
, as seen in the memory map above.When you write
char *q;
, the initial value ofq
is indeterminate1 as indicated by the0x??
byte values. That value may or may not correspond to a writable address; odds are that it doesn't. So basically, when you writestrcpy(q, "goodbye");
, you're attempting to copy the contents of the"goodbye"
string literal to a random location in memory. More often than not, that's going to lead to a runtime error.If you allocate a buffer for the string, the buffer must be long enough to store the entire string plus the 0 terminator; allocating just 4 bytes isn't enough, because then your string will spill over into memory you don't "own", potentially clobbering something important (technically, the behavior is undefined, meaning anything can happen). IOW, you don't have to allocate memory for the pointer (that's already done when you declare the pointer), you have to allocate memory for the thing being pointed to.
If we change our code snippet to something like
then our memory map will look something like this:
In this case,
malloc
sets aside 10 bytes of memory starting at 0x40000000, and copies that address toq
. The call tostrcpy
then copies the contents of the string literal "goodbye" to that location.1If
q
had been declared asstatic
or at file scope (outside of any function) , then it would have been initialized to 0 (0x00000000).