1

Тема: Сигнал SIGSEGV segmentation fault

Створив проект у QT, суть його проста. У вікні є 2 таблиці. За замовчуванням в них всього 1 елемент, але це можливо налаштувати за допомогою відповідних спінбоксів в нижній частині вікна. В одну таблицю вводится массив чисел і по настиканні кнопки программа має перевірити кожний елемент на кратність. Якщо елемент кратний - вона виводить його у відповідній комірці другої таблиці, а якщо ні то у відповідну комірку вводить текст "Nan" але якщо я залишаю всього 1 елемент то программа не працює взагалі (запускається, але нічого не виводится), а якщо я якось змінюю розмірність то при спробі пропустити программу через відладник отримав повідомлення:


Підпроцес зупинено, оскільки він отримав сигнал від операційної системи.

Назва сигналу: SIGSEGV
Значення сигналу: Segmentation fault


Порившись у гуглі я виявив що це виникає коли программа звертається до сегменту пам'яті, до якого не має доступу.

Код:

main.cpp:

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  MainWindow w;
  w.show();
  return a.exec();
}

mainwindow.cpp:

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

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
      , ui(new Ui::MainWindow)
{
  ui->setupUi(this);
}

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



void MainWindow::on_spbSize_valueChanged(int InputArrSize)
{
  InputArrSize = ui->spbSize->value();
  if(InputArrSize == 1)
  {
    ui->lblYCoord->setDisabled(1);
    ui->spbYCoord->setDisabled(1);
  }
  else
  {
    ui->lblYCoord->setDisabled(0);
    ui->spbYCoord->setDisabled(0);
  }
}


void MainWindow::on_spbXCoord_valueChanged(int RowCount)
{
  ui->TBLInput->setRowCount(RowCount);
  ui->TBLOutput->setRowCount(RowCount);
}


void MainWindow::on_spbYCoord_valueChanged(int ColumnCount)
{
  ui->TBLInput->setColumnCount(ColumnCount);
  ui->TBLOutput->setColumnCount(ColumnCount);
}


void MainWindow::on_PBTArrayCheck_clicked()
{
  int RowCount, ColumnCount;
  RowCount = ui->TBLInput->rowCount();
  ColumnCount = ui->TBLInput->columnCount();
  int n = 1;
  int i = 1;
  while (n<RowCount || i<ColumnCount)
  {
    QString buffer;
    buffer = ui->TBLInput->item(n,i)->text();
    int buff = buffer.toInt();
    if (buff%2==0)
    {
      ui->TBLOutput->item(n,i)->setText(buffer);
    }
    else
    {
      ui->TBLOutput->item(n,i)->setText("Nan");
    }
    if(n<RowCount)
    {
      n++;
    }
    if(n=RowCount, i<ColumnCount)
    {
      n=1;
      i++;
    }
    int Progress100 = RowCount*ColumnCount;
    int CurrentProgress = 0;
    CurrentProgress++;
    int ProgressValue = CurrentProgress/Progress100 * 100;
    ui->PBArrayCheck->setValue(ProgressValue);
  };
}

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
QT_END_NAMESPACE

    class MainWindow : public QMainWindow
{
  Q_OBJECT

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

             private slots:
               void on_spbSize_valueChanged(int arg1);

               void on_spbXCoord_valueChanged(int arg1);

               void on_spbYCoord_valueChanged(int arg1);

               void on_PBTArrayCheck_clicked();

