我遇到了这个程序的问题。该程序旨在从一个以逗号分隔的名称形式的文件中获取输入,并将它们计算在输出文件中(我还没有得到)。它在“好到目前为止3”之前失败了。显然,它正在打破的是使迭代器退缩。也就是说,我正在尝试做的是将它用作指针,而++那个指针。这应该跳到数组中的下一个结构。然后,我想使用它 - > inputName来访问struct内部的东西。但是,当我这样做 - > inputName时,它会尝试将它用作指针而不能这样做。不知道从哪里开始,如果我尝试制作像name *那样的常规指针,它不能与nameStorage.begin()一起使用,因为它只需要一个迭代器。我在Windows 7上使用Microsoft Visual Studio 2010,如果有帮助的话。
我对编程很新,所以其他任何提示也都很棒。谢谢!
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct name{
int tally;
string inputName;
};
bool die( const string& message );
int main( void ) {
ifstream infile;
infile.open( "input.txt", ifstream::in );
vector<name> nameStorage; // stores all names and tallies of them
vector<name>::iterator it;
string tempInput; // Stores the most recent input temporarily
char temp;
int counter = 0;
while ( temp = infile.get(), infile.good() ) { // loop while extraction from file is possible
if ( temp != ',' ) {
tolower ( temp ); // makes everything lowercase
tempInput.push_back(temp); }
else {
cout<<"good so far"<<endl;
for ( it = nameStorage.begin(); it <= nameStorage.end(); it++ ) {
cout<<"good so far 2"<<endl;
if ( tempInput == it->inputName ) {
cout<<"good so far 3"<<endl;
it->tally++;
break;
}
else if ( it == nameStorage.end() ) {
name tempStruct;
tempStruct.inputName = tempInput;
tempStruct.tally = 1;
nameStorage.push_back( tempStruct );
}
}
tempInput.clear(); // clears the string after it has stored it
}
counter++;
cout<<"Detected "<<counter<<" characters so far."<<endl;
}
}
bool die( const string& message ) {
cerr<<message;
exit (EXIT_FAILURE);
}
答案 0 :(得分:2)
变化:
for ( it = nameStorage.begin(); it <= nameStorage.end(); it++ )
要:
for ( it = nameStorage.begin(); it != nameStorage.end(); it++ )
移动:
else if ( it == nameStorage.end() ) {
name tempStruct;
tempStruct.inputName = tempInput;
tempStruct.tally = 1;
nameStorage.push_back( tempStruct );
}
从你现在更改的for循环中,你不需要else,因为这是for循环结束的条件:
name tempStruct;
tempStruct.inputName = tempInput;
tempStruct.tally = 1;
nameStorage.push_back( tempStruct );
请查看此简单示例here。
答案 1 :(得分:2)
此代码至少有4个问题,其中最重要的是使用向量进行此类查找/计数是非常低效的。
1)std :: vector :: end()返回一个特殊类型的迭代器,它不支持布尔运算符,例如&lt; =(但支持operator-或operator- =)。好吧,它支持它们,但行为未定义。
所以
for ( it = nameStorage.begin(); it <= nameStorage.end(); it++ )
应该是
for ( it = nameStorage.begin(); it != nameStorage.end(); it++ )
2)现在你的for语句是正确的,这个比较将永远不会返回true
else if ( it == nameStorage.end() ) {
因此您的新值永远不会存储在向量中。要在nameStorage中查找tempInput,您可以使用std :: find
if (std::find(nameStorage.begin(), nameStorage.end(), tempInput) != nameStorage.end())
{
/// temp struct blah blah blah
nameStorage.push_back(tempStruct);
}
3)在字符串上使用布尔等价运算符通常被认为是不良形式,即
if ( tempInput == it->inputName ) {
应该是
if (!tempInput.compare(it->InputName))
但如果您使用std :: find(上面),则不需要这样做。
4)std :: getline支持分隔符,你应该使用它而不是一次读取1个字符,参见http://www.cplusplus.com/reference/string/getline/
最后,您应该使用地图进行查找/计数。 std:地图很好
std::map<std::string, int> nameStorage;
if (nameStorage.find(tempInput) != nameStorage.end())
{
nameStorage[tempInput]++;
} else
{
nameStorage[tempInput] =1;
}
答案 2 :(得分:1)
vector
的范围[ begin(), end() )
,end()
不包含在该有效元素范围内。 end()
指的是一个元素(如果你可以称之为){em>超过vector
的结尾。
因此,it == nameStorage.end()
显然会出现解除引用迭代器的问题,因为it
不会引用现有元素:
if ( tempInput == it->inputName )
该约定将在!= end()
上终止,这将消除上述的一个一个问题:
for ( it = X.begin(); it != X.end(); it++ )
迭代器的想法是让内部完全隐藏起来;迭代器的值可能不一定大于下一个元素的值。
在这种情况下,您将减少一次迭代,条件else if (it == nameStorage.end())
永远不会成立。但是,您可以在 for
循环之后简单地添加该语句的主体,因为一旦循环终止,您就会迭代到vector
的末尾。
答案 3 :(得分:0)
您尚未向nameStorage
添加任何元素,因此您无法迭代该vector
容器的元素。因为你没有在for循环中正确地检查向量迭代器上的边界,所以它允许你进入你的循环,并且在那里你取消引用一个没有指向任何东西的迭代器。通过尝试访问尚未分配的内存,您将调用未定义的行为,如果您损坏内存但未能崩溃,则很可能会导致分段错误或其他一些奇怪的问题。
答案 4 :(得分:0)
添加另一个答案以涵盖有关地图和std :: getline
的问题映射是一个关联容器,它将键与值相关联。例如,std :: map是一个带有std :: string类型的键的映射,以及一个int类型的值。地图支持快速查找密钥(log(n))。例如
std::map<std::string, int> nameCount;
是否存储与字符串键关联的int值的映射。 (在解释std :: getline之后参见代码示例)。
std :: getline将指定的分隔符视为行尾字符。使用它的常用方法是首先获取由EOL分隔的整行,然后使用分隔符从该行获取行。 ''
这是一些可以达到你想要的代码。
std::map<std::string, int> nameCount;
std::ifstream myfile(filename.c_str(),std::ios::in);
std::string line;
while(std::getline(myfile, line))
{
std::stringstream linestream(line);
std::string name;
while (std::getline(linestream, name, ','))
{
if (nameCount.find(name) != nameCount.end())
{
nameCount[name]++; // increases the tally for name
}
else
{
nameCount[name] = 1; // inserts name into map and sets the tally to 1
}
}
}
// now output the map
std::map<std::string, int>::iterator namecountitr;
for (namecountitr = nameCount.begin();
namecountitr != nameCount.end(); namecountitr++)
{
std::cout << namecountitr->first.c_str() << ":"
<< namecountitr->second << std::endl;
}
享受。