C 为什么会发生堆损坏?

C 为什么会发生堆损坏?,c,string,pointers,segmentation-fault,dynamic-memory-allocation,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", strin

我一直在为学校做一些练习题,在其中一个练习题中,输入的整数必须写入一个动态分配的字符串。在释放分配的内存之前,代码可以很好地完成它的工作,而此时会发生堆损坏

有人能解释一下为什么会这样,我做错了什么吗

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

您需要为
\0
终止符分配一个额外字符

*string = (char*)malloc((dcount + 1) * sizeof(char));
如果
num
为0或负值,则
dcount
也不正确

其他意见:

  • 你可以。它将为您节省在
    num
    中计算数字的所有繁重工作,并且它将正确处理所有边缘情况

    int dcount = snprintf(NULL, 0, "%d", num);
    
  • 你应该

  • sizeof(char)
    定义为1。我会省略乘法运算

    *string = malloc(dcount + 1);
    
    然而,如果你真的离开了它

    如果将字符串从
    char*
    更改为
    char16\u t*
    /
    char32\u t*
    /
    wchar\u t*
    这将自动调整,而
    sizeof(char)
    尽管类型不匹配,但编译时不会出错


您需要为
\0
终止符分配一个额外字符

*string = (char*)malloc((dcount + 1) * sizeof(char));
如果
num
为0或负值,则
dcount
也不正确

其他意见:

  • 你可以。它将为您节省在
    num
    中计算数字的所有繁重工作,并且它将正确处理所有边缘情况

    int dcount = snprintf(NULL, 0, "%d", num);
    
  • 你应该

  • sizeof(char)
    定义为1。我会省略乘法运算

    *string = malloc(dcount + 1);
    
    然而,如果你真的离开了它

    如果将字符串从
    char*
    更改为
    char16\u t*
    /
    char32\u t*
    /
    wchar\u t*
    这将自动调整,而
    sizeof(char)
    尽管类型不匹配,但编译时不会出错


该功能有几个缺点

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

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

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

第三,该函数无法正确处理负数,允许用户输入负数

本声明

char **string2 = &string;
int Conversion(char **string); 
这是多余的。您可以按以下方式调用该函数

Conversion( &string );
Enter a number: -12
The entered number converted to string: -12
它不是要求用户输入数字的函数。该函数只应执行一项任务:将整数转换为字符串

还有一个功能设计缺陷

从函数声明中

char **string2 = &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 );
}
考虑到根据C标准,不带参数的功能
main
应声明如下

int main( void )

该功能有几个缺点

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

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

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

第三,该函数无法正确处理负数,允许用户输入负数

本声明

char **string2 = &string;
int Conversion(char **string); 
这是多余的。您可以按以下方式调用该函数

Conversion( &string );
Enter a number: -12
The entered number converted to string: -12
它不是要求用户输入数字的函数。该函数只应执行一项任务:将整数转换为字符串

还有一个功能设计缺陷

从函数声明中

char **string2 = &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 );
}
考虑到根据C标准,不带参数的功能
main
应声明如下

int main( void )

啊!我知道这将是一件愚蠢的显而易见的事情,就像往常一样。谢谢你的时间,特别是所有额外的评论。snprintf()将在将来非常有用。这也是一篇关于malloc转换的有趣文章,因为我们在课堂上被告知,我们需要自己转换它,因为它返回一个空指针。Doh!我知道这将是一件愚蠢的显而易见的事情,就像往常一样。谢谢你的时间,特别是所有额外的评论。snprintf()将在将来非常有用。这也是一篇关于malloc强制转换的有趣阅读,因为我们在课堂上被告知,我们需要自己强制转换它,因为它返回一个空指针。这只是一段代码片段,其中包含了表示我遇到的问题所需的部分:)我在自定义头中声明AI使用的所有内容。但是谢谢你的回答。在你的和上面的一个之间,我学到了很多,比我从我的问题中得到的要多得多!这只是一段代码片段,其中包含表示我遇到的问题所需的部分:)我在自定义头中声明AI使用的所有内容。但是谢谢你的回答。在你的和上面的一个之间,我学到了很多,比我从我的问题中得到的要多得多!错误:1)子函数:
Conversion()
缺少原型,因此编译器将假定参数的类型和返回的类型可能正确(也可能不正确)。2) 实际子函数返回一个“int”,表示调用
malloc()
失败/成功,但
main()
中的调用在
mal>时无法检查返回的值