             private:
  Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.ui:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>994</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QTableWidget" name="TBLInput">
    <property name="geometry">
     <rect>
      <x>20</x>
      <y>40</y>
      <width>431</width>
      <height>371</height>
     </rect>
    </property>
    <property name="inputMethodHints">
     <set>Qt::ImhDigitsOnly</set>
    </property>
    <row>
     <property name="text">
      <string>1</string>
     </property>
    </row>
    <column>
     <property name="text">
      <string>1</string>
     </property>
    </column>
   </widget>
   <widget class="QLabel" name="lblInput">
    <property name="geometry">
     <rect>
      <x>140</x>
      <y>10</y>
      <width>131</width>
      <height>20</height>
     </rect>
    </property>
    <property name="text">
     <string>Входящий массив</string>
    </property>
   </widget>
   <widget class="QTableWidget" name="TBLOutput">
    <property name="enabled">
     <bool>false</bool>
    </property>
    <property name="geometry">
     <rect>
      <x>480</x>
      <y>40</y>
      <width>431</width>
      <height>371</height>
     </rect>
    </property>
    <property name="inputMethodHints">
     <set>Qt::ImhNone</set>
    </property>
    <row>
     <property name="text">
      <string>1</string>
     </property>
    </row>
    <column>
     <property name="text">
      <string>1</string>
     </property>
    </column>
   </widget>
   <widget class="QLabel" name="lblOutput">
    <property name="geometry">
     <rect>
      <x>610</x>
      <y>10</y>
      <width>141</width>
      <height>20</height>
     </rect>
    </property>
    <property name="text">
     <string>Исходящий массив</string>
    </property>
   </widget>
   <widget class="QSpinBox" name="spbSize">
    <property name="geometry">
     <rect>
      <x>210</x>
      <y>430</y>
      <width>42</width>
      <height>26</height>
     </rect>
    </property>
    <property name="minimum">
     <number>1</number>
    </property>
    <property name="maximum">
     <number>2</number>
    </property>
   </widget>
   <widget class="QLabel" name="lblSize">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>430</y>
      <width>161</width>
      <height>20</height>
     </rect>
    </property>
    <property name="text">
     <string>Размерность массива</string>
    </property>
   </widget>
   <widget class="QSpinBox" name="spbXCoord">
    <property name="geometry">
     <rect>
      <x>210</x>
      <y>460</y>
      <width>42</width>
      <height>26</height>
     </rect>
    </property>
    <property name="minimum">
     <number>1</number>
    </property>
   </widget>
   <widget class="QSpinBox" name="spbYCoord">
    <property name="enabled">
     <bool>false</bool>
    </property>
    <property name="geometry">
     <rect>
      <x>210</x>
      <y>490</y>
      <width>42</width>
      <height>26</height>
     </rect>
    </property>
    <property name="minimum">
     <number>1</number>
    </property>
   </widget>
   <widget class="QLabel" name="lblXCoord">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>460</y>
      <width>161</width>
      <height>20</height>
     </rect>
    </property>
    <property name="text">
     <string>1 Координата</string>
    </property>
   </widget>
   <widget class="QLabel" name="lblYCoord">
    <property name="enabled">
     <bool>false</bool>
    </property>
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>490</y>
      <width>161</width>
      <height>20</height>
     </rect>
    </property>
    <property name="text">
     <string>2 Координата</string>
    </property>
   </widget>
   <widget class="QPushButton" name="PBTArrayCheck">
    <property name="geometry">
     <rect>
      <x>420</x>
      <y>490</y>
      <width>231</width>
      <height>29</height>
     </rect>
    </property>
    <property name="text">
     <string>Проверить массив на четность</string>
    </property>
   </widget>
   <widget class="QProgressBar" name="PBArrayCheck">
    <property name="geometry">
     <rect>
      <x>320</x>
      <y>450</y>
      <width>461</width>
      <height>23</height>
     </rect>
    </property>
    <property name="inputMethodHints">
     <set>Qt::ImhNone</set>
    </property>
    <property name="value">
     <number>0</number>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>994</width>
     <height>26</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

2

Re: Сигнал SIGSEGV segmentation fault

Наскільки я пам'ятаю, setRowCount та setColumnCount не створюють item-и (QTableWidgetItem). Вам треба після розширення таблиці заповнити її за допомогою setItem, без цього ui->TBLInput->item(n,i) поверне nullptr, а nullptr->text() і призводить до сегфолту.

setDisabled приймає аргументом bool, не ставите там 0 та 1 замість false та true.

Цикли по n та i мають бути вкладеними, так вам буде значно легше. А

    int Progress100 = RowCount*ColumnCount;
    int CurrentProgress = 0;

мають бути проголошені до цикла.

Подякували: VPrisniak1

3

Re: Сигнал SIGSEGV segmentation fault

koala написав:

Наскільки я пам'ятаю, setRowCount та setColumnCount не створюють item-и (QTableWidgetItem). Вам треба після розширення таблиці заповнити її за допомогою setItem, без цього ui->TBLInput->item(n,i) поверне nullptr, а nullptr->text() і призводить до сегфолту.

setDisabled приймає аргументом bool, не ставите там 0 та 1 замість false та true.

Цикли по n та i мають бути вкладеними, так вам буде значно легше. А

