Malloc - 为什么这个字符串接受这个文本的分配较小?

时间:2018-01-06 08:55:41

标签: c

我想知道为什么这个程序不会出现段错误?

    int main(void)
    {
          char *s = malloc(sizeof(char) * 5);

          s = "Hello world !";
          printf("%s\n", s);
    }

我的意思是我只分配了5个大小的字符,但它会打印整个文本。

感谢。

3 个答案:

答案 0 :(得分:5)

char* s = malloc(5);

指向分配的内存

s = "Hello World !";

你将指向设置为内存中的另一个地方,你没有将字符串复制到s指向的位置。为此,您需要使用strcpy或memcpy。

答案 1 :(得分:4)

因为你没有做任何会导致的事情。

您有内存泄漏。就是这样。您正在分配字符串文字的地址。(作为数组的字符串文字衰减为指向它的第一个元素的指针)。并丢失旧分配的块地址。

如果您执行了strcpy(s,"hello world!");,那么肯定会出现段错误。当然,你的程序会有不确定的行为。

另请注意,有一件事s = "hello world";不会将字符串文字"hello world"复制到s。事实并非如此。只需拥有字符串文字的地址,然后将其传递给printf%s格式说明符输出字符,直到它获得\0并获得一个。 (因为字符串文字以null结尾)。

供您参考,

  

分段错误(aka segfault)是导致的常见情况   程序崩溃;它们通常与名为core的文件相关联。   Segfaults是由试图读取或写入非法的程序引起的   记忆位置。

在这里你没有做过这样的事情。

每当你分配动态分配的内存时,请记住一件事 - 在你完成工作后释放它。为此,请参阅此函数free()。此外,最好检查malloc的返回值。问题是当你通过s指向字符串文字时,如果你试图修改它,你也可能会得到分段错误。因为字符串文字是不可修改的。

总之,代码在分配后不会使用分配的内存。那个记忆被泄露了。然后将指向字符串文字的指针分配给s,然后打印出预期的内容。代码没有未定义的行为问题。

答案 2 :(得分:1)

在你编写的动态分配内存的任何代码中,你有2个职责关于任何分配的内存块:(1)总是保留一个指向起始地址的指针内存块,(2)当不再需要时,它可以释放

你违反了规则(1),它阻止了能够满足规则(2)。

能够直观显示您正在做的事情的一种方法是使用调试器,或者只是在s之后查看malloc的地址,然后在分配{{1}后再查看"Hello world !"的地址(注意:您还应该在进一步使用malloc之前验证您对s的调用是否成功)

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

int main (void) {

    char *s = malloc(sizeof(char) * 5);
    if (!s) {
        perror ("malloc - s");
        return 1;
    }

    printf ("1. address of s : %p\n", s);

    s = "Hello world !";

    printf ("2. address of s : %p\n", s);

    return 0;
}

示例使用/输出

$ ./bin/saddress
1. address of s : 0xa45010
2. address of s : 0x4006f5

地址有变化吗?为什么?保留malloc ed s的原始地址的变量是什么?你将如何free你分配的记忆?

正如许多答案和评论中所解释的那样"Hello world !"是在只读内存中创建的字符串文字,其地址是第一个的地址字符'H'。当您致电s时,您还请求malloc新分配的内存块的地址并将其分配给s。除非您在致电malloc后保留free中包含的原始地址,否则您无法s = "Hello world !";您分配的内存 - 导致内存泄漏。基本上,当您分配s时,您丢失了已分配的内存块的地址(因为"Hello world !"现在将地址保存到#include <stdio.h> #include <stdlib.h> int main (void) { char *literal = "Hello world !"; char *s = malloc(sizeof(char) * 5); if (!s) { perror ("malloc - s"); return 1; } printf ("1. address of s : %p\n", s); s = literal; printf ("2. address of s : %p\n", s); return 0; } 的开头)

如果它仍然模糊,那么让我们看另一个完全相同的例子:

s

这里出现了完全相同的问题。您为"Hello world !"分配,然后将literal的地址(由指针s保存)分配给free (s);,失去对原始内存块的引用。

如果您尝试s,问题会变得非常明显。

你如何解决这个问题? (不要覆盖s开头)但是,既然你可以自由覆盖malloc,你怎么保证你不会丢失你对{{1}分配的内存块的引用}}?它非常简单,只需用另一个指针保存地址,例如

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

int main (void) {

    char *literal = "Hello world !";
    char *s = malloc(sizeof(char) * 5);
    char *p = s;
    if (!s) { 
        perror ("malloc - s"); 
        return 1; 
    }

    printf ("1. address of s : %p\n", s);

    s = literal;

    printf ("2. address of s : %p\n", s);

    printf ("3. address of p : %p\n", p);

    free (p);

    return 0;
}

示例使用/输出

$ ./bin/saddress3
1. address of s : 0x1a96010
2. address of s : 0x400745
3. address of p : 0x1a96010

您可以查看valgrind(或类似的内存错误检查程序),已释放所有内存并且没有内存错误。

如果您还有疑问,请询问。所有人都很乐意提供帮助。