【问题标题】:C++ Making a 2D boolean matrixC++ 制作二维布尔矩阵
【发布时间】:2023-05-26 21:00:02
【问题描述】:

我正在制作一个程序,其中有 2 个向量(clientvecproductslist),我需要创建一个 2D 布尔矩阵,其中列的大小为 productslist 向量和这些线条是clientvec 向量的大小,但它给了我这个错误:

"表达式必须有一个常数值"

这是我使用的代码:

unsigned int lines = clientvec.size();
unsigned int columns = productslist.size();
bool matrixPublicity[lines][columns] = {false};

请帮帮我..

编辑:我是 C++ 新手,所以假设我什么都不知道 xD

Edit2:我已经知道我无法用非常数值初始化数组的答案,现在的问题是如何在初始化后放置它们...

【问题讨论】:

  • C++ 没有variable-length arrays,你需要使用std::vector(更具体地说,一个向量的向量)。
  • 即使编译器对允许 VLA 的语言进行了扩展(有些确实有这样的扩展,但我不建议您使用它),这也不是您初始化数组的方式。你确实知道如何初始化一个数组吗?你知道,花括号之类的吗?
  • 嗯,我刚开始接触 c++,所以我对 c++ 了解不多……但是数组可以是多维的,对吧?以及如何初始化一个数组?
  • 您之前已经看到过正在初始化的数组吗?喜欢int array[SOME_SIZE] = { 0 };
  • 是的,我已经更正了,但是如何使用向量的大小来制作该数组?

标签: c++ c++11 visual-c++ matrix c++14


【解决方案1】:

错误信息很清楚::expression must have a constant value"

表示数组维度不能是可变类型。只有enums 或预处理器定义的常量是有效的。

查看更多信息: Why can't I initialize a variable-sized array?

编辑:既然您提到您是 C++ 新手,这里有一段代码可能对您有所帮助:

#include <iostream>
#include <vector>
#include <bitset>

int main()
{
    unsigned int lines = 10;
    const unsigned int columns = 5;

    std::vector<std::bitset<columns>> matrixPublicity;
    matrixPublicity.resize(lines);

    for(int i=0; i < lines; i++)
    {
        for(int j=0; j < columns; j++)
            std::cout << matrixPublicity[i][j] <<' ';
        std::cout<<'\n';
    }
}

请注意,在这种情况下,columns 必须是常量。

编辑2:如果行的大小不一样,那么你必须坚持vector类型:

typedef std::vector<bool> matrixLine;
std::vector<matrixLine> matrixPublicity;

现在您可以对矩阵的第 i 行使用 resize 方法,例如

matrixPublicity[1].resize(number_of_columns_in_line_2);

【讨论】:

  • 使用std::vector&lt;std::vector&lt;bool&gt;&gt; 并调整其大小。或者在这种情况下,std::bitset 也可以提供帮助。见vector referencebitset
  • 在我的程序中,向量的大小并不总是相同,那么如何更改列数?
  • 我还需要用这些unsigned int lines = 10;const unsigned int columns = 5;进行初始化?? @Ali Reza Nameghi
  • 如果你问这个问题,不,如果你使用向量,你就不再需要那个了。 @J.Seixas
【解决方案2】:

你正在尝试做的将与此相同:

std::vector<unsigned int> v1 { 1, 2, 3, 4, 5 };
std::vector<unsigned int> v2 { 6, 7, 8, 9 };

bool mat[v1.size()][v2.size()] = false;

这是编译器在没有临时变量的情况下将如何解释它,这是无效的。当你声明一个任何类型的数组时,它的大小必须在编译时知道。

bool mat[2][3] = false; // still invalid    
bool mat[2][3] = { false }; // Okay 

const int x = 5;
const int y = 7;
bool mat[x][y] = false; // invalid
bool mat[x][y] = { false }; // okay

// Even this is invalid
std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 4, 5, 6, 7 };
const std::size_t x1 = v1.size();
const std::size_t y1 = v2.size();
bool mat2[x1][y1] = { false }; // Still won't compile.

声明数组的值必须是常量表达式。

【讨论】:

  • Thx,但现在的问题是如何在初始化后放置非常数值?
  • @J.Seixas 你看过我上面为你提供的答案吗,我创建了一个类模板,它采用两个相同类型的向量并构造另一个向量(矩阵)输入?
【解决方案3】:

您可以创建一个类模板,该模板将为您构造一个类似矩阵的对象,而不是像您尝试做的那样创建一个数组。这是我想出的,现在这个模板的整体设计或模式将适合您的条件,但生成内部矩阵的实际实现将取决于您的数据和您的意图。

#include <vector>
#include <iostream>
#include <conio.h>

template <class T, class U>
class Matrix {
private:
    std::vector<T> m_lines;
    std::vector<T> m_cols;
    std::vector<U> m_mat;
    std::size_t       m_size;
    std::size_t       m_lineCount;
    std::size_t       m_colsCount;

public:
    Matrix() {};
    Matrix( const std::vector<T>& lines, const std::vector<T>& cols ) :
        m_lines(lines),
        m_cols(cols),
        m_lineCount( lines.size() ),
        m_colsCount( cols.size() )
    {
        addVectors( lines, cols );
    }

