【问题标题】:Stack smashing detected: running program with dinamically allocated array of structures检测到堆栈粉碎:使用动态分配的结构数组运行程序
【发布时间】:2017-09-28 22:39:26
【问题描述】:

我正在编写以下程序:

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

    }
}

头文件为:

#ifndef PLANES_H_INCLUDED
#define PLANES_H_INCLUDED

typedef struct
{
    char letter;
    int number;
}model;


typedef struct
{
    int airplaneID;
    model planemodel;
    float fuel;
}plane;

void readPlanes(plane**, int*);
int lowestFuel(plane*, int);
void printID(plane*, int, char*);


#endif // PLANES_H_INCLUDED

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

检测到堆栈破坏:/home/user/Documents/program/bin/Debug/program 已终止 中止(核心转储)

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

【问题讨论】:

  • 标准 C 没有 C++ STL 意义上的“向量”。看起来您想要的术语可能是“数组”。
  • 好吧,free(planes) 不会释放你分配的所有东西,所以理论上你这里有内存泄漏。但这可能与您看到的错误无关。

标签: c memory-management struct


【解决方案1】:

鉴于 planes 声明为 plane **,此分配不正确:

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

您正在分配plane * 将指向的内存;由于您正在考虑将内存作为数组的存储,因此数组的元素(例如(*planes)[0])必须是plane 类型。但是,您没有为 plane 类型的 *size 元素分配足够的空间;只够那么多指针

一种用于分配的好形式根据分配的指针指定所需的大小;例如,

mytype *p;
p = calloc(n, sizeof (*p));

注意分配的大小是根据p 指向的事物的大小来定义的,这几乎总是你想要的,没有硬编码p 的类型。这不仅减少了错误的范围,而且在更改p 的类型方面也很灵活。 (另请注意,在 C 中转换 malloc / calloc / realloc 的结果不仅没有必要,而且被许多人认为是糟糕的形式。)

在你的情况下,你分配的指针是*planes,所以上面的形式将被实现为

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

但是,您似乎对双指针感到困惑。它的唯一原因是启用readPlanes() 来修改其调用者的局部变量。它并不意味着需要多级分配。特别是,分配了内存并在*planes 中记录了指向它的指针,随后分配更多内存并将其分配给planes[0] 毫无意义,这是同一件事。但是,尝试将任何内容分配给planes[1] 就更没有意义了,因为调用此函数时,planes 指向main 的指针planes,因此planes[1] 指向过去的plane*那,到……什么?它没有定义,因此您的程序表现出未定义的行为。那是你的堆栈粉碎。

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

(*planes)[invent].airplaneID = airplaneID;

【讨论】:

  • 你好约翰布林格!非常感谢您的回复。我理解你对内存分配的解释。但是,我仍然对双指针以及我们为什么使用它有一些问题。是因为您可能希望 readPlanes 更改平面数组(平面*)的地址吗?如果我们的数组不是动态分配的,我们是否只需要一个指针(当然,代表向量)?谢谢!
  • @GrangerObliviate,我已经说明了使用双指针的原因(尽管它是 你的 程序——你不知道你为什么这样做吗?)。唯一合理的原因是函数readPlanes() 可以设置属于其调用者的变量的值,假设调用者通过传递一个指向该(指针)变量的指针进行合作。
猜你喜欢
  • 2016-01-02
  • 2012-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多