C 检测到堆栈崩溃:正在使用随机分配的结构数组运行程序

C 检测到堆栈崩溃:正在使用随机分配的结构数组运行程序,c,memory-management,struct,C,Memory Management,Struct,我正在编写以下程序: #include <stdio.h> #include <stdlib.h> #include <string.h> #include "planes.h" int main(void) { plane* planes=NULL; int size=0; readPlanes(&planes, &size); free(planes); planes=NULL; re

我正在编写以下程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "planes.h"

int main(void)
{
    plane* planes=NULL;
    int size=0;

    readPlanes(&planes, &size);

    free(planes);
    planes=NULL;

    return EXIT_SUCCESS;
}


void readPlanes(plane** planes, int* size)
{
    char buffer[100]={'\0'};
    int airplaneID, modeli;
    float fuel;
    char modelc;
    int invent=0;
    int rettest=0;
    do{
        printf("Enter the number of planes:\n");
        fgets(buffer, 100, stdin);
        rettest=sscanf(buffer, "%d", size);
        if((*size)<=0)
        {
            printf("Invalid number of planes: enter a non negative number\n");
            rettest=0;
        }

    }while(rettest!=1);

    *planes=(plane*)calloc((*size), sizeof(plane*));

    for(invent=0; invent<(*size); invent++)
    {
        planes[invent]=calloc(1, sizeof(plane));

        do{
            rettest=0;
            printf("Enter the airplaneID:\n");
            fgets(buffer, 100, stdin);
            rettest=sscanf(buffer, "%d", &airplaneID);
            if(airplaneID<0)
            {
                printf("Invalid airplaneID: enter a positive number\n");
                rettest=0;
            }

        }while(rettest!=1);

        planes[invent]->airplaneID=airplaneID;

        do{
            rettest=0;
            printf("Enter the model:\n");
            fgets(buffer, 100, stdin);
            rettest=sscanf(buffer, "%c %d", &modelc, &modeli);
            if(modeli<0 || modelc<'A' || modelc>'Z')
            {
                printf("Invalid model: enter an uppercase letter followed by a non negative number\n");
                rettest=0;
            }

        }while(rettest!=2);

        planes[invent]->planemodel.letter=modelc;
        planes[invent]->planemodel.number=modeli;

        do{
            rettest=0;
            printf("Enter the fuel:\n");
            fgets(buffer, 100, stdin);
            rettest=sscanf(buffer, "%f", &fuel);
            if(fuel<0.0f)
            {
                printf("Invalid fuel: enter a non negative number\n");
                rettest=0;
            }

        }while(rettest!=1);

        planes[invent]->fuel=fuel;

    }
}
无论如何,当我用planes=1运行程序时,程序运行没有问题。但是,如果我尝试使用2个或更多平面运行它,则会发生以下错误(在程序结束时,在用户输入所有平面的所有参数后):

检测到堆栈崩溃:/home/user/Documents/program/bin/Debug/program terminated 中止(堆芯转储)


我不知道为什么会发生这种情况,我的问题在哪里。有人能帮我吗

给定声明为
平面**
平面,此分配不正确:

*planes=(plane*)calloc((*size), sizeof(plane*));
您正在分配
平面*
将指向的内存;由于您将内存视为阵列的存储器,因此阵列的元素(例如,
(*planes)[0]
)必须为
plane
类型。但是,您没有为
*大小
类型
平面
的元素分配足够的空间;只够这么多的指针

用于分配的良好表单根据分配所指向的指针指定所需的大小;比如说,

mytype *p;
p = calloc(n, sizeof (*p));
(*planes)[invent].airplaneID = airplaneID;
请注意,分配的大小是根据
p
指向的对象的大小定义的,这几乎总是您想要的,而无需硬编码
p
的类型。这不仅减少了错误的范围,而且对于
p
类型的更改也很灵活。(还需要注意的是,在C语言中转换
malloc
/
calloc
/
realloc
的结果不仅是不必要的,而且被许多人视为糟糕的形式。)

在您的情况下,您正在为其分配的指针是
*平面
,因此上述形式将实现为

*planes = calloc(*size, sizeof(**planes));
然而,你似乎被双指针弄糊涂了。唯一的原因是启用
readPlanes()
来修改其调用者的局部变量。这并不意味着需要多层次的分配。特别是,在分配了内存并在
*平面中记录了指向它的指针之后,随后分配更多内存并将其分配给
平面[0]
是没有意义的,这是同样的事情。然而,尝试将任何内容分配给
平面[1]
的意义就更小了,因为调用此函数时,
平面
指向
的指针
平面
,因此
平面[1]
指向一个
平面*
。。。什么?它没有定义,因此您的程序表现出未定义的行为。那是你的一塌糊涂

事实上,您根本不需要循环中的分配——您已经(在第一次更正之后)分配了所需的所有空间。因为您将指针指定给
*平面
,所以您希望通过该指针访问它;这意味着使用形式为
(*planes)[n]
的表达式来引用
n
th平面。比如说,

mytype *p;
p = calloc(n, sizeof (*p));
(*planes)[invent].airplaneID = airplaneID;

标准C没有C++STL意义上的“向量”。看起来您想要的术语可能是“数组”。嗯,
free(planes)
不会释放您分配的所有内容,因此理论上这里存在内存泄漏。但这可能与你看到的错误无关。嗨,约翰·布林格!非常感谢您的回复。我理解你对内存分配的解释。但是,关于双指针以及为什么使用它,我仍然有一些问题。是因为您可能希望readPlanes更改平面数组(平面*)的地址吗?如果我们的数组没有被动态分配,我们只需要一个指针(当然,表示向量)吗?谢谢@GrangerObliviate,我已经说明了使用双指针的原因(尽管它是您的程序——您还不知道为什么要这样做吗?)。唯一合理的原因是函数
readPlanes()
可以设置属于调用者的变量的值,因为调用者通过传递指向该(指针)变量的指针进行合作。