【问题标题】:C Language - Malloc unlimited space?C 语言 - Malloc 无限空间?
【发布时间】:2011-12-04 07:59:46
【问题描述】:

我在学习 C 语言的 malloc 和指针时遇到了困难:

到目前为止我学到了什么:

  • 指针是内存地址指针。

  • malloc()分配内存位置并返回内存地址。

我正在尝试创建一个程序来测试malloc 和指针,这就是我所拥有的:

#include<stdio.h>

main()
{
char *x;
x = malloc(sizeof(char) * 5);

strcpy(*x, "123456");
printf("%s",*x); //Prints 123456

}

我预计会出现错误,因为我提供给malloc 的大小是 5,我将 6 个字符 (123456) 放入指针指向的内存位置。这里发生了什么?请帮帮我。

更新

在哪里学习malloc和指针?我对星号的东西感到困惑,比如什么时候使用星号等。在我学会这个东西之前我不会休息!谢谢!

【问题讨论】:

    标签: c malloc


    【解决方案1】:

    您正在调用未定义的行为,因为您正在写入(或尝试写入)超出分配内存的范围。

    其他挑剔:

    • 因为您使用的是strcpy(),所以您复制的是 7 个字节,而不是您在问题中声称的 6 个字节。
    • 您对 strcpy() 的调用存在缺陷 - 您传递的是 char 而不是指向 char 的指针作为第一个参数。
    • 如果您的编译器没有报错,则说明您没有使用足够的警告选项。如果您使用 GCC,您的编译器命令行中至少需要 -Wall
    • 您需要同时包含 &lt;stdlib.h&gt; 用于 malloc()&lt;string.h&gt; 用于 strcpy()
    • 您还应该明确指定int main()(或者,更好的是int main(void))。
    • 就个人而言,我已经够老了,我更喜欢在 main() 的末尾看到明确的 return(0);,即使 C99 遵循 C++98 并允许您省略它。

    您可能很不走运并且暂时无法调用未定义的行为,但是像valgrind 这样的工具应该指出您的方式错误。在实践中,malloc() 的许多实现分配了 8 个字节的倍数(以及一些 16 字节的倍数),并且考虑到您小心翼翼地不跨过 8 字节分配,您实际上可能会侥幸逃脱。但是好的调试malloc()valgrind 会指出你做错了。

    请注意,由于您在从main() 返回之前没有free() 分配的空间,因此您(在这种情况下相对无害)泄漏它。还要注意,如果你复制的字符串更长(比如字母表一样长),特别是如果你试图free()你分配的内存,或者在第一个结束后试图分配其他内存块,那么你更有可能看到您的代码崩溃。

    未定义的行为是无条件的坏。什么事情都可能发生。不需要任何系统来诊断它。避免它!

    【讨论】:

    • 先生,我也试过malloc(1),并分配“123456”,仍然没有错误。
    • 是的 - 因为malloc(1) 可能分配了 8 个字节......而你没有调用 free()。将字符串更改为"abcdefghijklmnopqrstuvwxyz" 并添加free(),您很可能会看到它崩溃并烧毁。然而,关于未定义行为的可怕之处在于,程序似乎可以使用它很长一段时间——然后突然间你发现了一些让它们崩溃的东西(一个新平台、一个新编译器、某个地方的额外函数调用,.. .).
    【解决方案2】:

    如果您调用 malloc,您将获得并寻址堆上的内存区域。 如果它返回例如1000 你的记忆应该是这样的:

    Adr  Value
    ----------
    1000 1
    1001 2
    1002 3
    1003 4
    1004 5
    1005 6
    1006 0
    

    在调用 strcpy() 之后。你写了 7 个字符(比分配的多 2 个)。

    x == 1000(指针地址)

    *x == 1(取消引用 x 指向的值)

    编译器没有警告或错误消息,因为 C 没有任何范围检查。

    【讨论】:

      【解决方案3】:

      我的三分钱:

      1. 使用 x,因为 (*x) 是存储在 x 处的值(在您的情况下是未知的) - 您正在写入未知的内存位置。应该是:

        strcpy(x, "123456");

      2. 其次 - “123456”不是 6 个字节,而是 7 个字节。您忘记了尾随零终止符。

      3. 使用当前代码的程序可能可以工作,但不能保证。

      我会做什么:

      #include<stdio.h>
      
      main()
      {
          char str[] = "123456";
          char *x;
          x = malloc(sizeof(str));
      
          strcpy(x, str);
          printf("%s",x); //Prints 123456
      
          free(x);
      }
      

      【讨论】:

      • 您没有崩溃,因为在未知内存位置写入是“未定义的行为”。
      【解决方案4】:

      首先,你的代码有一个问题:

      x 是指向您为 5 个字符分配空间的内存区域的指针。 *x 它是第一个字符的值。 你应该使用 strcpy(x, "123456");

      其次,分配5个字节后的内存是有效的,所以你不会收到错误。

      【讨论】:

        【解决方案5】:
        #include<stdio.h>
        
        main()
        {
        char *x;
        x = malloc(sizeof(char) * 5);
        
        strcpy(x, "123456");
        printf("%s",x); //Prints 123456
        
        }
        

        使用这个...它会工作

        查看您和我的计划的不同之处

        现在您在这里分配 5 个字节并写入 6 个字节,因此 第 6 个字节将存储在下一个连续地址中。这个额外的字节可以通过内存管理分配给其他人,所以任何时候这个额外的字节都可以被其他程序更改,因为第 6 个字节不是你的,因为你还没有 malloc'd ......这就是为什么称为未定义的行为

        【讨论】:

        • 我以为x是用来访问地址容器的内容,而*x是用来访问我的指针指向的内存位置的内容。
        • 你是对的,但是看到 strcpy 的语法,其中第一个参数是指向字符的指针。
        • “当你释放这个内存时它会给你分段错误”你确定吗?你在谈论免费(x)吗?
        • 很抱歉这种情况下不会出现分段错误
        • 首先,复制了 7 个字节,因为 strcpy() 在字符串末尾包含空字节。额外的空间可以分配给当前程序的其他部分;在任何主流操作系统上,它都不可能属于另一个程序(进程)。字节可能随时更改,因为该程序的另一部分写入“其内存”。
        猜你喜欢
        • 2012-01-19
        • 2015-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-04
        • 1970-01-01
        • 2011-04-22
        相关资源
        最近更新 更多