Ошибка сегментации С++ при передаче значений адреса между функциями

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

Коду удается передать адрес a[0] в основную функцию, и я могу читать значения, используя указатели внутри main. Когда я пытаюсь передать адрес для решения функции, это дает ошибку сегментации.

(Также в качестве второстепенного вопроса я могу правильно читать значения в main, правильно используя cout ‹‹ *(a+5) и т. д. (закомментировано в main), но когда я пытаюсь напечатать все 81 значение, сохраненное с помощью цикла for, он выдает бессмысленные значения (опять же, закомментированные в коде).Код работает с литералами, такими как *(a+3) или a[3], но не работает, когда int используется для (int i, что угодно) cout ‹‹ *(а+я);)

#include <iostream>
using namespace std;

int * get_input();
void solve(int *);

int main()
{
    int * a;
    a = get_input();
    //cout << *a << " " << *(a+1) << " " << *(a+2) << " " << *(a+3) << " " << *(a+4);
    //for (int i = 0 ; i < 81 ; i++) {if (i%9 == 0) cout << "\n"; cout << a[i] << " ";}
    solve(a);
    return(0);
}

int * get_input ()
{
    int a[81];
    getinput:
    for (int i = 0 ; i < 81 ; i++)  {a[i] = 0;}
    for (int i = 0 ; i < 81 ; i++)  {cin >> a[i];}
    print:
    for (int i = 0 ; i < 81 ; i++)
    {
        if (i%27 == 0){cout << "\n";}
        if (i%9 == 0) {cout << "\n";}
        if (i%3 == 0) {cout << "  " << a[i];}
        if (i%3 != 0) {cout << a[i];}
    }
    cout << "\n\nCheck:\n1- Fix\n2- Reset\n3- Confirm\n\n";
    int check = 0;
    cin >> check;
    if (check == 1)
    {   
        int input[3] = {-1, -1, -1};
        while (true)
        {
            cin >> input[0] >> input[1] >> input [2];
            if (input[1] == 0) goto print;
            a[(input[2]-1)+((input[1]-1)*9)] = input[0];
        }
    }
    if (check == 2) goto getinput;
    if (check == 3) return a;
}

void solve(int * a)
{
    bool matrix[9][9][9];
    for (int i = 0 ; i < 81 ; i++) {for (int j = 0 ; j < 9 ; j++) {matrix[(i-i%9)/9][i%9][j] = true;}}
    for (int i = 0 ; i < 81 ; i++)
    {
        if (a[i] == 0) continue;
        else
        {
            for (int j = 0 ; j < 9 ; i++)
            {
                matrix[(i-i%9)/9][j][a[i]] = false;
                matrix[j][i%9][a[i]] = false;
                matrix[((i-i%9)/9)-((i-i%9)/9)%3+j%3][i%9-(i%9)%3+(j-j%3)/3][a[i]] = false;
            }
        }
    }
    for (int i = 0 ; i < 9 ; i++)
    {
        for (int j = 0 ; j < 9 ; j++)
        {
            cout << matrix[i][j][1] << " ";
        }
        cout << "\n";
    }
}

person corsel    schedule 18.02.2013    source источник
comment
После очень быстрого просмотра я бы сказал, что это return a в get_input . Вы не можете вернуть указатель на переменную стека, вместо этого выделите его с помощью malloc/new и верните его.   -  person slugonamission    schedule 18.02.2013
comment
Закрытие как слишком локализованное.   -  person djechlin    schedule 18.02.2013
comment
Массивы, goto, ... вы уверены, что имели в виду C++?   -  person Angew is no longer proud of SO    schedule 18.02.2013
comment
Ну, он использует С++ IO...   -  person r_ahlskog    schedule 18.02.2013


Ответы (4)


Создайте массив a в своей функции get_input() static:

int a[81];

должно быть

static int a[81];

Это работает, потому что ключевое слово static гарантирует, что выделенный блок памяти (массив a) останется выделенным после возврата из функции. Обычно это «потому что я еще не закончил с этим» (например, вы можете подсчитать, сколько раз ваша функция вызывалась таким образом), но это также может быть использовано для обеспечения того, чтобы возвращаемое значение функции переживает конец функции.

