Filthy-ice 发表于 2023-4-25 21:11:43

关于realloc再循环体内,第一次开辟成功,第二次失败的问题

void BSTreeDATAPush(BSTree* T)
{
    int chose;//用来限制循环体
    do
    {

      if(DATAsub == num)
      {
            num = num+4;
            BSTData* tmp = (BSTData*)realloc(T->DATA,sizeof(BSTData)*num);
            if(!tmp)
            {
                printf("%s\n",strerror(errno));
                exit(-1);
            }
            T->DATA = tmp;
            free(tmp);
            tmp = NULL;
      }
      printf("请插入数据:>");
      scanf("%d",&(T->DATA));
      rewind(stdin);
      DATAsub++;
      printf("是否继续插入结点数据? 1.继续 0.退出 :>");
      scanf("%d",&chose);
      rewind(stdin);
      //以上是仅存放需排序的无序数组信息。
    } while (chose);
    printf("结点数据录入结束。\n");
    return ;
}
两个全局变量,num是专门用来开辟数组空间的变量;Datasub是数组的下标.
函数是我输入需要排序的数组用的,输入完数据它的值应该是和数组内存放的数据量是相同的。初始化接口里,已经开辟了4个int大小,在我输入第五个数据的时候,realloc没有提示出错。当第二次,也就是下标为8的时候,vscode提示分段错误。
也就是sub = 8; num = 12时,提示分段错误,还不是error报的……
我瞅了半天,也没见哪里有非法访问。      有没大佬解读一下?

sfqxx 发表于 2023-4-25 21:13:53

根据给出的代码,问题可能在realloc和free的使用上。重点如下:

- realloc函数返回的是一个指针,该指针指向重新分配大小后的空间。所以这里需要将 realloc 的返回值赋值给 tmp,而不是 BSTData* 类型的 T->DATA。
- 在进行 realloc 调用之后,我们无需再次释放旧内存块,因为 realloc 函数已经执行了此操作。
- 需要仔细检查调用realloc之前数据数组 DATA 中的所有访问是否都在有效范围内。这也是引起段错误的一种常见原因。

请看修改后的代码:


void BSTreeDATAPush(BSTree* T)
{
    int chose;//用来限制循环体
    do
    {
      if(DATAsub == num) {
            num = num+4;
            BSTData* tmp = (BSTData*)realloc(T->DATA,sizeof(BSTData)*num);
            if(!tmp) {
                printf("%s\n",strerror(errno));
                exit(-1);
            }
            T->DATA = tmp; // 此处将 realloc 函数返回值赋值给 T->DATA
      }

      printf("请插入数据:>");
      scanf("%d",&(T->DATA));
      rewind(stdin);
      DATAsub++;
      printf("是否继续插入结点数据? 1.继续 0.退出 :>");
      scanf("%d",&chose);
      rewind(stdin);
      //以上是仅存放需排序的无序数组信息。
    } while (chose);
    printf("结点数据录入结束。\n");
    return ;
}

isdkz 发表于 2023-4-25 21:14:37

您的代码存在一个错误,这可能是导致问题的原因。在执行 `realloc` 后,您立即调用了 `free(tmp);`。这样做会释放刚刚重新分配的内存,而您实际上还需要使用它。将 `free(tmp);` 这一行删除,问题应该会得到解决。此外,由于不再需要释放 `tmp`,您也可以将 `tmp = NULL;` 这一行删除。

修改后的代码如下:

void BSTreeDATAPush(BSTree* T)
{
    int chose;//用来限制循环体
    do
    {

      if(DATAsub == num)
      {
            num = num+4;
            BSTData* tmp = (BSTData*)realloc(T->DATA,sizeof(BSTData)*num);
            if(!tmp)
            {
                printf("%s\n",strerror(errno));
                exit(-1);
            }
            T->DATA = tmp;
            // 删除以下两行
            // free(tmp);
            // tmp = NULL;
      }
      printf("请插入数据:>");
      scanf("%d",&(T->DATA));
      rewind(stdin);
      DATAsub++;
      printf("是否继续插入结点数据? 1.继续 0.退出 :>");
      scanf("%d",&chose);
      rewind(stdin);
      //以上是仅存放需排序的无序数组信息。
    } while (chose);
    printf("结点数据录入结束。\n");
    return ;
}


这样修改后,您的代码应该可以正常工作。

Filthy-ice 发表于 2023-4-25 21:19:19

isdkz 发表于 2023-4-25 21:14
您的代码存在一个错误,这可能是导致问题的原因。在执行 `realloc` 后,您立即调用了 `free(tmp);`。这样做 ...

谢谢,代码可以跑了,但是不释放会造成内存泄漏吧?

isdkz 发表于 2023-4-25 21:21:00

Filthy-ice 发表于 2023-4-25 21:19
谢谢,代码可以跑了,但是不释放会造成内存泄漏吧?

不需要担心内存泄漏。在您的示例代码中,realloc用于重新分配内存。当realloc成功时,它会自动处理原始内存块的释放。所以,在这种情况下,您不需要手动释放原始内存块。

当realloc返回新的内存地址时,它已经在内部处理了原始内存块的释放,所以您只需关心新返回的内存地址。在这种情况下,手动释放tmp实际上是错误的,因为它会释放已经重新分配给T->DATA的内存。

一般来说,您需要在程序结束时或不再需要这些内存时手动释放内存。在这个例子中,当您不再需要T->DATA时,您应该调用`free(T->DATA);`来释放内存。这通常发生在程序结束前的某个地方,或者在您不再需要BSTree结构时。

Filthy-ice 发表于 2023-4-25 21:23:39

sfqxx 发表于 2023-4-25 21:13
根据给出的代码,问题可能在realloc和free的使用上。重点如下:

- realloc函数返回的是一个指针,该指针 ...

明白了,学蒙了,是开辟的数组不再使用时需要释放。谢谢答疑。

sfqxx 发表于 2023-4-25 21:23:58

Filthy-ice 发表于 2023-4-25 21:23
明白了,学蒙了,是开辟的数组不再使用时需要释放。谢谢答疑。

最佳绝缘体{:10_266:}
页: [1]
查看完整版本: 关于realloc再循环体内,第一次开辟成功,第二次失败的问题