Infinite loop on 'getline' in Visual Studio 2010 - c++

I am working through some C++ exercises in Visual Studio 2010, and I keep having problems with an infinite loop which occurs when I try to terminate a standard in stream with "CTRL-Z", when using the getline() function. Here is the relevant bit of code....
// find all the lines that refer to each word in the input
map<string, vector<int> >
xref(istream& in,
vector<string> find_words(const string&) = split)
{
string line;
int line_number = 0;
map<string, vector<int> > ret;
// read the next line
while (getline(in, line)) {
++line_number;
// break the input line into words
vector<string> words = find_words(line);
// remember that each word occurs on the current line
for (vector<string>::const_iterator it = words.begin();
it != words.end(); ++it)
ret[*it].push_back(line_number);
}
return ret;
}
...instead of kicking me out of the while loop, the program goes into an infinite loop printing a random integer. I'm pretty sure this is something specific to the Windows environment that I'm missing. Here's the entire code...
#include <algorithm>
#include <cctype>
#include <string>
#include <vector>
#include "split.h"
using std::find_if;
using std::string;
using std::vector;
using std::isspace;
// `true' if the argument is whitespace, `false' otherwise
bool space(char c)
{
return isspace(c);
}
// `false' if the argument is whitespace, `true' otherwise
bool not_space(char c)
{
return !isspace(c);
}
vector<string> split(const string& str)
{
typedef string::const_iterator iter;
vector<string> ret;
iter i = str.begin();
while (i != str.end()) {
// ignore leading blanks
i = find_if(i, str.end(), not_space);
// find end of next word
iter j = find_if(i, str.end(), space);
// copy the characters in `[i,' `j)'
if (i != str.end())
ret.push_back(string(i, j));
i = j;
}
return ret;
}
#include <map>
#include <iostream>
#include <string>
#include <vector>
#include "split.h"
using std::cin; using std::cout;
using std::endl; using std::getline;
using std::istream; using std::string;
using std::vector; using std::map;
// find all the lines that refer to each word in the input
map<string, vector<int> >
xref(istream& in,
vector<string> find_words(const string&) = split)
{
string line;
int line_number = 0;
map<string, vector<int> > ret;
// read the next line
while (getline(in, line)) {
++line_number;
// break the input line into words
vector<string> words = find_words(line);
// remember that each word occurs on the current line
for (vector<string>::const_iterator it = words.begin();
it != words.end(); ++it)
ret[*it].push_back(line_number);
}
return ret;
}
int main()
{
// call `xref' using `split' by default
map<string, vector<int> > ret = xref(cin);
// write the results
for (map<string, vector<int> >::const_iterator it = ret.begin();
it != ret.end(); ++it) {
// write the word
cout << it->first << " occurs on line(s): ";
// followed by one or more line numbers
vector<int>::const_iterator line_it = it->second.begin();
cout << *line_it; // write the first line number
++line_it;
// write the rest of the line numbers, if any
while (line_it != it->second.end()) {
cout << ", " << *line_it;
++line_it;
}
// write a new line to separate each word from the next
cout << endl;
}
return 0;
}

I think instead of trying to make this work, I'd start by writing code I could understand (and for me to understand it, the code has to be fairly simple):
#include <map>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include "infix_iterator.h"
typedef std::map<std::string, std::vector<unsigned> > index;
namespace std {
ostream &operator<<(ostream &os, index::value_type const &i) {
os << i.first << ":\t";
std::copy(i.second.begin(), i.second.end(),
infix_ostream_iterator<unsigned>(os, ", "));
return os;
}
}
void add_words(std::string const &line, size_t num, index &i) {
std::istringstream is(line);
std::string temp;
while (is >> temp)
i[temp].push_back(num);
}
int main() {
index i;
std::string line;
size_t line_number = 0;
while (std::getline(std::cin, line))
add_words(line, ++line_number, i);
std::copy(i.begin(), i.end(),
std::ostream_iterator<index::value_type>(std::cout, "\n"));
return 0;
}
As (more or less) usual, this needs the infix_ostream_iterator I've posted elsewhere.

Related

Finding ALL Non Repeating characters in a given string