    void addVectors( const std::vector<T>& v1, const std::vector<T>& v2 ) {
        m_lines = v1;
        m_cols  = v2;
        m_lineCount = m_lines.size();
        m_colsCount = m_cols.size();
        for ( unsigned int i = 0; i < m_lineCount; ++i ) {
            for ( unsigned int j = 0; j < m_colsCount); j++ ) {
                // This will depend on your implementation and how you
                // construct this matrix based off of your existing containers
                m_mat.push_back(m_lines[i] & m_cols[j]);
            }
        }
        m_size = m_mat.size();
    }

    std::size_t size() const { return m_size; }
    std::size_t sizeRows() const { return m_lineCount; }
    std::size_t sizelColumns() const { return m_colsCount; }

    std::vector<U>&     getMatrix() const { return m_mat; }
    std::vector<T>&     getLines() const { return m_lines; }
    std::vector<T>&     getColumns() const { return m_columns; }

    bool operator[]( std::size_t idx ) { return m_mat[idx]; }
    const bool& operator[]( std::size_t idx ) const { return m_mat[idx]; }
};

int main() {
    std::vector<unsigned> v1{ 1, 0, 1, 1, 0 };
    std::vector<unsigned> v2{ 0, 1, 1, 1, 0 };

    Matrix<unsigned, bool> mat1( v1, v2 );
    int line = 0;

    for ( unsigned u = 0; u < mat1.size(); ++u ) {
        line++;
        std::cout << mat1[u] << " ";
        if ( line == mat1.sizeRows() ) {
            std::cout << "\n";
            line = 0;
        }

    }

    std::cout << "\nPress any key to quit.\n" << std::endl;
    _getch();
    return 0;
}

输出

0 1 1 1 0
0 0 0 0 0
0 1 1 1 0
0 1 1 1 0
0 0 0 0 0

使用这个模板类,您可以通过传入T 类型的两个向量来创建任何类型U 的矩阵。现在如何构造矩阵将取决于实现。但是这个类对于不同的类型是可重用的。

您可以有两个双精度类型的向量,并构造一个无符号字符矩阵,或者您可以有两个用户定义的类或结构类型的向量,并生成一个无符号值矩阵。这可能会在许多情况下帮助您。

注意: - 这确实会生成编译器警告,但没有错误,并且可以正确打印和显示,但是 MSVS 2015 生成的编译器警告是警告 C4800: unsigned int: forcing value to bool true or false (performance warning)

这是因为我正在对无符号值进行一些明智的 & 操作而生成的;但这就是为什么我将初始向量设置为传递给此类模板的构造函数以具有所有 1 和 0,因为这仅用于演示。

编辑 - 我对类进行了编辑,因为我注意到我有一个默认构造函数并且无法向其中添加向量,所以我添加了一个额外的成员变量和一个 addVectors 函数,并将实现从定义的构造函数移动到新函数,并最终在定义的构造函数中调用该函数。

【讨论】:

    【解决方案4】:

    创建一个数组并不难 :) 不幸的是,如果您想按照自己的方式进行操作,矩阵(2D/3D/...-array)会有些不同!

    但首先你应该了解堆栈和堆!

    让我们看看这两个:

    堆栈:

    堆栈变量/数组/矩阵/...仅在最近的 2 -> {}

    例子:

    #include <iostream>
    #define MACRO 128
    
    int arraySize(int size){
        std::cin >> size;
        return size;
    }
    
    int main() {
    
        //this is valid
        int intArray[128] = {}; //the size(here: 128) needs to be a number like
                                //or a macro like 'MACRO' which is
                                //compile-time-only as well
    
        //this is valid 
        int intArray2[MACRO] = {};
    
        //this is not valid!
        int intArray[size()] = {};
    
        return 0;
    }
    

    堆:

    堆变量/数组/矩阵/...在您删除它之前一直有效。这也意味着在运行时(从启动程序直到关闭/停止它)会创建一个堆变量!这允许您定义它的大小。

    例子:

    #include <iostream>
    #define MACRO 128
    
    int arraySize(int size){
        return size;
    }
    
    int main() {
    
        //this is valid
        int intArray[128] = {}; //the size(here: 128) needs to be a number like
                                //or a macro like 'MACRO' whic is
                                //compile-time-only as well
    
        //this is valid 
        int intArray2[MACRO] = {};
    
        //creating an array with a non-static size
        //works like this:
        //int can also be a 'bool'
        int* intArray = new int[arraySize()];
        // ^ the star means you are pointing to
        //an adress inside of your memory which has
        //the size of an int (per element)
        //That's why they are called "pointers"!
        //Right now it points to the beginning of the
        //array.
    
        //               ^ the keyword "new" says that
        //you are allocating memory on the heap.
    
        //                    ^
        //then you have to say which kind of array
        //it is which is the same you gave the pointer
    
        //                          ^
        //now you give it the size of that array
        //this time it can be return value or the size
        //of a variable
    
        //as I mentioned...you have to delete this array on your own
        //if you dont do that your program will crash
        //maybe not after starting but it will!
        //SO NEVER NEVER NEVER... forget about it
        delete intArray[];
    
        //^ write delete
    
        //          ^
        //then the name of your array
    
        //              ^
        //at the end of it write these 2 brackets
        //thex say you wanna remove the whole array!
        //why? because you can also create/delete 
        //heap variables not only arrays.
    
        return 0;
    }
    

    不幸的是,在堆上创建一个矩阵并不容易。 但在进一步研究之前了解一维数组的工作原理是很重要的!这就是我编写本教程的原因!

    点击here查看如何在堆上创建矩阵

    点击here了解更多关于堆的信息

    点击here选择这个主题的最佳结果

    希望能帮到你:)!

    【讨论】: