我无法读取用户的输入并将其转换为矩阵进行计算。例如,对于 input = {1 2 3/4 5 6}
,程序应该以
1 2 3
4 5 6
有 3 列和 2 行。到目前为止我得到的似乎不起作用:
input.replace(input.begin(), input.end(), '/', ' ');
stringstream ss(input);
string token;
while (getline(ss, token, ' '))
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
int tok = atoi(token.c_str());
(*matrix).setElement(i, j, tok);
}
}
}
所以我要做的是将输入分解为标记,并使用 setElement 函数将它们存储到矩阵中,该函数获取行数、列数和用户想要存储的变量。这段代码的错误在于 tok
的变量似乎没有改变并一直卡在 0
中。假设 row 和 col 是已知的。
非常感谢您的帮助。
最佳答案
虽然存在许多解决特定问题的简单方法(其他答案有各种好的建议),但让我尝试对“格式化输入”问题给出一个更一般的看法。
这里基本上存在三种问题:
- 在底层你必须做一个字符串到数字的转换
- 在更高层次上,您必须解析复合格式(理解行和行分隔)
- 最后,您还必须了解化合物的大小(有多少行和多少列?)
这 3 件事情并不完全独立,最后一件事情需要知道如何存储元素(如何调整矩阵的大小?)
最后是第 4 个问题(其他 3 个问题都存在):如果输入“错误”怎么办。
这类问题通常以两种相反的方式提供:
- 读取数据,识别格式是否匹配,并动态增长必须包含它们的数据结构或...
- 按原样读取所有数据(文本形式),然后分析文本以确定它有多少元素,然后隔离“ block ”并进行转换。
第 2 点需要良好的字符串操作,但也需要知道输入有多长的能力(如果其中一个分隔空格是换行符会发生什么?一切都通过 getline 得到的想法
在这些情况下失败)
第 1 点需要一个能够在您阅读时增长的 Matrix
类,或者一个临时的动态结构(例如和 std
容器),您可以在其中放置您阅读的内容在将其发送到适当的地方之前。
因为我不知道你的矩阵是如何工作的,所以让我保留一个临时 vector 和计数器来存储行。
#include <vector>
#include <iostream>
#include <cassert>
class readmatrix
{
std::vector<int> data; //storage
size_t rows, cols; //the counted rows and columns
size_t col; //the counting cols in a current row
Matrix& mtx; //refer to the matrix that has to be read
public:
// just keep the reference to the destination
readmatrix(Matrix& m) :data(), rows(), cols(), cols(), mtx(m)
{}
// make this class a istream-->istream functor and let it be usable as a stream
// manipulator: input >> readmatrix(yourmatrix)
std::istream& operator()(std::istream& s)
{
if(s) //if we can read
{
char c=0:
s >> c; //trim spaces and get a char.
if(c!='{') //not an open brace
{ s.setstate(s.failbit); return s; } //report the format failure
while(s) //loop on rows (will break when the '}' will be found)
{
col=0;
while(s) //loop on cols (will break when the '/' or '}' will be found)
{
c=0; s >> c;
if(c=='/' || c=='}') //row finished?
{
if(!cols) cols=col; //got first row length
else if(cols != col) //it appears rows have different length
{ s.setstate(s.failbit); return s; } //report the format failure
if(c!='/') s.unget(); //push the char back for later
break; //row finished
}
s.unget(); //pushthe "not /" char back
int x; s >> x; //get an integer
if(!s) return s; //failed to read an integer!
++col; data.push_back(x); //save the read data
}
++rows; //got an entire row
c=0; s >> c;
if(c == '}') break; //finished the rows
else s.unget(); //push back the char: next row begin
}
}
//now, if read was successful,
// we can dispatch the data into the final destination
if(s)
{
mtx.setsize(rows,cols); // I assume you can set the matrix size this way
auto it = data.begin(); //will scan the inner vector
for(size_t r=0; r<rows; ++r) for(size_t c=0; c<cols; ++c, ++it)
mtx(r,c) = *it; //place the data
assert(it == data.end()); //this must be true if counting have gone right
}
return s;
}
};
现在你可以将矩阵读作
input >> readmatrix(matrix);
此时您会注意到代码中存在某些重复出现的模式:这在单程解析中很典型,并且可以将这些模式分组以形成子解析器。如果你一般地这样做,你 - 事实上 - 将重写 boost::spirit
。
当然,可以根据矩阵的工作方式(是否固定大小??)或如果行大小不匹配(部分列填充??)做什么来进行一些调整
你甚至可以添加一个格式化的输入运算符,比如
std::istream& operator>>(std::istream& s, Matrix& m)
{ return s >> readmatrix(m); }
这样你就可以做
input >> matrix;
关于c++ - C++ 中矩阵的用户输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27243414/