【问题标题】:Malloc vs character arrays of a specific sizeMalloc 与特定大小的字符数组
【发布时间】:2012-01-18 15:54:34
【问题描述】:

首先我对 C 很陌生,所以我可能只是在这里有一个基本的误解。给定如下代码:

int main()
{
    char ack[100];
    char *bar;
    bar = malloc(100);
    strncpy(ack, "testing", 7);    
    bar = "testing";

    return 0;
}

ack 被 gdb 检查时看起来像这样:

(gdb) p ack
$1 = "testing\000\360WV\000\000\000\000\000\277\000\000\000\000\000\000      
'\000'\000\220\005@",<repeats 13 times>, "\003\004@", '\000' <repeats 13 times>    
"\325,\005@\000\000\000\000\000H\214\246\367\377\177\000\000\220\005@",
'\000' <repeats 13 times>,     "P\004@\000\000\000\000\000\360\342\377\377"` 

考虑到我如何初始化ack,这对我来说很有意义。我不太明白为什么bar 看起来像这样:

(gdb) p bar
$2 = 0x40066c "testing"

我分配的存储量(据我所知)与我为 ack 请求空间时所做的相同,但 malloc 没有多余的垃圾。据我了解, malloc 不做任何类型的数据初始化或任何事情,所以我有点困惑。出现这种情况的原因是我在使用 strstr 时遇到的问题。基本上,当我从文件(fgets)中读取数据到具有特定大小 strstr() 的 char 数组时会失败(我假设这是因为额外的垃圾)。使用指针和 malloc 的内存工作得很好。无论如何,我有几个具体的问题。

  1. 这个 malloc 变量的行为是预期的吗?这里是否进行了一些优化(我使用 gcc 编译,但没有进行任何优化)或者 gdb 没有向我显示所有内容?该变量是否应该存在“垃圾”?

  2. 我是否正确使用了 malloc?我应该初始化我请求的所有内存吗?如果有,怎么做?

谢谢!

编辑

感谢所有回复的人!我从你们那里学到了很多东西,非常感谢。我现在看到了我上面发布的代码的问题,以及我在使用 fgets() 和 strstr() 时遇到的原始问题。

【问题讨论】:

  • 内存在分配时未填充空值。为此,请使用 memset(..)
  • @Adrian,不,不,不。这是C。不要投射malloc(),也不要教C 的新手这样做。
  • @DanFego 我也在学习我猜哈哈。我一直在投射mallocs。谢谢(你的)信息。我已经编辑了我的评论!
  • @Adrian 抱歉大喊大叫!我只是看到这里有这么多人建议,我不想认为我们也在教初学者这样做。 :P
  • @Adrian: Pre-C89,malloc 返回char *,所以在那个时候演员表是必要的,当然任何教程或参考资料都会显示出来。在 C89 中,malloc 更改为返回 void *,它可以隐式转换为任何对象指针类型,因此现在强制转换是多余的(实际上可能隐藏错误)。不幸的是,许多旧的参考资料没有更新以反映这种变化,而且这种做法一直存在。

标签: c


【解决方案1】:
bar = "testing";

重新分配指针 bar 指向一个包含字符串 "testing" 的静态缓冲区,即它不再指向您的 malloc'd 数组。这是memory leak

要将字符串放入malloc'd 缓冲区,请使用strcpystrncpymemcpy,就像使用ack 一样。

【讨论】:

    【解决方案2】:

    这是因为您在分配时(无意中)丢弃了malloced 内存

    bar = "testing";
    

    这使得bar 指向字符串文字,而不是指向(泄露的)malloced 内存。

    【讨论】:

    • 嗯,throw away 有意图的含义,所以forget about 的重点。另一方面,forget about 对于内存泄漏来说听起来不够戏剧化。我妥协了。
    • 完美!我们也会接受“丢失”、“泄漏”、“丢弃”、“忽略”和“抛弃为太空垃圾”。
    【解决方案3】:

    你在几点上偏离了。

    首先,ack 在打印时“测试”后出现垃圾的原因是因为您从未以 NULL 终止它。在C 中,所有字符串都必须以NULL 结尾,即以\0 结尾。您可以在此处通过调用长度为 8 的 strncpy() (strlen("testing") + 1) or just usingstrcpy() 来解决此问题。

    其次,bargdb 中看起来不同,因为它是一个指向char 的指针,而ack 是一个直接向上的char 数组。 gdb 向您显示 bar 的指针值,但如果可以的话,您还可以向您显示该指针另一侧的内容,如您所见。当您执行bar = "testing;" 时,您正在将bar 指向的内容重新分配给内存中包含“测试”的字符数组。当您使用这样的字符串文字时,它会自动在末尾有一个 \0 字符,因此以 NULL 结尾,因此之后没有垃圾。

    【讨论】:

      【解决方案4】:

      C 字符串有一个空终止符(ascii 字符值为零),因此 C 字符串“测试”实际上是 8 个字节长,包括终止符。

      当您打印原始值时,它会在到达终止符时停止打印。

      但是因为你只复制了前 7 个字符,所以当你打印第二个值时,它会一直打印垃圾,直到它在之前的垃圾数据中达到零。

      【讨论】:

      • 再一次,也许这是丹尼尔的解释 ;-) 虽然技术上是正确的,但我认为我不应该投反对票。
      猜你喜欢
      • 2016-01-22
      • 1970-01-01
      • 2021-07-24
      • 2021-05-05
      • 2020-10-18
      • 2012-07-23
      • 2019-11-17
      • 2014-09-14
      • 1970-01-01
      相关资源
      最近更新 更多