Как объяснить ошибку сегментации, которая иногда возникает при динамическом размещении двумерного массива? - PullRequest
0 голосов
/ 05 февраля 2019

Я хочу иметь функцию, которая инициализирует простую сетку (2d-массив) столбцами и строками, каждая позиция (ячейка) имеет размер struct.

Я нашел решение, которое выполняет это в основной функциино при выполнении в любой другой функции, после выполнения на полпути, она падает с ошибкой сегментации, прежде чем печатает Grid (в отличие от последнего абзаца).

Однако, если печать Grid добавляется непосредственно после инициализациипосле этого код работает нормально и все ошибки исчезают.

Я подозреваю, что main теперь не инициализирует массив Position, но я передаю его как указатель, так что я делаю неправильно?

Следующий код разделен на две части.Первый имеет ошибку сегментации, второй нет.Разница лишь в том, что во второй части циклы for для распечатки сетки находятся внутри функции, которая инициализирует массив 2d.

//SEGMENTATION FAULT

void CreateMap (struct GameGrid *Position, int &Dim_x, int &Dim_y)
{
    cout << "Lets create the game map." << endl;
    cout << "Enter number of Columns: ";
    cin >> Dim_x;
    cout << "Enter number of Rows: ";
    cin >> Dim_y;

    Position = new GameGrid[Dim_x * Dim_y];
}

int main()
{
    struct GameGrid *Position = NULL;
    int Dim_x;
    int Dim_y;

    CreateMap(Position, Dim_x, Dim_y);

    for (int y=0; y < Dim_y; y++)
    {
        cout << setw (20);

        for (int x=0; x < Dim_x; x++)
        {
            cout << Position[x*Dim_y + y].Element;
            cout << char(32);
        }
        cout << endl;
    }

    delete[] Position;
    return 0;
}

//NO FAULTS

void CreateMap (struct GameGrid *Position, int &Dim_x, int &Dim_y)
{
    cout << "Lets create the game map." << endl;
    cout << "Enter number of Columns: ";
    cin >> Dim_x;
    cout << "Enter number of Rows: ";
    cin >> Dim_y;

    Position = new GameGrid[Dim_x * Dim_y]

    for (int y=0; y < Dim_y; y++)
    {
        cout << setw (20);

        for (int x=0; x < Dim_x; x++)
        {
            cout << Position[x*Dim_y + y].Element;
            cout << char(32);
        }
        cout << endl;
    }
}

int main()
{
    struct GameGrid *Position = NULL;
    int Dim_x;
    int Dim_y;

    CreateMap(Position, Dim_x, Dim_y);

    delete[] Position;
    return 0;
}

Сетка должна выглядеть примерно так для измерений Dim_x = 6 иDim_y = 6 (выбирается конечным пользователем).

A A A A A A
A A A A A A
A A A A A A
A A A A A A
A A A A A A
A A A A A A

Также, когда печать сетки выполняется два раза (один раз в функции CreateMap и один раз в основном), она печатает их оба раза, затем останавливаетсяна 10 секунд и умирает.

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Хотя вы используете указатель в качестве параметра, вы все равно передаете по значению.

При попытке передачи по ссылке сам указатель не изменяется, но объект по адресу, на который он указывает, обновляется.

Поэтому для обновления указателя необходим указатель на указательили ссылка на указатель.В противном случае, часто, как уже было получено, возврат используется для возврата обновленного указателя.

0 голосов
/ 05 февраля 2019

В вашей функции CreateMap:

void CreateMap (struct GameGrid *Position, int &Dim_x, int &Dim_y)
{
    // ...    
    Position = new GameGrid[Dim_x * Dim_y];
}

Это изменяет только локальную переменную Position , оно не изменяет значение вызывающей стороны, предоставленное этому аргументу.

Что вам нужно, это переделать это:

GameGrid *CreateMap(const int Dim_x, const int Dim_y)
{
    // ...    
    return new GameGrid[Dim_x * Dim_y];
}

Где это возвращает значение, которое вы можете захватить:

int main()
{
  int x, y;
  cout << "Lets create the game map." << endl;
  cout << "Enter number of Columns: ";
  cin >> x;
  cout << "Enter number of Rows: ";
  cin >> y;

  GameGrid *Position = CreateMap(x, y);
  // ...
}

Делать все ваши входные / выходные данные вне этих функций,Запомните свои ТВЕРДЫЕ Принципы , дайте этой функции одну работу и только одну работу.Ввод и распределение - это два задания.

Еще лучше: Создать конструктор вместо этих CreateX функций.Это C ++, и вы можете в полной мере воспользоваться этим.

Как всегда:

Всякий раз, когда у вас странное поведение, шагайте по коду в отладчике, чтобы увидеть значения различных переменных.как он выполняет.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...