为什么不能总是需要Malloc指针?

时间:2011-11-01 14:06:40

标签: c pointers malloc

为什么以下代码有效:

char *p;

p="hello";

printf("%s\n",p);

虽然这个没有:

char *p;

strcpy(p,"hello");

printf("%s\n",p);

我知道添加p = malloc(4);在第二个例子将使代码工作,但这正是我的问题。为什么在第二个例子中需要malloc而在第一个例子中不需要malloc?

我在SO上寻找类似的问题,但没有人回答这个问题。

6 个答案:

答案 0 :(得分:5)

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"可以存储为只读内存,因此您无法覆盖它。

答案 1 :(得分:0)

"hello"是一个字符串文字,将存在于输出程序的一部分中。内存由编译器在编译时分配,与实际代码相同的位置 *

也就是说"hello"的类型为const char[6],会自动转换为char *。 (对于字符串文字,使用const char*而不是char*是一个很好的习惯。)

在第二种情况下,当您致电pstrcpy未经宣传,因此结果未定义。 p=malloc(4); 不足以解决这个问题,字符串“hello”由 6 个字符组成 - 来自单词hello本身加上{{1}终止字符串。

* 实际上在现代系统上并不完全正确,它附近与代码相同。

答案 2 :(得分:0)

p="hello";将字符串文字“hello”的地址分配给p,而scanf需要放置扫描输入的位置,因此需要分配一些内存(静态,动态或自动)。

答案 3 :(得分:0)

strcpy(p,"hello");

对于字符串文字hello复制,p必须指向有效的内存位置,在这种情况下不是。

答案 4 :(得分:0)

因为p具有的值将是随机的,并且任何复制字符串的尝试都将导致崩溃。通过使用malloc,您可以确保p的值可以复制(只要缓冲区足够大)

答案 5 :(得分:0)

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

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

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 ++中的const char)的数组,以这样的方式存储,即它们在生命周期内是活动的该程序。文字"Hello"从地址0x00080000开始存储,文字“再见”从地址0x00080008开始存储。

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

当您编写char *p = "Hello";时,数组表达式"Hello"将转换为指针表达式,其值是数组的第一个元素的位置,并且该指针值将复制到{{1} },如上面的记忆图所示。

当您编写p时,char *q;的初始值是不确定的 1 ,如q字节值所示。该值可能对应于可写地址,也可能不对应;可能性不大。所以基本上,当你写0x??时,你试图将strcpy(q, "goodbye");字符串文字的内容复制到内存中的随机位置。通常情况下,这会导致运行时错误。

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

如果我们将代码段更改为

"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        0x40  0x00  0x00  0x00
            ...
<dynamic>   0x40000000        'g'   'o'   'o'   'd'
            0x40000004        'b'   'y'   'e'   0x00
            0x40000008        0x??  0x??

在这种情况下,char *p = "Hello"; char *q; q = malloc(10); strcpy(q, "goodbye"); printf("p = %s, q = %s\n", p, q); 从0x40000000开始留出10个字节的内存,并将该地址复制到malloc。然后,对q的调用将字符串文字“goodbye”的内容复制到该位置。

<小时/> 1 如果strcpy被声明为q或文件范围(任何函数之外),那么它将被初始化为0(0x00000000)。