为什么指向 Char 的指针并不总是需要 Malloc?

发布于 2024-12-13 00:31:53 字数 292 浏览 0 评论 0原文

为什么下面的代码有效:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

冰雪梦之恋 2024-12-20 00:31:53

p 是一个指针。您需要使其指向某物。在第一种情况下,

 p = "hello";

使 p 指向运行时位于程序内存中某处的字符串文字。

在第二种情况下,您没有使 p 指向任何内容,因此执行任何查看 p 指向位置的操作都是无效的。

p = malloc(some_size);

使p指向一块可以容纳some_size字符的(未初始化的)内存。如果你保留了足够的空间,你就可以做类似 strcpy(p, "hello") 的事情,因为 p 确实指向一个有效的内存区域,所以复制到内存中指向 -通过 p 就可以了。请注意,some_size 必须至少与您要复制到其中的内容一样大,包括 '\0' 字符串终止符。

请注意,这样做:

p = "hello";
strcpy(p, "bye");

将无效,因为 "hello" 可以存储在只读存储器中,因此您无法覆盖它。

p is a pointer. You need to make it point to something. In the first case,

 p = "hello";

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 where p points to is invalid.

p = malloc(some_size);

makes p point to a piece of (uninitialized) memory that can hold some_size chars. If you reserved enough, you can then do things like strcpy(p, "hello") because p does point to a valid memory area, so copying into the memory pointed-to by p is ok. Note that some_size must be at least as big as what you want to copy into it, including the '\0' string terminator.

Note that doing:

p = "hello";
strcpy(p, "bye");

would be invalid because "hello" can be stored as in a read-only memory, so you can't overwrite it.

自找没趣 2024-12-20 00:31:53

p="hello"; 将字符串文字“hello”的地址分配给 p,而 scanf 需要一个地方来放置扫描的输入,所以你需要为其分配一些内存(静态、动态或自动)。

p="hello"; assigns the address of the string literal "hello" to p, while scanf requires a place to put the scanned input, so you need to allocate some memory (static, dynamic or automatic) for it.

卸妝后依然美 2024-12-20 00:31:53
strcpy(p,"hello");

对于要复制的字符串文字hello,p必须指向有效的内存位置,但在本例中并非如此。

strcpy(p,"hello");

For string literal hello to be copied, p must point to a valid memory location which in this case isn't.

素染倾城色 2024-12-20 00:31:53

因为 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 of p will be ok for a copy to occur (as long as the buffer is big enough)

国产ˉ祖宗 2024-12-20 00:31:53

"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 be const char[6], which is converted automatically into char *. (Using const char* instead of char* for string literals is a good habit to get into though)

In the second case p is uninitalised when you call strcpy, 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.

酒几许 2024-12-20 00:31:53

我发现在这种情况下,图片会派上用场。

让我们结合上面的两个片段:

char *p = "Hello";
char *q;

strcpy(q, "goodbye");
printf("p = %s, q = %s\n", p, q);

这是一个假设的内存映射,显示了 pq 以及字符串 "Hello"之间的关系>"goodbye":

Item        Address           0x00  0x01  0x02  0x03
----        -------           ----  ----  ----  ----
  "Hello"   0x00080000        'H'   'e'   'l'   'l'
            0x00080004        'o'   0x00  0x??  0x??
"goodbye"   0x00080008        'g'   'o'   'o'   'd'
            0x0008000C        'b'   'y'   'e'   0x00
            ...
        p   0x01010000        0x00  0x08  0x00  0x00
        q   0x01010004        0x??  0x??  0x??  0x??

"Hello""goodbye" 是字符串文字,它们是 char 数组 (常量字符 中C++),存储方式使得它们在程序的整个生命周期内都处于活动状态。文字“Hello”存储在地址0x00080000开始,文字“goodbye”存储在地址0x00080008开始。

pq 是指向具有 auto 范围的 char 的指针,这意味着它们仅在块的生命周期内存在其中声明了它们。在本例中,它们分别位于地址 0x01010000 和 0x01010004(在本例中我们假设为 32 位指针)。

当您编写 char *p = "Hello"; 时,数组表达式 "Hello" 会转换为指针表达式,其值是数组第一个元素的位置,并且该指针值被复制到 p,如上面的内存映射所示。