Незначительно лучше было бы объявить массив на уровне main и передать указатель на него в функции get_input() и solve(). Таким образом, вы указываете в коде, что массив будет "жить в течение всей программы" - и это обычно является хорошей практикой.

person Floris    schedule 18.02.2013
comment
Я не могу этого отрицать... но поскольку головоломка до сих пор должна храниться в памяти все время, статика не так уж и плоха. Было бы лучше поместить его на верхний уровень, чем в функцию. - person Floris; 18.02.2013
comment
Конечно. Я понимаю, почему это сработает, и я вижу ваше обоснование этого, я просто не могу избавиться от ощущения, что это кажется немного неприятным: P. Возможно, стоит добавить почему это работает. - person slugonamission; 18.02.2013
comment
Доступ к статическому объекту через функцию вполне законен и даже желателен, поскольку в некоторых случаях (не в этом) он аккуратно избегает фиаско статической инициализации. Единственные проблемы с использованием статики, подобной этой, связаны с многопоточностью и повторным входом, и я не вижу в этом проблемы. - person Benj; 18.02.2013
comment
Спасибо, я попробую это. Это был мой первый вопрос в stackoverflow, и, честно говоря, я поражен тем, сколько законных ответов дается за такое короткое время :) - person corsel; 18.02.2013
comment
@cem - пожалуйста. Как новый пользователь, вы никогда не можете точно знать, будете ли вы проголосованы против и закрыты менее чем за минуту, или получите 5 полезных ответов за пять минут. Вам повезло! Кстати - пожалуйста, пожалуйста, научитесь писать структурированные циклы, которым не нужен goto - это редко правильный подход (хотя и может быть). См. stackoverflow.com /вопросы/245742/ - person Floris; 18.02.2013
comment
хорошо, я посмотрю на это. goto впечатлил меня своим простым, олдскульным внешним видом, но я думаю, что это не очень хорошая практика для больших проектов. - person corsel; 18.02.2013
comment
о, я не знал, что в мире гиков есть команда goto и соперники :) ветка заставила меня опасаться, что третья мировая война может начаться с битвы из-за goto. - person corsel; 18.02.2013
comment
По крайней мере, теперь вы предупреждены... Удачного взлома! - person Floris; 18.02.2013
comment
Спасибо! не спал до 5 утра, чтобы понять это. - person killer; 17.03.2018

Вы возвращаете адрес локальной переменной в getInput (массив a). Я бы посоветовал вам передать массив в качестве аргумента этой функции. Другой вариант — выделить массив динамически, а затем позаботиться о его освобождении перед завершением программы.

person Ivaylo Strandjev    schedule 18.02.2013

int a[81];

Это выделение локальной памяти, и оно освобождается, когда ваша функция get_input возвращается.

Вместо этого используйте указатель int* a и функцию malloc для динамического выделения памяти!

Команда malloc может быть такой (если я ее хорошо помню):

int *a = (int *) malloc(sizeof(int)*81);
person Paschalis    schedule 18.02.2013

Ваша проблема в том, что вы возвращаете указатель на локально объявленную переменную. Не делай этого. Вы должны либо передать переменную в качестве параметра (например, get_input(int[] arr, int length)`, либо выделить новую память в куче для вашего массива. Проще всего первое, последнее может вызвать у вас проблемы, поскольку вы должны управлять своей памятью, или вы получите утечки памяти.

Зачем вам это нужно? Когда вы объявляете [] в get_input, он выделяет место для этой переменной в стеке. Стек — это длинный непрерывный блок памяти, который используется для хранения параметров функции, ее локальных переменных и адреса программы, вызывающей текущую функцию. Когда функция возвращается, вся эта память освобождается для использования при следующем вызове функции. То есть, когда вызывается solve, он начинает перезаписывать память в стеке, которая ранее использовалась get_input.

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

В итоге: объявите свой массив в основной функции и передайте его get_input для работы.

person Dunes    schedule 18.02.2013