首页 > 解决方案 > 为什么这个结构需要比 sizeof 本身更多的分配空间?

问题描述

我对 C 中的动态内存有点陌生,到目前为止我已经设法更好地理解它,但我正在尝试为这个结构分配内存,它应该是 24 字节长,但保留 24 字节不起作用,我必须分配 29 个字节或更多才能使其工作,我不明白这个的确切原因。

我正在尝试创建一个函数来初始化 tInfection,并且我正在为 tInfection tInfectiousAgent* 指针分配内存object->tInfectiousAgent = (tnfectiousAgent*) malloc(sizeof(tInfectiousAgent));

在此处输入图像描述

这是调试器信息,据我所知,如果不能分配其数据,malloc 会返回 NULL 指针吗?但在这里它不返回 NULL 指针。

这是2个结构

在此处输入图像描述

在此处输入图像描述

tError infection_init(tInfection* object, tInfectiousAgent* infectiousAgent, const char* country,  tDate* date, int cases, int deaths){

    // We check pre conditions
    assert(object != NULL);
    assert(infectiousAgent != NULL);
    assert(country != NULL);
    assert(date != NULL);

    // We allocate memory
    object->infectiousAgent = (tInfectiousAgent*) malloc(sizeof(tInfectiousAgent));
    object->country = (char*) malloc(sizeof(char) * (strlen(country) + 1));
    object->date = (tDate*) malloc(sizeof(tDate));


    // We check that memory was allocated correctly
    if ((object->country == NULL) || (object->date == NULL) || (object->infectiousAgent == NULL)) {
            return ERR_MEMORY_ERROR;
    }


    //infectiousAgent_cpy(object->infectiousAgent, infectiousAgent);
    strcpy(object->country, country);
    strcpy(object->date, date);
    object->cases = cases;
    object->deaths = deaths;



    return OK;
}

标签: cmemorydynamicmalloc

解决方案


您是否分配足够的空间不是这里的问题。如果您使用sizeof,一切都应该正常工作。

顺便说一句,如果您提供错误的尺寸,malloc也不会失败,因为它无法知道正确的尺寸是多少。它只能使用你给它的东西,对错。如果您在界限之外读取或写入,错误的大小通常会导致问题出现,但那是在成功之后。malloc

潜在问题是您的调试器中的r0,medium和的值date3.09456111e+35浮点数的值r0存储为 IEEE754 单精度十六进制字节{7a,6e,65,75}(请参阅此处了解让我辨别的有用工具)。medium变量是{33,48,20,61},变量date{32,4e}

如果您应用英特尔小端调整,您最终得到的字节序列是(如下所示为十六进制转储,包括 ASCII 字符):

      +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +0123456789
0000  75 65 6e 7a 61 20 48 33 4e 32  uenza H3N2

鉴于您在谈论传染性病原体,那几乎可以肯定是字符串的一部分Influenza H3N2,是许多流感病毒株之一。浮点数、指针和其他非字符串的东西可能包含看起来像文本的东西,但是三个连续的变量在它们之间都有一个连贯的字符串这一事实,以及指针值不是有效地址的事实,强烈暗示了损坏。

这意味着您正在执行类似将该字符串直接复制到指针所在的空间中的操作,因此可能会在某处溢出一些缓冲区。造成这种情况的一个潜在原因可能是strcpy(object->date, date),除非tDate是与 C 样式字符串兼容的类型( 的定义tDate将有助于确定这是否是问题所在)。

你的论点也支持这一点,即使结构应该是 24 字节长,除非你分配 29 字节,否则会发生奇怪的事情。这是一个明显的迹象,表明某些东西正在超出其应有的范围,并且很可能会破坏内存领域。

我不确定根本原因,因为您没有提供所有可以让我们确定这一点的代码,但根据我们可以看到的证据,这是一个不错的选择。


还有一件事需要注意,比如:

assert(object != NULL);

实际上,如果定义了 when是没有效果的。NDEBUGassert.h

通常,该宏不是为调试版本定义的,而是发布版本定义的(当然,这取决于您的构建系统)。

这意味着您不能将assert其用作通用合同保护,因为发布版本会将其转换assert为空操作。因此,如果断言可以基于运行时数据为真或假,assert则可能不是该工作的好工具(如果它仅基于编译时数据,那么您将在测试期间捕获所有断言)。


推荐阅读