当您写入 char *q; 时,q 的初始值是不确定的1,如 0x?? 字节值。该值可能对应也可能不对应于可写地址;很可能事实并非如此。所以基本上,当您编写 strcpy(q, "goodbye"); 时,您正在尝试将 "goodbye" 字符串文字的内容复制到记忆。通常,这会导致运行时错误。

如果为字符串分配缓冲区,缓冲区必须足够长才能存储整个字符串加上 0 终止符;仅分配 4 个字节是不够的,因为这样你的字符串将溢出到你不“拥有”的内存中,可能会破坏一些重要的东西(从技术上讲,行为是未定义的,意味着任何事情都可能发生)。 IOW,您不必为指针分配内存(在声明指针时已经完成),您必须为所指向的对象分配内存。

如果我们将代码片段更改为类似的内容

char *p = "Hello";
char *q;

q = malloc(10);
strcpy(q, "goodbye");
printf("p = %s, q = %s\n", p, q);

,那么我们的内存映射将如下所示:

Item        Address           0x00  0x01  0x02  0x03
----        -------           ----  ----  ----  ----
  "Hello"   0x00080000        'H'   'e'   'l'   'l'
            0x00080004        'o'   0x00  0x??  0x??
"goodbye"   0x00080008        'g'   'o'   'o'   'd'
            0x0008000C        'b'   'y'   'e'   0x00
            ...
        p   0x01010000        0x00  0x08  0x00  0x00
        q   0x01010004        0x40  0x00  0x00  0x00
            ...
<dynamic>   0x40000000        'g'   'o'   'o'   'd'
            0x40000004        'b'   'y'   'e'   0x00
            0x40000008        0x??  0x??

在本例中,malloc 从 0x40000000 开始留出 10 个字节的内存,并将该地址复制到 q。然后,对 strcpy 的调用会将字符串文字“goodbye”的内容复制到该位置。


1If q had been declared as static 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:

char *p = "Hello";
char *q;

strcpy(q, "goodbye");
printf("p = %s, q = %s\n", p, q);

Here's a hypothetical memory map showing the relationships between p, q, and the strings "Hello" and "goodbye":

Item        Address           0x00  0x01  0x02  0x03
----        -------           ----  ----  ----  ----
  "Hello"   0x00080000        'H'   'e'   'l'   'l'
            0x00080004        'o'   0x00  0x??  0x??
"goodbye"   0x00080008        'g'   'o'   'o'   'd'
            0x0008000C        'b'   'y'   'e'   0x00
            ...
        p   0x01010000        0x00  0x08  0x00  0x00
        q   0x01010004        0x??  0x??  0x??  0x??

"Hello" and "goodbye" are string literals, which are arrays of char (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 and q are pointers to char with auto 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 to p, as seen in the memory map above.

When you write char *q;, the initial value of q is indeterminate1 as indicated by the 0x?? byte values. That value may or may not correspond to a writable address; odds are that it doesn't. So basically, when you write strcpy(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

char *p = "Hello";
char *q;

q = malloc(10);
strcpy(q, "goodbye");
printf("p = %s, q = %s\n", p, q);

then our memory map will look something like this:

Item        Address           0x00  0x01  0x02  0x03
----        -------           ----  ----  ----  ----
  "Hello"   0x00080000        'H'   'e'   'l'   'l'
            0x00080004        'o'   0x00  0x??  0x??
"goodbye"   0x00080008        'g'   'o'   'o'   'd'
            0x0008000C        'b'   'y'   'e'   0x00
            ...
        p   0x01010000        0x00  0x08  0x00  0x00
        q   0x01010004        0x40  0x00  0x00  0x00
            ...
<dynamic>   0x40000000        'g'   'o'   'o'   'd'
            0x40000004        'b'   'y'   'e'   0x00
            0x40000008        0x??  0x??

In this case, malloc sets aside 10 bytes of memory starting at 0x40000000, and copies that address to q. The call to strcpy then copies the contents of the string literal "goodbye" to that location.


1If q had been declared as static or at file scope (outside of any function) , then it would have been initialized to 0 (0x00000000).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文