为什么会发生堆损坏?

时间:2019-06-07 13:54:03

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

我一直在研究学校的一些练习题,其中之一是必须将输入的整数写到动态分配的字符串中。该代码可以正常工作,直到释放分配的内存(发生堆损坏)为止。

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

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;
}

2 个答案:

答案 0 :(得分:5)

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

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

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

其他评论:

  • 您可以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)会在没有错误的情况下进行编译不匹配。

答案 1 :(得分:2)

该功能有几个缺点。

对于初学者,您无需考虑分配的字符串的终止零'\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 )