【问题标题】:Why is heap corruption happening?为什么会发生堆损坏?
【发布时间】:2019-10-23 00:59:36
【问题描述】:

我一直在为学校做一些练习题,其中一个问题是,必须将输入的整数写入动态分配的字符串。代码在释放分配的内存(堆损坏发生)之前运行良好。

有人可以解释为什么会发生这种情况以及我做错了什么吗?

int main() {

  char *string = NULL;
  char **string2 = &string;

  Conversion(string2);
  printf("Entered number converted to string: %s", string);
  free(string);

  return 0;
}

int Conversion(char **string) {

    int num = 0, temp = 0, dcount = 0;
    printf("Enter number: ");
    scanf(" %d", &num);

    temp = num;

    while (temp != 0) {
      temp /= 10;
      dcount++;
    }

    *string = (char*)malloc(dcount*sizeof(char));
    if (*string == NULL) {
      printf("Error during memory allocation!");
      return -1;
    }

    sprintf(*string, "%d", num);

    return 0;
}

【问题讨论】:

  • 错误:1) 子函数:Conversion() 缺少原型,因此编译器将假定参数的类型和返回的类型,这可能(或可能不)正确。 2) 实际的子函数返回一个'int',表示调用malloc() 的失败/成功,但main() 中的调用未能检查返回值,3) 当malloc() 失败时,main() 函数仍然尝试将该 NULL 指针传递给 printf()

标签: c string pointers segmentation-fault dynamic-memory-allocation


【解决方案1】:

这个函数有几个缺点。

对于初学者,您不考虑分配字符串的终止零'\0'

其次,用户可以输入0 作为数字。在这种情况下,dcount 的值将不正确,因为循环

while (temp != 0) {
  temp /= 10;
  dcount++;
}

将被跳过。

第三,函数不能正确处理负数,允许用户输入负数。

此声明

char **string2 = &string;

是多余的。您可以通过以下方式调用该函数

Conversion( &string );

这不是要求用户输入数字的功能。该函数应该只完成一项任务:将整数转换为字符串。

还有一个功能设计缺陷。

从函数声明

int Conversion(char **string); 

(应该在函数main之前)不清楚用户应该为字符串提供内存还是为字符串分配内存的函数。

一个更好的函数界面可以如下面的演示程序所示。

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

char * Conversion( int x )
{
    const int Base = 10;

    size_t digits = x < 0 ? 1 : 0;

    int tmp = x;

    do
    {
        ++digits;
    } while ( tmp /= Base );

    char *s = malloc( digits + sizeof( ( char )'\0' ) );

    if ( s != NULL ) sprintf( s, "%d", x );

    return s;
}

int main( void )
{
    int num = 0;

    printf( "Enter a number: " );
    scanf( "%d", &num );

    char *s = Conversion( num );

    if ( s != NULL )
    {
        printf( "The entered number converted to string: %s\n", s );
    }
    else
    {
        puts( "A conversion error ocured." );
    }

    free( s );
}

它的输出可能如下所示

Enter a number: -12
The entered number converted to string: -12

考虑到根据 C 标准,不带参数的函数 main 应声明为

int main( void )

【讨论】:

  • 这只是一段代码,其中包含呈现我遇到的问题所需的部分:) 我在自定义标头中声明了 AI 使用的所有内容。但是谢谢你的回答。在你的和上面的之间,我学到了很多,比我预期的要多得多!
【解决方案2】:

您需要分配一个额外的字符来说明\0 终止符。

*string = (char*)malloc((dcount + 1) * sizeof(char));

如果num 为0 或负数,dcount 也是不正确的。

其他cmets:

  • 你可以use snprintf() to calculate the needed buffer size。它将为您省去计算num 中数字的所有繁重工作,而且它还能正确处理所有边缘情况。

    int dcount = snprintf(NULL, 0, "%d", num);
    
  • 你应该avoid casting malloc's return value

    *string = malloc((dcount + 1) * sizeof(char));
    
  • sizeof(char) 被定义为 1。我会省略乘法

    *string = malloc(dcount + 1);
    

    但是,如果你真的离开了,avoid hard coding the item type

    *string = malloc((dcount + 1) * sizeof(**string));
    

    如果您将字符串从 char* 更改为 char16_t*/char32_t*/wchar_t*,这将自动调整,而 sizeof(char) 将编译而不会出错,尽管类型不匹配。

【讨论】:

  • 噢! UI 知道这将是一件非常明显的事情,就像往常一样。感谢您的宝贵时间,尤其是所有额外的 cmets。 snprintf() 将来会非常有用。这也是关于 malloc 转换的有趣读物,因为我们在课堂上被告知我们需要自己转换它,因为它返回一个 void 指针。
猜你喜欢
  • 1970-01-01
  • 2015-01-01
  • 1970-01-01
  • 2013-11-24
  • 2019-10-13
  • 2021-12-11
  • 2010-10-31
  • 2015-03-14
  • 1970-01-01
相关资源
最近更新 更多