【问题标题】:Function defined in scope but the compiler complains that it is out of scope在范围内定义的函数,但编译器抱怨它超出范围
【发布时间】:2023-03-28 19:30:01
【问题描述】:

我尝试为两个 2x2 矩阵实现 strassens 算法,以创建递归矩阵乘法算法,但是实现无法编译,给我如下错误:

“strassen 没有在这个范围内声明” 和 “不合格的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 空间,因为一旦函数退出返回垃圾值,我当前的C 实现就会超出范围。

【问题讨论】:

  • 您应该始终发布您的编译器/链接器错误逐字
  • "返回 C[][];" - 你到底想达到什么目的?
  • 忘掉malloc这个东西吧!不要在 C++ 中使用它!
  • 问题是您创建了一个需要 A[][] 的函数,它是一个取消引用的指针,但尝试将 main 中的指针传递给它。我敢打赌你的编译器会告诉类似“candidate strassen(...) can't be used...”
  • 由于strassen的定义中有编译错误,所以它永远不会被定义。您需要按发生的顺序修复错误。

标签: c++ scope unqualified-name


【解决方案1】:

正如许多 cmets 中提到的,您的解决方案是典型的C 风格,这可能会产生很多问题(尤其是当您是初学者时)。 C++ 为许多 C 可能变得复杂的情况提供了强大、节省内存和易于使用的解决方法。

不要误会我的意思:C 是一门很棒的语言,但是当您决定使用 C++ 时,请使用它!

对于您的情况,std::array 是完美的,因为您使用了明确定义大小的数组。它的工作原理如下:您使用std::array&lt;type,size&gt; 定义其内容的大小和类型。

以下代码使用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&lt;std::array&lt;T,size&gt;,size&gt;&gt;

对于AB 的初始化中看起来奇怪的大括号数量,请参阅Why can't simple initialize (with braces) 2D std::array? [duplicate] 的最佳答案。

请注意,我在main() 中初始化数组的方式需要-std=c++11 编译器标志。用gcc -std=c++11 -o strassen strassen.c之类的东西编译

【讨论】:

    【解决方案2】:

    您的代码无法编译有几个原因: 因为函数 strassen 没有编译,所以你得到了函数超出范围的错误,并且它没有编译,因为你正在返回一个在函数内部声明的数组。

    一个好的经验法则是永远不要返回数组,也不要将它们作为参数传递,而是使用引用,这样可以节省内存和时间。

    Heres 是一种不使用动态内存的解决方案(虽然我认为这样做会更容易)

    #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 作为对函数的引用传递,因此您在函数内部对其所做的更改也会在函数外部影响它

    【讨论】:

    • 当我们将整数传递给函数但在声明中使用“&”时,这是什么意思。像您一样,传入的 A、B、C 是参数,但是当您定义了您使用的函数时 (&A)、(&B)、(&C)。还有为什么他们在括号中。
    • 该符号表示您没有复制参数,而是发送对它们的引用,函数中的变量将引用与您作为参数传递的变量完全相同的内存空间。它们在括号中表示您发送的不是引用数组,而是对数组的引用。
    • 如果您是发送参考(即地址),为什么在完成所有相应的数学运算时不取消参考 A、B、C?
    • 因为引用不需要取消引用,所以指针就可以。这是引用和指针之间的主要区别。引用是引用另一个变量的变量,而不是存储引用的变量。
    • 无论如何都不是应该通过引用传递的数组。那么为什么要分类写(&A)等呢?
    猜你喜欢
    • 2021-10-04
    • 1970-01-01
    • 1970-01-01
    • 2019-09-24
    • 2023-03-25
    • 1970-01-01
    • 2021-01-01
    • 2018-08-30
    • 2014-06-18
    相关资源
    最近更新 更多