Home > Software engineering >  Why does the unexecuted code in my Qt program cause the program to crash?
Why does the unexecuted code in my Qt program cause the program to crash?

Time:11-29

A piece of code in this Qt program caused the program to crash but it is not executed.

The program consists of main.cpp, mainwindow.cpp, mainwindow.h, mainwindow.ui and CMakeLists.txt, and the problem is mainly in the MainWindow class.

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPainter>
#include <QMouseEvent>
#include <QColorDialog>
#include <vector>
#include <cmath>
#include <cstdio>
#define Pi 3.1415926535897932
#define MAXHEIGHT 4320
#define MAXWIDTH 7680
using namespace std;

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

enum State{NONE,RECT,CIRCLE,POLYGON,CUBE,BEZIER};

struct Circle
{
    int x;
    int y;
    double r;
};

struct Pos
{
    int x;
    int y;
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

protected:
    void paintEvent(QPaintEvent*);
    void mousePressEvent(QMouseEvent*);
    void mouseReleaseEvent(QMouseEvent*);
    void mouseMoveEvent(QMouseEvent*);

    void DDALine(QPainter* painter, int x1, int y1, int x2, int y2);
    void BresenhamCircle(QPainter* painter, int x, int y, int r);
    void Polygon(QPainter* painter, vector<Pos> cpolygon);

    State state=NONE;
    vector<QRect> rects;
    vector<Circle> circles;
    vector<vector<Pos>> polygons;
    vector<Pos> currentPolygon;
    QPoint* movePoint=nullptr;
    vector<Pos> curPaintPolygon;
    int rectX1=0;
    int rectY1=0;
    int circleX1=0;
    int circleY1=0;
    QColor penColor=Qt::black;
    QImage img;
};
#endif // MAINWINDOW_H

mainwindow.cpp:

#include "mainwindow.h"
#include "./ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    if(!(img.load("/Users/lijiabo/Documents/GitHub/CGWORK0528/0528.png")))
        throw "Image loading failed!";

    //connect menu actions
    connect(ui->actionDrawRect,&QAction::triggered,this,[=](){
        this->state=RECT;
    });
    connect(ui->actionDrawCircle,&QAction::triggered,this,[=](){
        this->state=CIRCLE;
    });
    connect(ui->actionSetColor,&QAction::triggered,this,[=](){
        penColor=QColorDialog::getColor(penColor,this,"设置颜色");
        update(rect());
    });
    connect(ui->actionDrawPolygon,&QAction::triggered,this,[=](){
        this->state=POLYGON;
    });
    connect(ui->actionSetColor_2,&QAction::triggered,this,[=](){
        penColor=QColorDialog::getColor(penColor,this,"设置颜色");
        update(rect());
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setPen(penColor);
    //DEBUG
    painter.drawText(rect(),QString("Width: " QString::number(rect().width()) " Height: " QString::number(rect().height())));

    switch(state)
    {
    case RECT:
    case CIRCLE:
        for(QRect rect:rects)
        {
            DDALine(&painter,rect.topLeft().x(),rect.topLeft().y(),rect.topRight().x(),rect.topRight().y());//top
            DDALine(&painter,rect.bottomLeft().x(),rect.bottomLeft().y(),rect.bottomRight().x(),rect.bottomRight().y());//bottom
            DDALine(&painter,rect.topLeft().x(),rect.topLeft().y(),rect.bottomLeft().x(),rect.bottomLeft().y());//left
            DDALine(&painter,rect.topRight().x(),rect.topRight().y(),rect.bottomRight().x(),rect.bottomRight().y());//right
        }
        for(Circle c:circles)
            BresenhamCircle(&painter,c.x,c.y,(int)c.r);
        break;
    case POLYGON:
        if(currentPolygon.size()>=1)
        {
            //把currentPolygon复制给curPaintPolygon
            curPaintPolygon.clear();
            for(Pos point:currentPolygon)
            {
                curPaintPolygon.push_back({point.x,point.y});
            }
            if(movePoint!=nullptr)
                curPaintPolygon.push_back({movePoint->x(),movePoint->y()});
            Polygon(&painter,curPaintPolygon);
        }
        if(polygons.size()>0)
        {
            for(vector<Pos> polygon:polygons)
            {
                Polygon(&painter,polygon);
            }
        }
        break;
    case CUBE:
        break;
    case BEZIER:
        break;
    default:
        ;
    }
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    switch(state)
    {
    case RECT:
        rectX1=event->pos().x();
        rectY1=event->pos().y();
        rects.push_back(QRect(rectX1,rectY1,0,0));
        break;
    case CIRCLE:
        circleX1=event->pos().x();
        circleY1=event->pos().y();
        circles.push_back({circleX1,circleY1,1});
        break;
    case POLYGON:
        /*
        if(currentPolygon==nullptr)
        {
            currentPolygon=new QPolygon;
            currentPolygon->append(QPoint(event->pos().x(),event->pos().y()));
        }
        else
        */
        movePoint= nullptr;
        currentPolygon.push_back({event->pos().x(),event->pos().y()});
        break;
    case CUBE:
        break;
    case BEZIER:
        break;
    default:
        ;
    }
    update(rect());
}

void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    switch(state)
    {
    case RECT:
        break;
    case CIRCLE:
        break;
    case POLYGON:
        if(event->button()==Qt::LeftButton)
        {
            if(currentPolygon.size()>1)
                polygons.push_back(currentPolygon);
            currentPolygon.clear();
            if(movePoint!=nullptr)
                delete movePoint;
            movePoint=nullptr;
        }
        break;
    case CUBE:
        break;
    case BEZIER:
        break;
    default:
        ;
    }
    update(rect());
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    switch(state)
    {
    case RECT:
        rects.back().setCoords(rectX1,rectY1,event->pos().x(),event->pos().y());
        break;
    case CIRCLE:
        circles.back().r=sqrt((event->pos().x()-circleX1)*(event->pos().x()-circleX1) (event->pos().y()-circleY1)*(event->pos().y()-circleY1));
        break;
    case POLYGON:
        if(movePoint==nullptr)
            movePoint=new QPoint(event->pos().x(),event->pos().y());
        else
            *movePoint=event->pos();
        break;
    case CUBE:
        break;
    case BEZIER:
        break;
    default:
        ;
    }
    update(rect());
}

void MainWindow::DDALine(QPainter* painter, int x1, int y1, int x2, int y2)
{
    double dx, dy, e, x, y;
    dx = x2 - x1;
    dy = y2 - y1;
    e = (fabs(dx) > fabs(dy)) ? fabs(dx) : fabs(dy);
    dx /= e;
    dy /= e;
    x = x1;
    y = y1;
    for (int i = 1; i <= e; i  )
    {
        painter->drawPoint((int)(x   0.5), (int)(y   0.5));
        x  = dx;
        y  = dy;
    }
}

void MainWindow::BresenhamCircle(QPainter* painter, int x, int y, int r)
{
    int edgeX,edgeY,p;

    edgeX=0;
    edgeY=r;
    p=3-2*r;
    for(;edgeX<=edgeY;edgeX  )
    {
        painter->drawPoint(x edgeX,y edgeY);
        double dT=0;
        for(int dTNC=1;dTNC<8;dTNC  )
        {
            dT=dTNC*0.25*Pi;
            painter->drawPoint( x   r*cos(acos(edgeX/double(r)) dT), y   r*sin(asin(edgeY/double(r)) dT) );
        }
        if(p>=0)
        {
            p =4*(edgeX-edgeY) 10;
            edgeY--;
        }
        else
            p =4*edgeX 6;
    }


}

void MainWindow::Polygon(QPainter* painter, vector<Pos> cpolygon)
{
    if(cpolygon.size()<=1)
        return;
    
    vector<Pos>::iterator prevPoint = cpolygon.begin();
    for(vector<Pos>::iterator it=cpolygon.begin() 1;it!=cpolygon.end();it  ,prevPoint  )
    {
        DDALine(painter,prevPoint->x,prevPoint->y,it->x,it->y);
    }
    DDALine(painter,prevPoint->x,prevPoint->y,cpolygon.begin()->x,cpolygon.begin()->y);
    
    //fill------------------------------

    int imgWidth=img.width();
    int imgHeight=img.height();
    int x1=rect().left();
    int x2=rect().right();
    int y1=rect().bottom();
    int y2=rect().top();
    bool mask[MAXHEIGHT][MAXWIDTH];
    for(int y=y1;y<=y2;y  )
        for(int x=x1;x<=x2;x  )
            mask[y][x]=false;
    for(vector<Pos>::const_iterator it=cpolygon.cbegin();it!=cpolygon.cend();it  )
    {
        int xs=it->x;
        int dxs=((it 1)->x-it->x)/((it 1)->y/it->y);
        int dys=abs((it 1)->y-it->y)/((it 1)->y-it->y);
        for(int ys=it->y;ys!=(it 1)->y;ys =dys)
        {
            int Ixs=int(xs 0.5);
            mask[ys][Ixs]=!mask[ys][Ixs];
            xs =dys*dxs;
        }
    }
    QPen initialPen = painter->pen();
    for(int y=y1;y<=y2;y  )
    {
        bool inside=false;
        for(int x=x1;x<=x2;x  )
        {
            if(mask[y][x])
                inside=!inside;
            if(inside)
            {
                painter->setPen(img.pixel(x%imgWidth,y%imgHeight));
                painter->drawPoint(x,y);
            }
        }
    }
    painter->setPen(initialPen);
    //----------------------------------
}

In the last function Polygon() in mainwindow.cpp, when the "fill" part is exist, the program will crash when actionDrawPolygon is triggered, and I click mouse left button(so the mousePressEvent() is invoked),and the program won't crash without this part.

But when I add a printf("TEST") function to this part, "TEST" is not printed, so this part is not executed at all, then why it causes the program to crash?

OS version: macOS Monterey 12.0.1

IDE: CLion 2021.2.3

CodePudding user response:

As mentioned, you have a local bool array that is std::sizeof(bool) * MAXHEIGHT * MAXWIDTH in size. Depending on sizeof bool, that is greater than 30 megabytes in size.

Since the stack size is limited (maybe 1 megabyte up to usually 8 megabytes) the program stack is not going to be able to handle arrays that size.

Instead, try this:

std::vector<std::vector<bool>> mask(MAXHEIGHT, std::vector<bool>(MAXWIDTH));

This also eliminates the need for that for loop that initializes the array entries to false, since that will be the default value anyway.

This is not the best method, since it is a vector of vector's, but more than likely this will bypass the crash you are seeing now.

  •  Tags:  
  • c qt
  • Related