So I was given the question:
Find ALL of the non-repeating characters in a given string;
After doing some Google searching it was clear to me that finding the first non repeating character was pretty common. I found many examples of how to do that, but I have not really found anything on how to find ALL of the non repeating characters instead of just the first one.
my example code so far is:
#include <iostream>
#include <unordered_map>
using namespace std;
char findAllNonRepeating(const string& s) {
unordered_map<char, int> m;
for (unsigned i = 0; i < s.length(); ++i) {
char c = tolower(s[i]);
if (m.find(c) == m.end())
m[c] = 1;
else
++m[c];
}
auto best = m.begin();
for (auto it = m.begin(); it != m.end(); ++it)
if (it->second <= best->second)
best = it;
return (best->first);
}
int main()
{
cout << findAllNonRepeating("dontknowwhattochangetofindallnonrepeatingcharacters") << endl;
}
I am not sure what I need to change or add to have this find all of the non repeating characters.
k, f, p, s should be the non repeating characters in this string.
Any hints or ideas are greatly appreciated!
As suggested, simply keep a frequency map. Then, once the string is processed, iterate over the map, returning only those values that occur exactly once.
#include <iostream>
#include <map>
#include <vector>
using namespace std;
std::vector<char> nonRepeating(const std::string& s)
{
std::map<char, int> frequency;
for(int i=0;i<s.size();i++)
{
frequency[s[i]]++;
}
std::vector<char> out;
for(auto it = frequency.begin(); it != frequency.end(); it++)
{
if(it->second == 1)
out.push_back(it->first);
}
return out;
}
int main() {
// your code goes here
std::string str = "LoremIpsum";
for(char c : nonRepeating(str))
{
std::cout << c << std::endl;
}
return 0;
}

C++, undefined reference to a function that despite including it's header [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 7 years ago.
I'm pretty new to C++, and working through a book called "Accelerated C++." In one of the chapters you are suppose to make a program that, given a string of text, tells you what line(s) each word appears on. To break up all of the words in the string, i used a function called 'split' from a different source file, but included its header file so I could use it. It didn't work though. For the life of me I can't figure out why the linker tells me "undefined reference to 'split(std::string const&)'
split.cpp:
#include <string>
#include <cctype>
#include <vector>
#include "split.h"
using namespace std;
bool space(char c) {
return isspace(c);
}
bool not_space(char c) {
return !isspace(c);
}
vector<string> split(const string& s) {
vector<string> ret;
string::const_iterator i = s.begin();
while (i != s.end()) {
i = find_if(it, s.end(), not_space);
string::const_iterator j = i;
j = find_if(j, s.end(), space);
if (i != s.end())
ret.push_back(string(i, j));
i = j;
}
return ret;
}
split.h:
#ifndef GUARD_split_h
#define GUARD_split_h
#include <string>
#include <vector>
bool space(char);
bool not_space(char);
std::vector<std::string> split(const std::string&);
#endif
Word_Counter.cpp:
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include "split.h"
using namespace std;
map<string, vector<int> > xref(istream& in, vector<string>
find_words(const string&) = split) {
string line;
int line_number = 0;
map<string, vector<int> > ret;
while (getline(in, line)) {
++line_number;
vector<string> words = find_words(line);
for (vector<string>::const_iterator it = words.begin();
it != words.end(); it++)
ret[*it].push_back(line_number);
}
return ret;
}
int main() {
map<string, vector<int> > ret = xref(cin);
for(map<string, vector<int> >::const_iterator it = ret.begin();
it != ret.end(); it++) {
cout << it->first << "occurs on line(s): ";
vector<int>::const_iterator line_it = it->second.begin();
cout << *line_it;
line_it++;
while(line_it != it->second.end()) {
cout << ", " << *line_it;
line_it++;
}
cout << endl;
}
return 0;
}
I've been having a tough time with headers in general lately. Any help is greatly appreciated!
If you have sources split in several files, you need to make the compiler aware of all them. The simplest way is to list all .cpp files (not .h files!) on the command line:
g++ Word_Counter.cpp split.cpp -o Word_Counter

Counting occurrences of word in vector of characters

I have written a program to store a text file in vector of characters .
#include<iostream>
#include<fstream>
#include <algorithm>
#include<vector>
using namespace std;
int main()
{
vector<char> vec;
ifstream file("text.txt");
if(!file.eof() && !file.fail())
{
file.seekg(0, std::ios_base::end);
std::streampos fileSize = file.tellg();
vec.resize(fileSize);
file.seekg(0, std::ios_base::beg);
file.read(&vec[0], fileSize);
}
int c = count(vec.begin(), vec.end(), 'U');
cout << c;
return 0;
}
I want to count occurrence of "USER" in the text file , but using count i can only count number of characters . How can i count number of occurrences of "USER" in the vector of character?
For example
text.txt
USERABRUSER#$$* 34 USER ABC RR IERUSER
Then the count of "USER" is 4. Words can only be in uppercase.
std::string has a find member function that will find an occurrence of one string inside another. You can use that to count occurrences something like this:
size_t count(std::string const &haystack, std::string const &needle) {
auto occurrences = 0;
auto len = needle.size();
auto pos = 0;
while (std::string::npos != (pos = haystack.find(needle, pos))) {
++occurrences;
pos += len;
}
return occurrences;
}
For example:
int main() {
std::string input{ "USERABRUSER#$$* 34 USER ABC RR IERUSER" };
std::cout << count(input, "USER");
}
...produces an output of 4.
This is how I would do it:
#include <fstream>
#include <sstream>
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;
int main() {
unordered_map<string, size_t> data;
string line;
ifstream file("text.txt");
while (getline(file, line)) {
istringstream is(line);
string word;
while (is >> word) {
++data[word];
}
}
cout << data["USER"] << endl;
return 0;
}
Let's try again. Once again, a vector isn't necessary. This is what I would consider to be the most C++ idiomatic way. It uses std::string's find() method to repeatedly find the substring in order until the end of the string is reached.
#include <fstream>
#include <iostream>
#include <string>
int main() {
// Read entire file into a single string.
std::ifstream file_stream("text.txt");
std::string file_contents(std::istreambuf_iterator<char>(file_stream),
std::istreambuf_iterator<char>());
unsigned count = 0;
std::string substr = "USER";
for (size_t i = file_contents.find(substr); i != std::string::npos;
i = str.find(substr, i + substr.length())) {
++count;
}
}

