【问题标题】:SegFault while using Malloc/Realloc on an uninitialized pointer在未初始化的指针上使用 Malloc/Realloc 时出现 SegFault
【发布时间】:2020-06-11 09:17:53
【问题描述】:

我正在开发一个“轻型无人机模拟器”(C 语言),我的任务之一是在左键单击地图时添加一个静态目标。到现在为止还挺好。 问题是,我不想创建一个给定大小的矩阵作为全局变量,而是从一个未初始化的指针指针开始,只要我左键单击,我就会重新分配新内存,以便始终有足够的可用内存但不多.我的“矩阵”也应该有 4 列用于 3D 坐标,1 列用于“激活”。

这是我的代码的一部分:

/* Main program */

double **TargetsArray;

int main(int argc, char *argv[]) {

/* Call of model-specific mouse handling function */
   HandleSpecialMouseEvent(button, state, x, y, &ActualFlockingParams,
            &ActualVizParams, TargetPosition, TargetsArray, Modder);
}
void HandleSpecialMouseEvent(int button,
        int state,
        int x,
        int y,
        flocking_model_params_t * FlockingParams,
        vizmode_params_t * VizParams, 
        double * CoordTarg, double ** TargetsArray,
        const int Modifier) {

       static int cnt = 0;

       if (button == GLUT_LEFT && state == GLUT_DOWN && Modifier == GLUT_ACTIVE_ALT) {
            FillVect(CoordTarg, MouseCoordToReal_2D(x, VizParams->MapSizeXY,
                    VizParams->Resolution) + VizParams->CenterX, -MouseCoordToReal_2D(y, VizParams->MapSizeXY,
                    VizParams->Resolution) + VizParams->CenterY, 0);
            printf("%d\n", cnt);

            if (cnt == 0) {

                TargetsArray = malloc( sizeof *TargetsArray );
                TargetsArray[cnt] = malloc( sizeof **TargetsArray * 4);
                printf("Hello");
                TargetsArray[cnt][0] = CoordTarg[0];
                TargetsArray[cnt][1] = CoordTarg[1];
                TargetsArray[cnt][2] = 0;
                TargetsArray[cnt][3] = 1;

                cnt += 1;
            }
            else {
                printf("Youhou");
                TargetsArray = realloc(TargetsArray, sizeof *TargetsArray * (cnt + 1) );
                TargetsArray[cnt] = malloc( sizeof **TargetsArray * 4);
                TargetsArray[cnt][0] = CoordTarg[0];
                TargetsArray[cnt][1] = CoordTarg[1];
                TargetsArray[cnt][2] = 0;
                TargetsArray[cnt][3] = 1;
                TargetsArray[cnt - 1][3] = 0;

                cnt += 1;

            }

            // for (int j = 0; j < cnt; j++) {
            //     for (int i = 0; i < 4; i++) {
            //         printf("%f\t", TargetsArray[j][i]);
            //     }
            //     printf("\n");
            // }
        }


}

我通常会遇到两种类型的错误:

0
Hello1
Youhou2
Erreur de segmentation (core dumped)

OR 

0
Hello1
free(): invalid next size (fast)
Abandon (core dumped)

我知道有更简单的方法可以做到这一点,但我真的很想了解为什么这不起作用。我很确定这是由于我使用 mallocrealloc 的方式,但我也不明白为什么在第一个“循环”中程序没有运行进入if语句,而它确实打印“0”,然后为什么在打印计数器(cnt)之前打印“Hello”?

我希望我提供了足够的代码让您理解我的问题,但如果缺少某些内容,请告诉我。

谢谢!!

【问题讨论】:

  • 标题说“在未初始化的指针上使用 Malloc/Realloc”。为什么不初始化呢?初始化变量(所有变量,尤其是那些在首次写入之前可能或保证使用的变量)通常是一个好主意。
  • realloc 将无法使用未初始化的指针。将其设置为NULL
  • @Yunnosch 我的目标是在我第一次使用“左键单击”功能时对其进行初始化,因为我可能根本不需要它。
  • 每次离开函数时,TargetsArray 的值都会被丢弃。是函数参数,分配的指针不是函数返回的值。
  • 你怎么看?函数参数double ** TargetsArrayTargetsArray = malloc( sizeof *TargetsArray );覆盖

标签: c pointers malloc realloc


【解决方案1】:

您需要更改函数的参数TargetsArray,使其指向全局变量,而不仅仅是存储相同的值。

主程序:

double **TargetsArray;

