【问题标题】:Why does writing to one more array member cause an issue? [duplicate]为什么写入另一个数组成员会导致问题? [复制]
【发布时间】:2021-02-17 14:15:57
【问题描述】:

以下代码似乎运行良好:

char **func()
{
    char **s = malloc(sizeof(char) * 5);
    
    s[0] = "1101";
    s[1] = "1001";
    s[2] = "0001";
    // s[3] = "1100";
    return s;
}

int main()
{
    char **s;
    s = func();
    printf("Hello World: %s", s[0]);
    free(s);

    return 0;
}

但如果我取消注释 s[3] = "1100"; 行,则会出现错误:

Error in `./a.out': free(): invalid next size (fast): 0x000000000259f010

为什么会这样,即使数组有足够的大小?

【问题讨论】:

  • sizeof(char) 应该是sizeof(char *)
  • sizeof(char) * 5 大小不正确。您可以通过使用推荐的样式 p = malloc(N * sizeof *p); 来避免这个问题。 stackoverflow.com/questions/605845
  • 如果mallocsizeof 的参数是一个类型,它的* 应该总是比你分配给的类型少一个。

标签: c string function pointers malloc


【解决方案1】:

在这里您为 5 chars 分配了足够的内存。

char **s = malloc(sizeof(char) * 5);

但是对于 5 个指向 char 的指针来说不是,它们更大。
让我们假设指针是四个字节(可能是 8...)。字符绝对是 1 个字节。

在这里,您正在写入该内存,大约 4 个字节(因为指针的大小,而不是因为四个字符)。
还不是问题。 s[0] = "1101";

在这里,您正在写入位于高 4 字节地址上的内存。
该地址本身还不是问题,它仍在分配的 5 个字节内。
但是,在那里写入大于一个字节的内容(您这样做,大小为 4)已经不正确。 s[1] = "1001";

这里更糟糕的是,在你得到的地址后面 8 个字节,在所有地址后面 3 个字节,总共 4 个字节。非常不正确。 s[2] = "0001";

您可能已经在第二次写入时遇到问题了。
第二次和第三次访问没有遇到问题纯属运气。好运或坏运,取决于您喜欢何时发现错误的理念。

要解决这个问题,请根据您正在编写的内容分配内存。引自 Barmar cmets:

sizeof(char) 应该是 sizeof(char *)
如果 malloc 中 sizeof 的参数是一个类型,它应该总是比你分配的类型少一个 *。

来自 Deduplicator(我其实也更喜欢这个):

我更希望看到 char** s = malloc(5 * sizeof *s);。不必编写类型使其不易出错。

不必键入类型的部分包括指针/星号数量的潜在错误部分。 IE。这种最佳做法可以避免您的问题。

【讨论】:

  • 我更愿意看到char** s = malloc(5 * sizeof *s);。不必编写类型使其不易出错。
  • @Deduplicator True。我想我可能看起来像是一个挑剔的人来改变那个细节,但在你的支持下,我很高兴能达到那个细节水平。谢谢。
【解决方案2】:

为什么会这样,即使数组有足够的大小?

添加一些代码来检查发生了什么。

char **func(){
    char **s = malloc(sizeof(char) * 5);
    
//    s[0] = "1101";
//    s[1] = "1001";
//    s[2] = "0001";
//    s[3] = "1100";

    printf("allocated : %zu bytes\n", sizeof(char) * 5);
    printf("used : %zu bytes\n", sizeof(s[0]) + sizeof(s[1]) + sizeof(s[2]) + sizeof(s[3]));
    printf("Is the allocated memory big enough?\n");
    return s;
}

https://godbolt.org/z/9aqYKb

allocated : 5 bytes
used : 32 bytes
Is the allocated memory big enough?

它回答了你的问题吗?

【讨论】:

    【解决方案3】:

    一个指针,在 64 位系统中,我猜是你的情况,通常是 8 字节大小,你的内存分配只为 5 chars 保留空间,这只有 5 个字节,这甚至不够一个指针,更不用说四个了。

    令我惊讶的是它在第一次或第二次作业中没有中断。

    实现这一点在很大程度上达成共识的方法是使用分配内存的指针的取消引用名称作为 sizeof 的参数,正是为了避免像您遇到的问题:

    char **s = malloc(sizeof *s * 4); //you have 4 pointers
    

    它不仅避免了错误,而且还使代码更易于维护。

    【讨论】:

      【解决方案4】:

      sizeof( char ) 始终等于1。所以在这个 malloc 调用中

      char **s = malloc(sizeof(char) * 5);
      

      您分配了 5 个字节的内存。

      但是您正在使用此内存范围来存储通常可以等于48 字节的指针,具体取决于使用的系统。

      因此,您正在访问超出分配范围的内存。因此,该程序具有未定义的行为。

      你需要的是写

      char **s = malloc(sizeof(char *) * 5);
      

      或者你可以写

      char **s = malloc(sizeof( *s ) * 5);
      

      【讨论】:

      • sizeof *s 代替
      • 有很多常用的系统(尽管现代桌面很少)指针更小...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-19
      • 1970-01-01
      • 1970-01-01
      • 2017-06-13
      • 2020-11-18
      • 2016-03-15
      相关资源
      最近更新 更多