C++ split string by line

I need to split string by line.
I used to do in the following way:
int doSegment(char *sentence, int segNum)
{
assert(pSegmenter != NULL);
Logger &log = Logger::getLogger();
char delims[] = "\n";
char *line = NULL;
if (sentence != NULL)
{
line = strtok(sentence, delims);
while(line != NULL)
{
cout << line << endl;
line = strtok(NULL, delims);
}
}
else
{
log.error("....");
}
return 0;
}
I input "we are one.\nyes we are." and invoke the doSegment method. But when i debugging, i found the sentence parameter is "we are one.\\nyes we are", and the split failed. Can somebody tell me why this happened and what should i do. Is there anyway else i can use to split string in C++. thanks !
I'd like to use std::getline or std::string::find to go through the string.
below code demonstrates getline function
int doSegment(char *sentence)
{
std::stringstream ss(sentence);
std::string to;
if (sentence != NULL)
{
while(std::getline(ss,to,'\n')){
cout << to <<endl;
}
}
return 0;
}
You can call std::string::find in a loop and the use std::string::substr.
std::vector<std::string> split_string(const std::string& str,
const std::string& delimiter)
{
std::vector<std::string> strings;
std::string::size_type pos = 0;
std::string::size_type prev = 0;
while ((pos = str.find(delimiter, prev)) != std::string::npos)
{
strings.push_back(str.substr(prev, pos - prev));
prev = pos + delimiter.size();
}
// To get the last substring (or only, if delimiter is not found)
strings.push_back(str.substr(prev));
return strings;
}
See example here.
#include <sstream>
#include <string>
#include <vector>
std::vector<std::string> split_string_by_newline(const std::string& str)
{
auto result = std::vector<std::string>{};
auto ss = std::stringstream{str};
for (std::string line; std::getline(ss, line, '\n');)
result.push_back(line);
return result;
}
#include <iostream>
#include <string>
#include <regex>
#include <algorithm>
#include <iterator>
using namespace std;
vector<string> splitter(string in_pattern, string& content){
vector<string> split_content;
regex pattern(in_pattern);
copy( sregex_token_iterator(content.begin(), content.end(), pattern, -1),
sregex_token_iterator(),back_inserter(split_content));
return split_content;
}
int main()
{
string sentence = "This is the first line\n";
sentence += "This is the second line\n";
sentence += "This is the third line\n";
vector<string> lines = splitter(R"(\n)", sentence);
for (string line: lines){cout << line << endl;}
}
We have a string with multiple lines
we split those into an array (vector)
We print out those elements in a for loop
Using the library range-v3:
#include <range/v3/all.hpp>
#include <string>
#include <string_view>
#include <vector>
std::vector<std::string> split_string_by_newline(const std::string_view str) {
return str | ranges::views::split('\n')
| ranges::to<std::vector<std::string>>();
}
Using C++23 ranges:
#include <ranges>
#include <string>
#include <string_view>
#include <vector>
std::vector<std::string> split_string_by_newline(const std::string_view str) {
return str | std::ranges::views::split('\n')
| std::ranges::to<std::vector<std::string>>();
}
This fairly inefficient way just loops through the string until it encounters an \n newline escape character. It then creates a substring and adds it to a vector.
std::vector<std::string> Loader::StringToLines(std::string string)
{
std::vector<std::string> result;
std::string temp;
int markbegin = 0;
int markend = 0;
for (int i = 0; i < string.length(); ++i) {
if (string[i] == '\n') {
markend = i;
result.push_back(string.substr(markbegin, markend - markbegin));
markbegin = (i + 1);
}
}
return result;
}

