Функция определена в области видимости, но компилятор жалуется, что она не входит в область видимости

Я попытался реализовать алгоритм Штрассенса для двух матриц 2x2, чтобы создать алгоритм рекурсивного умножения матриц, однако реализация не компилируется, что приводит к таким ошибкам:

"Штрассен не был объявлен в этой области" и "Unqualified-ID"

Вот код:

#include <iostream>
#include <cstdlib>

using namespace std;

int[][] strassen(int A[][2], int B[][2])
{
    int s1 = B[0][1] - B[1][1];
    int s2 = A[0][0] + A[0][1];
    int s3 = A[1][0] + A[1][1];
    int s4 = B[1][0] - B[0][0];
    int s5 = A[0][0] + A[1][1];
    int s6 = B[0][0] + B[1][1];
    int s7 = A[0][1] - A[1][1];
    int s8 = B[1][0] + B[1][1];
    int s9 = A[0][0] - A[1][0];
    int s10 = B[0][0] + B[0][1];

    int p1 = A[0][0] * s1;
    int p2 = s2 * B[1][1];
    int p3 = s3 * B[0][0];
    int p4 = A[1][1] * s4;
    int p5 = s5 * s6;
    int p6 = s7 * s8;
    int p7 = s9 * s10;

int C[2][2];

C[0][0] = p5 + p4 - p2 + p6;
C[0][1] = p1 + p2;
C[1][0] = p3 + p4;
C[1][1] = p5 + p1 - p3 - p7;

return C[][];
}

int main()
{
    int A[2][2] = {{1,3},{7,5}};
    int B[2][2] = {{6,8},{4,2}};
    int C[][2] = strassen(A,B);
    cout<<C[0][0]<<endl<<C[0][1]<<endl<<C[1][0]<<endl<<C[1][1]<<endl;
    return 0;
}

Не могли бы вы сказать мне, почему я получаю ошибки во время компиляции. Мне также нужно знать, как malloc пространство для 2D-массива, как моя текущая реализация C выйдет из области видимости, как только закроется функция, возвращающая значения мусора.

2 ответа

Решение

Есть несколько причин, по которым ваш код не компилируется: вы выводите ошибку функции из области видимости, потому что функция strassen не компилируется и не компилируется, потому что вы возвращаете массив, объявленный внутри функции.

Хорошее практическое правило - никогда не возвращать массивы и не передавать их в качестве аргументов, вместо этого использовать ссылки, это экономит память и время.

Вот решение без использования динамической памяти (хотя я думаю, что так будет проще)

#include <iostream>

using namespace std;

void strassen(int (&A)[2][2], int (&B)[2][2], int (&C)[2][2])
{
    int s1 = B[0][1] - B[1][1];
    int s2 = A[0][0] + A[0][1];
    int s3 = A[1][0] + A[1][1];
    int s4 = B[1][0] - B[0][0];
    int s5 = A[0][0] + A[1][1];
    int s6 = B[0][0] + B[1][1];
    int s7 = A[0][1] - A[1][1];
    int s8 = B[1][0] + B[1][1];
    int s9 = A[0][0] - A[1][0];
    int s10 = B[0][0] + B[0][1];

    int p1 = A[0][0] * s1;
    int p2 = s2 * B[1][1];
    int p3 = s3 * B[0][0];
    int p4 = A[1][1] * s4;
    int p5 = s5 * s6;
    int p6 = s7 * s8;
    int p7 = s9 * s10;

    C[0][0] = p5 + p4 - p2 + p6;
    C[0][1] = p1 + p2;
    C[1][0] = p3 + p4;
    C[1][1] = p5 + p1 - p3 - p7;

}

int main()
{
    int A[2][2] = {{1,3},{7,5}};
    int B[2][2] = {{6,8},{4,2}};
    int C[2][2];

    strassen(A,B,C);

    cout<<C[0][0]<<endl<<C[0][1]<<endl<<C[1][0]<<endl<<C[1][1]<<endl;

    return 0;
}

Обратите внимание, что вы передаете C как ссылку на функцию, поэтому изменения, которые вы вносите в нее внутри функции, также влияют на нее вне функции.

Как упоминалось во многих комментариях, ваше решение - это типичный стиль C, который может создавать много проблем (особенно, когда вы начинающий). C++ обеспечивает мощный, экономящий память и простой в использовании обходной путь для многих случаев, когда C может усложниться.

Не поймите меня неправильно: C - отличный язык, но когда вы решили использовать C++, используйте его!

Для вашего случая std::array идеально, так как вы используете массивы четко определенного размера. Это работает так: Вы определяете размер и тип его содержимого с помощью std::array<type,size>,

Следующий код реализует вашу попытку использования std::array:

#include <iostream>
// #include <cstdlib> // use C libraries only when really needed
#include <array> 

using namespace std;

array<array<int,2>,2> strassen(array<array<int,2>,2> A, array<array<int,2>,2> B){
    int s1 = B[0][1] - B[1][1];
    int s2 = A[0][0] + A[0][1];
    int s3 = A[1][0] + A[1][1];
    int s4 = B[1][0] - B[0][0];
    int s5 = A[0][0] + A[1][1];
    int s6 = B[0][0] + B[1][1];
    int s7 = A[0][1] - A[1][1];
    int s8 = B[1][0] + B[1][1];
    int s9 = A[0][0] - A[1][0];
    int s10 = B[0][0] + B[0][1];

    int p1 = A[0][0] * s1;
    int p2 = s2 * B[1][1];
    int p3 = s3 * B[0][0];
    int p4 = A[1][1] * s4;
    int p5 = s5 * s6;
    int p6 = s7 * s8;
    int p7 = s9 * s10;

    array<array<int,2>,2> C;

    C[0][0] = p5 + p4 - p2 + p6;
    C[0][1] = p1 + p2;
    C[1][0] = p3 + p4;
    C[1][1] = p5 + p1 - p3 - p7;

    return C;
}

int main(){
    array<array<int,2>,2> A  {{{{1,3}},{{7,5}}}};
    array<array<int,2>,2> B  {{{{6,8}},{{4,2}}}};
    array<array<int,2>,2> C = strassen(A,B);
    cout<<C[0][0]<<endl<<C[0][1]<<endl<<C[1][0]<<endl<<C[1][1]<<endl;
}

Как и в случае с массивами в стиле C, двумерные массивы реализуются как массив массивов, таким образом std::array<std::array<T,size>,size>>,

Для странно выглядящего количества фигурных скобок в инициализации A а также B см. верхний ответ на вопрос: Почему нельзя просто инициализировать (с фигурными скобками) 2D std:: array? [дубликат].

Обратите внимание, что способ, которым я инициализировал массивы в main() требует -std=c++11 флаг компилятора. Компилировать с чем-то вроде gcc -std=c++11 -o strassen strassen.c

Другие вопросы по тегам