    int Progress100 = RowCount*ColumnCount;
    int CurrentProgress = 0;

мають бути проголошені до цикла.

З приводу змінних прогресу - дякую, цього я не помітив. Також додав у наявний цикл створення item-ів для вихідної таблиці - не допомогло, додав окремий цикл створення item-ів для вхідної - программа зависає намертво, а коли я намагаюсь переглянути виведення программи то бачу що там циклічно створюється запис "QTableWidget: cannot insert an item that is already owned by another QTableWidget"

4

Re: Сигнал SIGSEGV segmentation fault

Причину зависання я знайшов, а от проблема сегфолту залишилась. item-и створював за допомогою приблизно такого циклу

int n = 1;
  int i = 1;
  while (n<RowCount||i<ColumnCount)
   {
    QTableWidgetItem *newItem = new QTableWidgetItem(tr("%1").arg((n+1)*(i+1)));
    ui->TBLOutput->setItem(n, i, newItem);
    QTableWidgetItem *newItem2 = new QTableWidgetItem(tr("%1").arg((n+1)*(i+1)));
    ui->TBLInput->setItem(n, i, newItem2);
    if (n==RowCount||i<ColumnCount)
   {
     n = 1;
      i++;
   }
    if (n<RowCount||i<ColumnCount)
   {
     n++;
   }

   }

5

Re: Сигнал SIGSEGV segmentation fault

for(int i=0; i<ColumnCount; ++i) {
    for(int n=0; n<RowCount; ++n) {
        //а тут працюєте з i та n
    }
}

Так надто складно?

Ну і якщо ви хочете, щоб я у приблизно вашому коді помилки шукав, то помилка приблизно в рядку 57.

Подякували: VPrisniak1

6

Re: Сигнал SIGSEGV segmentation fault

koala написав:
for(int i=0; i<ColumnCount; ++i) {
    for(int n=0; n<RowCount; ++n) {
        //а тут працюєте з i та n
    }
}

Так надто складно?

Ну і якщо ви хочете, щоб я у приблизно вашому коді помилки шукав, то помилка приблизно в рядку 57.

Цикли виправив, дякую. Я вказав що цикл "приблизно" такий оскільки в мене вийшло 2 подібних один до одного цикли (відмінність лише у джерелі для змінних) і я намагався оптимізувати це, створивши для цього окрему функцію, але поки не вийшло, намагаюсь розібратись сам, оскільки поки не сильно знайомий з цим фреймворком. На даний момент код mainwindow.cpp виглядає так

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

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
      , ui(new Ui::MainWindow)
{
  ui->setupUi(this);
}

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





void MainWindow::on_spbSize_valueChanged(int InputArrSize)
{
  InputArrSize = ui->spbSize->value();
  if(InputArrSize == 1)
  {
    ui->lblYCoord->setDisabled(true);
    ui->spbYCoord->setDisabled(true);
  }
  else
  {
    ui->lblYCoord->setDisabled(false);
    ui->spbYCoord->setDisabled(false);
  }
}


void MainWindow::on_spbXCoord_valueChanged(int RowCount)
{
  ui->TBLInput->setRowCount(RowCount);
  ui->TBLOutput->setRowCount(RowCount);
  int ColumnCount = ui->TBLInput->columnCount();
  for ( int n = 0; n<RowCount; n++)
   {
    for (int i = 0; i<ColumnCount; i++)
    {
    QTableWidgetItem *newItem = new QTableWidgetItem(tr("%1").arg((n+1)*(i+1)));
    ui->TBLOutput->setItem(n, i, newItem);
    QTableWidgetItem *newItem2 = new QTableWidgetItem(tr("%1").arg((n+1)*(i+1)));
    ui->TBLInput->setItem(n, i, newItem2);

   }
  }
}


void MainWindow::on_spbYCoord_valueChanged(int ColumnCount)
{
  ui->TBLInput->setColumnCount(ColumnCount);
  ui->TBLOutput->setColumnCount(ColumnCount);
  int RowCount = ui->TBLInput->rowCount();
  for ( int n = 0; n<RowCount; n++)
  {
    for (int i = 0; i<ColumnCount; i++)
    {
      QTableWidgetItem *newItem = new QTableWidgetItem(tr("%1").arg((n+1)*(i+1)));
      ui->TBLOutput->setItem(n, i, newItem);
      QTableWidgetItem *newItem2 = new QTableWidgetItem(tr("%1").arg((n+1)*(i+1)));
      ui->TBLInput->setItem(n, i, newItem2);

    }
  }
}


void MainWindow::on_PBTArrayCheck_clicked()
{
  int RowCount, ColumnCount;
  RowCount = ui->TBLInput->rowCount();
  ColumnCount = ui->TBLInput->columnCount();
  int Progress100 = RowCount*ColumnCount;
  int CurrentProgress = 0;
  for ( int n = 0; n<RowCount; n++)
  {
    for (int i = 0; i<ColumnCount; i++)
    {
    QString buffer;
    buffer = ui->TBLInput->item(n,i)->text();
    int buff = buffer.toInt();
    if (buff%2==0)
    {
      ui->TBLOutput->item(n,i)->setText(buffer);
    }
    else
    {
      ui->TBLOutput->item(n,i)->setText("Nan");
    }


    }
    CurrentProgress++;
    int ProgressValue = CurrentProgress/Progress100 * 100;
    ui->PBArrayCheck->setValue(ProgressValue);
  }

}

7

Re: Сигнал SIGSEGV segmentation fault

Інші файли залишились без змін

8

Re: Сигнал SIGSEGV segmentation fault

І цей код видає SEGFAULT? У якій функції?

9

Re: Сигнал SIGSEGV segmentation fault

koala написав:

І цей код видає SEGFAULT? У якій функції?

В цей момент курсор встановлюється на функцію setText()

10

Re: Сигнал SIGSEGV segmentation fault

Помилку знайшов, просто в мене у вихідній таблиці була прибрана галочка enabled для того щоб користувачі не могли випадково відредагувати готовий результат, я просто повернув галочку і замість неї застосував строку ui->TBLOutput->setEditTriggers(QAbstractItemView::NoEditTriggers);