int main(int argc, char *argv[]) {

/* Call of model-specific mouse handling function */
   HandleSpecialMouseEvent(button, state, x, y, &ActualFlockingParams,
            &ActualVizParams, TargetPosition, &TargetsArray, Modder);
}
void HandleSpecialMouseEvent(int button,
        int state,
        int x,
        int y,
        flocking_model_params_t * FlockingParams,
        vizmode_params_t * VizParams, 
        double * CoordTarg, double *** TargetsArray,
        const int Modifier) {

       static int cnt = 0;

       if (button == GLUT_LEFT && state == GLUT_DOWN && Modifier == GLUT_ACTIVE_ALT) {
            FillVect(CoordTarg, MouseCoordToReal_2D(x, VizParams->MapSizeXY,
                    VizParams->Resolution) + VizParams->CenterX, -MouseCoordToReal_2D(y, VizParams->MapSizeXY,
                    VizParams->Resolution) + VizParams->CenterY, 0);
            printf("%d\n", cnt);

            if (cnt == 0) {

                *TargetsArray = malloc( sizeof **TargetsArray );
                (*TargetsArray)[cnt] = malloc( sizeof ***TargetsArray * 4);
                printf("Hello\n");
                (*TargetsArray)[cnt][0] = CoordTarg[0];
                (*TargetsArray)[cnt][1] = CoordTarg[1];
                (*TargetsArray)[cnt][2] = 0;
                (*TargetsArray)[cnt][3] = 1;

                cnt += 1;
            }
            else {
                printf("Youhou");
                *TargetsArray = realloc(*TargetsArray, sizeof **TargetsArray * (cnt + 1) );
                (*TargetsArray)[cnt] = malloc( sizeof ***TargetsArray * 4);
                (*TargetsArray)[cnt][0] = CoordTarg[0];
                (*TargetsArray)[cnt][1] = CoordTarg[1];
                (*TargetsArray)[cnt][2] = 0;
                (*TargetsArray)[cnt][3] = 1;
                (*TargetsArray)[cnt - 1][3] = 0;

                cnt += 1;

            }

            // for (int j = 0; j < cnt; j++) {
            //     for (int i = 0; i < 4; i++) {
            //         printf("%f\t", *TargetsArray[j][i]);
            //     }
            //     printf("\n");
            // }
        }


}

注意:括号很重要

每次重新分配内存时,都会在TargetsArray 中存储一个新的内存地址。由于您要更改函数内部的值,因此您需要为函数提供变量TargetsArray 的地址。其他方式你只会将重新分配的地址存储在函数的本地TargetsArray

【讨论】:

    【解决方案2】:

    有关 malloc 和 realloc 的行,请检查您要求的内存是否可用并且可以分配,如果出现错误,两者都会返回 NULL

    只需检查是否有足够的内存,并且可以为两个 alloc 调用分配内存,如下所示:

    TargetsArray = malloc( sizeof *TargetsArray );
    if(TargetsArray  == NULL){
    //oh! not enough mem, or whatever...
    }
    //...
    void* TargetsArray_ra = realloc(TargetsArray, sizeof(*TargetsArray) * (cnt + 1) );
    if(TargetsArray_ra == NULL){
    //oh! could not realloc
    //if you wish to return, don't forget to free up the TargetsArray 
    if(TargetsArray != NULL){free(TargetsArray);TargetsArray=NULL;}
    //return;
    }else{//when realloc was success
    TargetsArray = TargetsArray_ra ;
    }
    

    TargetsArray[cnt] = malloc( sizeof **TargetsArray * 4); 进行相同检查,确保在访问之前它采用正确的非NULL ptr

    除了最后一条语句之外,那些 if-else 块也是一样的,除此之外,当您调试代码时,您会在哪一行出现段错误? 您确定传递的CoordTarg 不是NULL,并且长度合适吗? FillVect 函数呢?它按预期工作?

    【讨论】:

    • 感谢您的回答。我得到了 realloc 的段错误,第一个 malloc 已通过,但我什至不确定它是否被考虑在内。 CoordTarg 不是空的或NULLFillVect 工作正常所以我知道问题是由于这个malloc/realloc。另外我的目标是主要填充这个全局TargetsArray,以跟踪以前使用的位置
    • 这是嵌入式应用吗?你的环境是什么?使用我提供的示例代码,检查realloc 返回什么?使用调试器找出导致段错误的确切行
    • 这不是嵌入式应用程序,我在 Linux Visual Studio 上并使用 C 和 OpenGL。这部分实际上是OpenGL循环的一部分。我尝试了您的代码,但仍然遇到与程序试图释放一些内存相同的问题。奇怪的是,当我在模拟器上移动鼠标太多时,经常会发生错误。当我在调试器上回溯我的错误时,主要是引发了内部 Linux 程序。
    • 另一种可能性是释放一个已经释放的指针。所以也许在其他地方TargetsArray 获得了免费,它即将再次获得免费。搜索任何可能的free(TargetsArray) 调用,并始终将任何释放的ptr 设置为NULL,以避免重复释放某些东西。另外请注意,我认为正如您所说的快速移动,所以我在这里闻到了一些竞争条件,可能每个鼠标事件都是并行运行的?!如果是,请确保任何 mem free-alloc 都是线程安全的(使用互斥锁)
    猜你喜欢
    • 2019-09-02
    • 2020-04-08
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多