Accelerated C++ exercise 8-5 solution not clear

I am stuck at solving Accelerated C++ exercise 8-5 and I don't want to miss a single exercise in this book.
Accelerated C++ Exercise 8-5 is as follows:
Reimplement the gen_sentence and xref functions from Chapter 7 to use
output iterators rather than putting their entire output in one data
structure. Test these new versions by writing programs that attach the
output iterator directly to the standard output, and by storing the
results in list <string> and map<string, vector<int> >, respectively.
To understand scope of this question and current knowledge in this part of the book - this exercise is part of chapter about generic function templates and iterator usage in templates. Previous exercise was to implement simple versions of <algorithm> library functions, such as equal, find, copy, remove_copy_if etc.
If I understand correctly, I need to modify xref function so it:
Use output iterator
Store results in map<string, vector<int> >
I tried to pass map iterator as back_inserter(), .begin(), .end() to this function, but was not able to compile it. Answer here explains why.
xref function as in Chapter 7:
// find all the lines that refer to each word in the input
map<string, vector<int> >
xref(istream& in,
vector<string> find_words(const string&) = split)
{
string line;
int line_number = 0;
map<string, vector<int> > ret;
// read the next line
while (getline(in, line)) {
++line_number;
// break the input line into words
vector<string> words = find_words(line);
// remember that each word occurs on the current line
for (vector<string>::const_iterator it = words.begin();
it != words.end(); ++it)
ret[*it].push_back(line_number);
}
return ret;
}
Split implementation:
vector<string> split(const string& s)
{
vector<string> ret;
typedef string::size_type string_size;
string_size i = 0;
// invariant: we have processed characters `['original value of `i', `i)'
while (i != s.size()) {
// ignore leading blanks
// invariant: characters in range `['original `i', current `i)' are all spaces
while (i != s.size() && isspace(s[i]))
++i;
// find end of next word
string_size j = i;
// invariant: none of the characters in range `['original `j', current `j)' is a space
while (j != s.size() && !isspace(s[j]))
++j;
// if we found some nonwhitespace characters
if (i != j) {
// copy from `s' starting at `i' and taking `j' `\-' `i' chars
ret.push_back(s.substr(i, j - i));
i = j;
}
}
return ret;
}
Please help to understand what am i missing.
I found more details on the exercise, here: https://stackoverflow.com/questions/5608092/accelerated-c-exercise-8-5-wording-help:
template <class Out>
void gen_sentence( const Grammar& g, string s, Out& out )
USAGE:
std::ostream_iterator<string> out_str (std::cout, " ");
gen_sentence( g, "<sentence>", out_str );
template <class Out, class In>
void xref( In& in, Out& out, vector<string> find_words( const string& ) = split )
USAGE:
std::ostream_iterator<string> out_str (std::cout, " ");
xref( cin, out_str, find_url ) ;
Frankly, I have to come to the conclusion that that question is ill-posed, specifically where they specified the new interface for xref: xref should result in a map. However, using output iterators would imply using std::inserter(map, map.end()) in this case. While you can write a compiling version of the code, this will not do what you expect since map::insert will simply ignore any insertions with duplicated keys.
If the goal of xref is only to link the words to the line number of their first appearance this would still be ok, but I have a feeling that the author of the exercise simply missed this subtler point :)
Here is the code anyways (note that I invented a silly implementation for split, because it was both missing and required):
#include <map>
#include <vector>
#include <iostream>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <iterator>
std::vector<std::string> split(const std::string& str)
{
std::istringstream iss(str);
std::vector<std::string> result;
std::copy(std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>(),
std::back_inserter(result));
return result;
}
// find all the lines that refer to each word in the input
template <typename OutIt>
OutIt xref(std::istream& in,
OutIt out,
std::vector<std::string> find_words(const std::string&) = split)
{
std::string line;
int line_number = 0;
// read the next line
while (getline(in, line)) {
++line_number;
// break the input line into words
std::vector<std::string> words = find_words(line);
// remember that each word occurs on the current line
for (std::vector<std::string>::const_iterator it = words.begin();
it != words.end(); ++it)
*out++ = std::make_pair(*it, line_number);
}
return out;
}
int main(int argc, const char *argv[])
{
std::map<std::string, int> index;
std::ifstream file("/tmp/test.cpp");
xref(file, std::inserter(index, index.end()));
#if __GXX_EXPERIMENTAL_CXX0X__
for(auto& entry: index)
std::cout << entry.first << " first found on line " << entry.second << std::endl;
#else
for(std::map<std::string, int>::const_iterator it = index.begin();
it != index.end();
++it)
{
std::cout << it->first << " first found on line " << it->second << std::endl;
}
#endif
return 0;
}