string Vector push_back failing in class - c++

I have a class with a method that should return a vector of strings. the getCommVector method has to push_back the elements of a string array into a string vector that can then be returned by the method. When trying to add a string element to the string vector i get:
libc++abi.dylib: terminate called throwing an exception
2Program ended with exit code: 0
I cannot understand why I can't push_back strings to the vector. Any ideas?
Thanks in advance!
code segments of interest (edited after suggestions):
class Command {
public:
//Command (std::string, bool, bool);
void setOperators(std::string,bool, bool);
void analyseCommand();
Command();
std::vector<std::string> getCommVector ();
private:
int numOperators; //number of total commands
int opCount; //current command number
std::string input_string;
bool field_command, byte_command;
std::string commVector[3];
std::vector<std::string> finalCommVector;
void byte_analysis();
void field_analysis();
void decode_command();
void syntax_error();
void decode_error();
};
Command::Command() : numOperators(0), opCount(0), field_command(false),byte_command(false)
{
}
std::vector<std::string> Command::getCommVector ()
{
std::string s ="test";
finalCommVector.push_back("s");
return finalCommVector;
}
adding SSCE:
class Command {
public:
//Command (std::string, bool, bool);
void setOperators(std::string,bool, bool);
void analyseCommand();
Command();
std::vector<std::string> getCommVector ();
private:
int numOperators; //number of total commands
int opCount; //current command number
std::string input_string;
bool field_command, byte_command;
std::string commVector[3];
std::vector<std::string> finalCommVector;
void byte_analysis();
void field_analysis();
void decode_command();
void syntax_error();
void decode_error();
};
Command::Command() : numOperators(0), opCount(0), field_command(false),byte_command(false)
{
}
void Command::syntax_error()
{
std::cout<<"Incorrect Syntax Error: Usage: linuxcut -b num -f num \n";
exit(EXIT_FAILURE);
}
void Command::decode_error()
{
std::cout<<"Decode Error: Usage: linuxcut -b num -f num \n";
exit(EXIT_FAILURE);
}
void Command::analyseCommand()
{
if (byte_command) {
//start byte command analysys
byte_analysis();
}
else if (field_command)
{
//start field command analysys
field_analysis();
}
}
void Command::setOperators(std::string input_argument, bool is_field, bool is_byte)
{
input_string = input_argument;
field_command = is_field;
byte_command = is_byte;
}
std::vector<std::string> Command::getCommVector ()
{
std::string s = "ssd";
finalCommVector.push_back(s);
/*
for (int i = 0; i<sizeof(commVector); i++)
{
if (commVector[i] != "")
{
//debug
std::cout<<"asdas";
}
}
*/
return finalCommVector;
}
void Command::byte_analysis()
{
int next_state = 0;
int dashCount = 0;
int commVectIndex = 0;
//iterate through string and check if the argument is valid
for (int i= 0; i<input_string.length(); i++) {
switch (next_state) {
case 0: //start
//if character is a number:
if (isdigit(input_string.at(i)))
{
//first elemnt of command commVector is number
commVector[commVectIndex]+=input_string.at(i);
//DEBUG
std::cout<<commVector[commVectIndex];
next_state = 1;
}
//if character is a dash:
else if (input_string[i] == '-')
{
//increment dashCount
dashCount++;
//if next character in input_string is a number continue
if (isdigit(input_string[i+1])) {
commVector[commVectIndex]+=input_string.at(i);
commVectIndex++;
next_state = 1;
}
else //else error
{
syntax_error();
}
}
//if it's niether: error!
else
{
syntax_error();
}
break;
case 1:
//if next character is a number:
if (isdigit(input_string[i]))
{
commVector[commVectIndex]+=input_string.at(i);
next_state = 1;
}
//if next character is dash
else if (input_string[i] == '-'&& dashCount <= 3)
{
dashCount++;
//increment commandVectIndex
commVectIndex++;
next_state = 2;
commVector[commVectIndex]+=input_string.at(i);
//increment commandVectIndex to accomodate next operation
commVectIndex++;
}
//if it's niether: error!
else
{
syntax_error();
}
break;
case 2://previous character was dash
//if next character is number
if (isdigit(input_string[i]))
{
commVector[commVectIndex]+=input_string.at(i);
next_state = 1;
}
//if it's niether: error!
else
{
syntax_error();
}
break;
default:
syntax_error();
break;
}
}
}
void Command::field_analysis()
{
}
/*****************FUNCTIONS DEFINITIONS***************/
void print_usage() {
std::cout<<"Incorrect Syntax Error: Usage: linuxcut -b num -f num \n";
}
/*****************END OF FUNCTIONS DEFINITIONS***************/
/***************** MAIN ***************/
int main(int argc, char *argv[]) {
int opt= 0;
std::string byte = "-1-2,2",field = "";
std::string sub_arg_delimiter = ","; //delimiter for comma serparated arguments
static bool complement = false;
int diffOpt = 0; //stores the difference between optind and argc to read filenames in command
std::string fileName;
//Specifying the expected options
//The two options l and b expect numbers as argument
static struct option long_options[] = {
{"byte", required_argument, 0, 'b' },
{"field", required_argument, 0, 'f' },
{"complement", no_argument, 0, 0 },
{0, 0, 0, 0 }
};
Command testCommand;
testCommand.setOperators("-2-", false, true);
std::vector<std::string> trial = testCommand.getCommVector();
std::cout<<"filename:"<<fileName<<std::endl;
std::cout<<"Selected flags:\n"<< "b: "<< byte<<"\nf: "<<field<<"\ncomplement: "<<complement<<std::endl;
return 0;
}

You're iterating way beyond the array size. sizeof(commVector) returns the size of the array in bytes.
If you have C++11 available, you can do this:
for (const auto &s : commVector) {
if (s != "") {
// as before
}
}
Or at least this (if you only have partial C++11 support):
for (auto it = std::begin(commVector); it != std::end(commVector); ++it) {
std::string s = *it;
// the rest as before
}
Without C++11, you can at least do this:
for (int i = 0; i < sizeof(commVector) / sizeof(commVector[0]); ++i) {
// the rest as before
}
Or provide your own function for obtaining the correct array size:
template <class T, size_t N>
size_t arraySize(const T (&)[N]) { return N; }
// Use:
for (size_t i = 0; i < arraySize(commVector); ++i) {
// the rest as before
}

i<sizeof(commVector);
should be
i<countof(commVector);
if countof/_countof is defined for your compiler. If not, you can do it yourself, it is typically defined as:
#define countof(a) (sizeof(a)/sizeof(a[0]))
and I won't go into discussion about using macros in C++ :)
Of course, you could also use a constant are your array has fixed number of elements, but I guess it's just an example.
sizeof returns the size of the object (in this case the string array) itself, not the count of elements inside the vector.
Because of this, it is equal to number of the array elements multiplied by size of a single string instance, so you try to access non-existing items with operator[].
This is also broken:
finalCommVector.push_back("s");
and probably you meant:
finalCommVector.push_back(s);

If all you need is the array of std::string commVector as a std::vector<String>, you can use std::vecor::assign:
finalCommVector.assign(commVector, commVector+3)
The '3' is the length of you array.

Related

Checking if a word is a palindrome by reversing a stack without using any prewritten functions

#include <iostream>
#include <string>
using namespace std;
#define Max 100000
class Stack {
private:
int top =-1;
char letters[Max];
public:
void setTop(int t) {
top = t;
}
int getTop() {
return top;
}
bool isEmptyStack() {
if (top == -1) {
return true;
}
else{ return false;
}
}
char push(char x,int s) {
if (top != s - 1){
top++;
x = letters[top];
return x;
}
}
char pop() {
if ((isEmptyStack())==false){
cout << "the deleted value is: " << l[top]<<endl;
top--;
return l[top];
}
}
};
void reverse(char letters[], char temp[], int size, Stack stack) {
int i=0;
for (i = 0; i < size; i++) {
stack.push(letters[i],size);
}
i = 0;
cout << temp<<endl;
while (stack.isEmptyStack() == false)
{
letters[-1] = stack.getTop();
stack.pop();
stack.push(letters[i],size);
i++;
}
/* for (int i = 0; i < size; i++) {
cout << temp[i];
}*/
}
int myStringLength(const char* letter)
{
for (int i = 0, c = 0; letter[i] != '\0'; i++, c++) {
if (letter[i] != '\0')
for (; letter[i] != '\0'; i++, c++)
if (letter[i] == '\0') break;
return c;
}
}
int main()
//initializes the main function
{
Stack stack;
string w;
std::cout << "Enter a Word: ";
getline(cin,w);
char* letters = &w[0];
// sets the character text array to set the number of characters equal to the size of the string
//calls the processData function
std::cout << letters<<endl;
int size = myStringLength(letters);
reverse(letters, letters, size, stack);
return 0;//returns the function at 0.
}
I set out to create a program that will check if a word is a palindrome(meaning it is spelled the same normally and if the word is reversed.) I am not yet at that point that is just the final objective. In my code, I have created a stack class because I wanted to feel the satisfaction of getting the same result using my own code. My problem is the stack is not reversing it is returning some weird characters that I don't have the keys on my keyboard to replicate.
The desired outcome should be word's reversed characters.
if the word is food the function should be returning doof. I have already compared the reversed stack to the original and printed the final statement. I fixed the char letters[];
If you're open to using a simple function instead of a Stack then you could use the following program since it is much more simple than your Stack version and hence less-error prone.
#include <iostream>
#include <string>
bool checkIfPalindroom(const std::string &str)
{
for(int i=0;i<(str.size()/2);i++)
{
if (str[i] != str[str.size() - i - 1])
{
return false;//if this if is satisfied even once, return false
}
}
return true;//if the control flow reaches here this will mean that no if was satisfied and hence return true
}
int main()
{
std::string myString = "Somearbitrarystring";
if(checkIfPalindroom(myString))//call the function
{
std::cout<<"The given string: "<<myString <<" is a palindrome"<<std::endl;
}
else
{
std::cout<<"The given string: "<<myString<<" is not a palindrome"<<std::endl;
}
return 0;
}

Getting Permutations with Repetitions in this special way

I have a list of {a,b} and i need all possible combinatations where say n=3.
so:
[a,b,a],
[b,a,b]
[a,a,a]
[b,b,b]
etc.
Is there a name of such a problem
My current solution just uses random sampling and is very inefficient:
void set_generator(const vector<int>& vec, int n){
map<string, vector<int>> imap;
int rcount = 0;
while(1){
string ms = "";
vector<int> mset;
for(int i=0; i<n; i++){
int sampled_int = vec[rand() % vec.size()];
ms += std::to_string(sampled_int);
mset.emplace_back(sampled_int);
}
if(rcount > 100)
break;
if(imap.count(ms)){
rcount += 1;
//cout << "*" << endl;
continue;
}
rcount = 0;
imap[ms] = mset;
cout << ms << endl;
}
}
set_generator({1,2},3);
Let us call b the size of the input vector.
The problem consists in generating all numbers from 0 to b^n - 1, in base b.
A simple solution increments the elements of an array one by one, each from 0 to b-1.
This is performed by the function increment in the code hereafter.
Output:
111
211
121
221
112
212
122
222
The code:
#include <iostream>
#include <vector>
#include <string>
#include <map>
void set_generator_op (const std::vector<int>& vec, int n){
std::map<std::string, std::vector<int>> imap;
int rcount = 0;
while(1){
std::string ms = "";
std::vector<int> mset;
for(int i=0; i<n; i++){
int sampled_int = vec[rand() % vec.size()];
ms += std::to_string(sampled_int);
mset.emplace_back(sampled_int);
}
if(rcount > 100)
break;
if(imap.count(ms)){
rcount += 1;
//cout << "*" << endl;
continue;
}
rcount = 0;
imap[ms] = mset;
std::cout << ms << "\n";
}
}
// incrementation of a array of int, in base "base"
// return false if max is already attained
bool increment (std::vector<int>& cpt, int base) {
int n = cpt.size();
for (int i = 0; i < n; ++i) {
cpt[i]++;
if (cpt[i] != base) {
return true;
}
cpt[i] = 0;
}
return false;
}
void set_generator_new (const std::vector<int>& vec, int n){
int base = vec.size();
std::vector<int> cpt (n, 0);
while (true) {
std::string permut = "";
for (auto &k: cpt) {
permut += std::to_string (vec[k]);
}
std::cout << permut << "\n";
if (!increment(cpt, base)) return;
}
}
int main() {
set_generator_op ({1,2},3);
std::cout << "\n";
set_generator_new ({1,2},3);
}
Following advices of Jarod42, I have
suppressed the useless conversion to a string
used a more elegant do ... while instead of the while true
inversed the iterators for printing the result
Moreover, I have created a templated version of the program.
New output:
111
112
121
122
211
212
221
222
aaa
aab
aba
abb
baa
bab
bba
bbb
And the new code:
#include <iostream>
#include <vector>
#include <string>
#include <map>
// incrementation of a array of int, in base "base"
// return false if max is already attained
bool increment (std::vector<int>& cpt, int base) {
int n = cpt.size();
for (int i = 0; i < n; ++i) {
cpt[i]++;
if (cpt[i] != base) {
return true;
}
cpt[i] = 0;
}
return false;
}
template <typename T>
void set_generator_new (const std::vector<T>& vec, int n){
int base = vec.size();
std::vector<int> cpt (n, 0);
do {
for (auto it = cpt.rbegin(); it != cpt.rend(); ++it) {
std::cout << vec[*it];
}
std::cout << "\n";
} while (increment(cpt, base));
}
int main() {
set_generator_new<int> ({1,2}, 3);
std::cout << "\n";
set_generator_new<char> ({'a','b'}, 3);
}
Besides the concrete answer for integer usage, I want to provide a generic way I needed during test case construction for scenarios with a wide spread of various parameter variations. Maybe it's helpful to you too, at least for similar scenarios.
#include <vector>
#include <memory>
class SingleParameterToVaryBase
{
public:
virtual bool varyNext() = 0;
virtual void reset() = 0;
};
template <typename _DataType, typename _ParamVariationContType>
class SingleParameterToVary : public SingleParameterToVaryBase
{
public:
SingleParameterToVary(
_DataType& param,
const _ParamVariationContType& valuesToVary) :
mParameter(param)
, mVariations(valuesToVary)
{
if (mVariations.empty())
throw std::logic_error("Empty variation container for parameter");
reset();
}
// Step to next parameter value, return false if end of value vector is reached
virtual bool varyNext() override
{
++mCurrentIt;
const bool finished = mCurrentIt == mVariations.cend();
if (finished)
{
return false;
}
else
{
mParameter = *mCurrentIt;
return true;
}
}
virtual void reset() override
{
mCurrentIt = mVariations.cbegin();
mParameter = *mCurrentIt;
}
private:
typedef typename _ParamVariationContType::const_iterator ConstIteratorType;
// Iterator to the actual values this parameter can yield
ConstIteratorType mCurrentIt;
_ParamVariationContType mVariations;
// Reference to the parameter itself
_DataType& mParameter;
};
class GenericParameterVariator
{
public:
GenericParameterVariator() : mFinished(false)
{
reset();
}
template <typename _ParameterType, typename _ParameterVariationsType>
void registerParameterToVary(
_ParameterType& param,
const _ParameterVariationsType& paramVariations)
{
mParametersToVary.push_back(
std::make_unique<SingleParameterToVary<_ParameterType, _ParameterVariationsType>>(
param, paramVariations));
}
const bool isFinished() const { return mFinished; }
void reset()
{
mFinished = false;
mNumTotalCombinationsVisited = 0;
for (const auto& upParameter : mParametersToVary)
upParameter->reset();
}
// Step into next state if possible
bool createNextParameterPermutation()
{
if (mFinished || mParametersToVary.empty())
return false;
auto itPToVary = mParametersToVary.begin();
while (itPToVary != mParametersToVary.end())
{
const auto& upParameter = *itPToVary;
// If we are the very first configuration at all, do not vary.
const bool variedSomething = mNumTotalCombinationsVisited == 0 ? true : upParameter->varyNext();
++mNumTotalCombinationsVisited;
if (!variedSomething)
{
// If we were not able to vary the last parameter in our list, we are finished.
if (std::next(itPToVary) == mParametersToVary.end())
{
mFinished = true;
return false;
}
++itPToVary;
continue;
}
else
{
if (itPToVary != mParametersToVary.begin())
{
// Reset all parameters before this one
auto itBackwd = itPToVary;
do
{
--itBackwd;
(*itBackwd)->reset();
} while (itBackwd != mParametersToVary.begin());
}
return true;
}
}
return true;
}
private:
// Linearized parameter set
std::vector<std::unique_ptr<SingleParameterToVaryBase>> mParametersToVary;
bool mFinished;
size_t mNumTotalCombinationsVisited;
};
Possible usage:
GenericParameterVariator paramVariator;
size_t param1;
int param2;
char param3;
paramVariator.registerParameterToVary(param1, std::vector<size_t>{ 1, 2 });
paramVariator.registerParameterToVary(param2, std::vector<int>{ -1, -2 });
paramVariator.registerParameterToVary(param3, std::vector<char>{ 'a', 'b' });
std::vector<std::tuple<size_t, int, char>> visitedCombinations;
while (paramVariator.createNextParameterPermutation())
visitedCombinations.push_back(std::make_tuple(param1, param2, param3));
Generates:
(1, -1, 'a')
(2, -1, 'a')
(1, -2, 'a')
(2, -2, 'a')
(1, -1, 'b')
(2, -1, 'b')
(1, -2, 'b')
(2, -2, 'b')
For sure, this can be further optimized/specialized. For instance you can simply add a hashing scheme and/or an avoid functor if you want to avoid effective repetitions. Also, since the parameters are held as references, one might consider to protect the generator from possible error-prone usage via deleting copy/assignement constructors and operators.
Time complexity is within the theoretical permutation complexity range.

How would I find a partial word match/find c++

I'm having trouble with a scrabble-like game I'm making. My goal was to have 5 random letters that possibly match at least one word in a dictionary I made so the game can start. I've done this but since the 5 letters are random there's probably a slim chance it will match one of the words in the dictionary. I've done test runs and got random letters but no match every time (it works hardcoded however). I figure if I can find a partial match, I can keep the letter(s) that do form part of a word and get different letters for the ones that don't. The thing is, I don't know how to go about doing this.
This is my code for the five random letters:
void fiveLetters()
{
srand(time(NULL));
for (int i =0; i<=4; i++) // display 5 random letters
{
int n = rand()%26;
char letter = (char)(n+97);
letters[i] = letter;
cout << letters[i]<< " ";
}
letters[5] = '\0'; // last value in char array null value so I can convert to string
attempt = letters; // the 4 letters
checkWords();
}
For checking if it matches a word I use:
void checkWords()
{
if (find(words.begin(),words.end(), attempt) != words.end()) // if matches word in set
{
cout << " Words found" << endl;
}
else // if it doesn't match
{
cout << "cannot find word " << endl;
attempt.clear();
fiveLetters();
}
}
The dictionary is a text file with a lot of words however since I'm just trying to get things working before I implement it, I used 5-10 words and put them in a set<string>. Sorry for the long read, any help is appreciated!
This example demonstrates using a Trie to recursively search for words loaded into it, using search criteria like counts of available letters, minimum word length, and a maximum number of "missing" letters -- letters which are used without being included as an "available" letter.
This Trie is a 26-ary tree, so each node has 26 child nodes, one for each letter in the alphabet. The root node's children are selected using the first letter in a word, the second letter chooses one of this child's children, and so on. A node contains a boolean value indicating that a word ends as that node. Such a node is not a "leaf", however, because the terminated word might be a prefix of a longer word (node terminates "ball", but still has a child branch for "balloon").
The Trie, along with a recursive search is amazingly rapid for your particular task. (By the way, the recursive search doesn't use a recursive function, it stores each level's context on a vector-based stack).
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <random>
#include <algorithm>
class Trie {
// branch_count defines the number of characters which are combined to make words
// 26 is the number of letters, interpreted case-insensitively
static const int branch_count = 26;
// index_map takes a character and returns a number between 0 and branch_count-1
static int index_map(char c) {
if((c >= 'a') & (c <= 'z')) return c - 'a';
if((c >= 'A') & (c <= 'Z')) return c - 'A';
return -1;
}
// index_unmap takes an index, between 0 and branch_count-1, and returns
// the canonical character representation for that index
static char index_unmap(int index) {
return char('a' + index);
}
// verify_word returns true if all characters in the string map to an index
// returns false if at least one character is not recognized
static bool verify_word(const std::string& word) {
for(auto&& c : word) {
if(index_map(c) == -1) return false;
}
return true;
}
// Node is the Trie's branch_count-ary tree node class
struct Node {
Node* child_nodes[branch_count];
bool terminates_word;
Node() : terminates_word(false) {
for(auto& p : child_nodes) { p = nullptr; }
}
};
// make_lower(str) changes upper-case letters in str to lower-case (in-place)
static void make_lower(std::string& str) {
for(auto& c : str) {
if((c >= 'A') & (c <= 'Z')) {
c += 'a' - 'A';
} } }
// is_space_char(x) returns true when c is some kind of
// unprintable or blank, but nonzero, character
static bool is_space_char(char c) { return (c > 0) & (c <= ' '); }
// trim(str) removes whitespace from the left and right sides
// of str (str is modified in-place)
static void trim(std::string& str) {
const auto len = str.length();
if(!len) return;
auto i = len-1;
if(is_space_char(str[i])) {
for(--i; i+1; --i) {
if(!is_space_char(str[i])) {
str.resize(i+1);
break;
} } }
if(!(i+1)) {
str.clear();
return;
}
i=0;
if(is_space_char(str[i])) {
for(++i;; ++i) {
if(!is_space_char(str[i])) {
str = str.substr(i);
return;
} } } }
Node *root;
int node_count;
int word_count;
public:
// Trie::AddWord(word) stores a string in the Trie
void AddWord(std::string word) {
if(word.empty()) return;
make_lower(word);
if(!verify_word(word)) return;
Node *p = root;
for(const auto c : word) {
const int child_index = index_map(c);
if(child_index == -1) {
// verify_word(word) should have caught this.
// Well-behaved, but might use excess memory.
return;
}
Node *pchild = p->child_nodes[child_index];
if(!pchild) {
p->child_nodes[child_index] = pchild = new Node;
++node_count;
}
p = pchild;
}
if(!p->terminates_word) {
p->terminates_word = true;
++word_count;
} }
// LoadWords(input_stream) loads all line-delimited words from
// the stream into the Trie
int LoadWords(std::istream& stream_in) {
const int start_count = word_count;
std::string line;
while(std::getline(stream_in, line)) {
trim(line);
AddWord(line);
}
return word_count - start_count;
}
// LoadWords(filename) loads all line-delimited words from
// the file at the given path
int LoadWords(const std::string& file_path) {
std::ifstream stream_in(file_path.c_str());
return LoadWords(stream_in);
}
// WordCount() returns the number of words loaded so far
int WordCount() const { return word_count; }
// select_type is a helper for specifying iterator behavior
template <bool select_A, typename A, typename B>
struct select_type { typedef A type; };
template <typename A, typename B>
struct select_type<false, A, B> { typedef B type; };
template <bool select_A, typename A, typename B>
using select_type_t = typename select_type<select_A, A, B>::type;
// The iterator class is used for begin() and end(), as a minimal
// implementation compatible with range-based for,
// as well as by the destructor when destroying the
// tree's Node objects.
template <bool is_const=true, bool delete_iter=false>
class iterator {
friend class Trie;
typedef select_type_t<is_const, const Node*, Node*> pnode_t;
struct context {
pnode_t node;
int child_index;
};
std::vector<context> stack;
pnode_t advance() {
for(;;) {
if(stack.empty()) return nullptr;
pnode_t p = stack.back().node;
int &child_index = stack.back().child_index;
while(++child_index < branch_count) {
pnode_t pchild = p->child_nodes[child_index];
if(pchild) {
stack.push_back({pchild, -1});
if(!delete_iter && pchild->terminates_word) return nullptr;
break;
} }
if(stack.back().child_index == branch_count) {
stack.pop_back();
if(delete_iter) return p;
} } }
public:
iterator(pnode_t root) {
stack.push_back({root, -1});
if(!delete_iter) advance();
}
iterator() {}
std::string operator * () const {
if(stack.empty()) return std::string();
std::string word;
for(int i=0; stack[i].child_index != -1; ++i) {
word += index_unmap(stack[i].child_index);
}
return word;
}
iterator& operator ++ () {
advance();
return *this;
}
bool operator != (const iterator& iter) const {
if(stack.size() != iter.stack.size()) return true;
const int size = static_cast<int>(stack.size());
for(int i=0; i<size; ++i) {
if(stack[i].node != iter.stack[i].node) return true;
}
return false;
}
};
// ctor
Trie() : root(new Node), node_count(1), word_count(0) {}
// dtor
~Trie() {
iterator<false, true> iter(root);
int count = 0;
while(auto pn = iter.advance()) {
delete pn;
++count;
}
//std::cout << "Final word count: " << word_count << '\n';
//std::cout << count << " of " << node_count << " Node objects deleted\n";
}
// const_iterator defined from iterator with template parameter
// for selecting const Node pointers
typedef iterator<true> const_iterator;
const_iterator begin() const { return const_iterator(root); }
const_iterator end() const { return const_iterator(); }
// FindWords:
// * takes an unordered map with char keys and int values
// (counts[ch] = <how many ch may be used>)
// * takes a "max_missing" count (number of substituted characters which
// may be used when none remain in "counts")
// * takes a "min_length", the minimum length a word
// must have to be added to the results
std::vector<std::string> FindWords(const std::unordered_map<char, int>& counts, int max_missing=0, int min_length=0) {
struct context {
const Node* node;
int child_index;
std::unordered_map<char, int> counts;
int missing_count;
bool missing_letter;
context(const Node* node, const std::unordered_map<char, int>& counts, int missing_count) :
node(node),
child_index(-1),
counts(counts),
missing_count(missing_count),
missing_letter(false)
{}
};
std::vector<context> stack;
stack.push_back(context(root, counts, 0));
std::vector<std::string> match_list; // results are added to this
// This walks the tree just like the iterator's advance() function
// however, this function's context includes more info, like
// each level's available letter counts and whether a letter
// was used by taking one of the available "missing" letters.
while(!stack.empty()) {
context& ctx = stack.back();
while(++ctx.child_index < branch_count) {
const Node* pchild = ctx.node->child_nodes[ctx.child_index];
if(!pchild) continue;
const char c = index_unmap(ctx.child_index);
if(ctx.counts[c] > 0) {
ctx.missing_letter = false;
context child_ctx(pchild, ctx.counts, ctx.missing_count);
--child_ctx.counts[c];
stack.push_back(child_ctx); // ctx made invalid here
break;
}
else if(ctx.missing_count < max_missing) {
ctx.missing_letter = true;
context child_ctx(pchild, ctx.counts, ctx.missing_count + 1);
stack.push_back(child_ctx); // ctx made invalid here
break;
} }
context& fresh_ctx = stack.back();
if(fresh_ctx.child_index == branch_count) {
stack.pop_back();
continue;
}
// After a new level is pushed on the stack, check if the last node
// completes a word from the tree, then check various conditions
// required for adding it to the results.
if(static_cast<int>(stack.size()) > min_length && fresh_ctx.node->terminates_word) {
std::string word;
for(const auto& entry : stack) {
if(entry.child_index != -1) {
char c = index_unmap(entry.child_index);
if(entry.missing_letter) {
// modify the character to show it was substituted
if(c >= 'a' && c <= 'z') {
// capitalize missing lower-case letters
word += c + 'A' - 'a';
} else {
// put funky square brackets around other types of missing characters
word += '[';
word += c;
word += ']';
}
} else {
word += c;
} } }
match_list.push_back(word);
} }
return match_list;
}
// FindWords(letters, max_missing, min_length) creates a "counts" map
// from the "letters" string and uses it to call FindWords(counts...)
std::vector<std::string> FindWords(std::string letters, int max_missing=0, int min_length=0) {
std::unordered_map<char, int> counts;
for(auto c : letters) {
switch(c) {
case '?': ++max_missing; break; // '?' is a wildcard (blank tile)
default: ++counts[c]; break;
} }
return FindWords(counts, max_missing, min_length);
}
// DumpAllWords dumps all words contained in the Trie to cout (in alphabetical order)
void DumpAllWords() {
for(auto&& s : *this) {
std::cout << s << '\n';
} }
};
class DrawPool {
std::mt19937 rng;
std::string letters;
int last_count = 1;
struct arg_is_int { char i[4]; };
static arg_is_int argtype(int);
static char argtype(char);
void Add() {}
template <typename T, typename ...Args>
void Add(T arg, Args ...args) {
if(sizeof(argtype(arg)) == sizeof(arg_is_int)) {
last_count = arg;
} else {
letters += std::string(last_count, arg);
}
Add(args...);
}
public:
void Shuffle() {
letters.clear();
Add(2, '?',
12,'e', 9, 'a', 'i', 8, 'o', 6, 'n', 'r', 't',
4, 'l', 's', 'u', 'd', 3, 'g',
2, 'b', 'c', 'm', 'p', 'f', 'h', 'v', 'w', 'y',
1, 'k', 'j', 'x', 'q', 'z');
std::shuffle(letters.begin(), letters.end(), rng);
}
int Count() const { return static_cast<int>(letters.length()); }
std::string Get(int count) {
if(count > Count()) count = Count();
const std::string draw = letters.substr(0, count);
letters.erase(0, count);
return draw;
}
DrawPool() {
std::random_device rd;
std::seed_seq seed = {rd(), rd(), rd(), rd(), rd()};
rng.seed(seed);
Shuffle();
}
};
int main() {
Trie trie;
// Call trie.LoadWords(filename) with each filename in the list
// The names here are files from the SCOWL word lists.
// These may be replaced with your own file name(s).
for(auto s : {
"english-words.10",
"english-words.20",
"english-words.35",
"english-words.40",
"english-words.50",
"english-words.55",
"english-words.60",
"english-words.70",
"english-words.80",
"english-words.95"
}) {
int count = trie.LoadWords(s);
std::cout << "Loaded " << count << " new words from " << s << '\n';
}
std::cout << "\nLoaded a total of " << trie.WordCount() << " words\n";
//trie.DumpAllWords(); // send all words to cout
// match a set of 7 randomly-drawn letters
// draw one more letter each time no matches found
DrawPool draw_pool;
std::string rack;
std::vector<std::string> word_list;
do {
rack += draw_pool.Get(rack.empty() ? 7 : 1);
std::cout << "\nRack: " << rack << '\n';
// find words at least 3 letters long, using the letters
// from "rack". The only "missing" matches allowed are
// 1 for each wildcard ('?') in "rack".
word_list = trie.FindWords(rack, 0, 3);
} while(word_list.empty() && draw_pool.Count());
// Dump the results to cout
std::cout << "\nFound " << word_list.size() << " matches\n";
for(auto&& word : word_list) {
std::cout << " " << word << '\n';
}
}
This is something from my class
if (Variable_name.find(thing to check for) != string::npos)
example
if (myname.find(james) != string::npos)
{
found=true;
//do something
}

C++ program runs in linux but not windows

I am writing this program for college and keep having problems with it. I wrote in using codeblocks in ubuntu and it runs fine no errors or anything. But when I run it in windows on codeblocks it crashes and I keep getting the same error "terminate called after throwing an instance of 'std::bad_alloc' what<>: std::badalloc' then it stops working.
Any help would be appreciated!
Thankyou
Ron
main.cpp
#include <iostream>
#include "set.h"
using namespace std;
int main()
{
Set Set1;
List List1;
List1.header();
int choice = 0;
int value = 0;
cout<<"Press 1 to use a list or press 2 for a set"<<endl;
cin>>choice;
if(choice == 1) //List
{
while(choice != 4)
{
value = 0;
List1.menu();
cin>>choice;
switch(choice)
{
case 1:cout<<"Please enter value"<<endl;
cin>>value;
List1.set_value(value);
break;
case 2:List1.print_list();
break;
case 3:List1.test_copy_constructor();
break;
}
}
}
else if(choice == 2) //Set
{
while(choice != 4)
{
value = 0;
List1.menu();
cin>>choice;
switch(choice)
{
case 1:cout<<"Please enter value"<<endl;
cin>>value;
Set1.set_value(value);
break;
case 2:Set1.print_list();
break;
case 3:Set1.test_copy_constructor();
break;
}
}
}
else
{
cout<<"Please Enter a valid option"<<endl;
}
return 0;
}
set.cpp
#include "set.h"
#include <iostream>
#include <string>
using namespace std;
//Constructor
List::List()
{
int array_size;
int *array = new int[array_size];
// delete [] array;
}
List List1;
//Print functions
void List::header(void) const
{
cout<<"Program Name: Program 2"<<endl;
cout<<"Program Created: March 20,2014"<<endl;
cout<<"Created by: Ron Miller"<<endl;
cout<<"--------------------------------"<<endl;
cout<<" "<<endl;
}
void List::menu(void) const
{
cout<<" Menu"<<endl;
cout<<"---------------------------------------------------------"<<endl;
cout<<"1. Insert (value to be inserted is entered from keyboard)"<<endl;
cout<<"2. Print List (all values, one per line)"<<endl;
cout<<"3. Test Copy Constructor (pass list by value to a function"<<endl;
cout<<" and from within the function change all values in list"<<endl;
cout<<" to 0, then call Print List before function ends)"<<endl;
cout<<"4. Quit"<<endl;
cout<<"---------------------------------------------------------"<<endl;
}
//Modification Functions
void List::set_value(const int value)
{
if (slot == 0) //If first run set array size
{
array = new int[array_size];
}
if (slot == array_size) //If array needs extended save data in temp array expand original array then copy back to original
{
cout<<"EXPAND ARRAY"<<endl;
temp_array = array;
array_size = array_size + 2;
array = new int[array_size];
array = temp_array;
}
array[slot] = value; //Set current array slot to value
slot = slot+1;
}
void List::print_list(void) const
{
int i = 0;
cout<<"---------------"<<endl;
while(i < slot)
{
cout<<array[i]<<endl;
i = i+1;
}
cout<<"---------------"<<endl;
}
void List::test_copy_constructor(void) const
{
int* test_array;
test_array = array;
int i = 0;
test_array = new int[array_size]; //Copy original array to test_Array
while(i < slot) //Set array to 0
{
test_array[i] = 0;
i = i+1;
}
i = 0;
cout<<"---------------"<<endl;
while(i < slot) //REMOVE THIS ONLY FOR TESTING PURPOSES
{
cout<<test_array[i]<<endl;
i = i+1;
}
i = 0;
cout<<"---------------"<<endl;
List::print_list(); //Print original array
}
void Set::set_value(const int value)
{
array = get_array(); //Use get functions to obtain copies of private data
temp_array = get_temp_array();
array_size = get_array_size();
temp_array_size = get_temp_array_size();
slot = get_slot();
char match;
match = Set::search_array(value);
if(match == 'y')
{
cout<<"Match"<<endl;
}
if(match == 'n')
{
if (slot == 0) //If first run set array size
{
array = new int[array_size];
}
if (slot == array_size) //If array needs extended save data in temp array expand original array then copy back to original
{
cout<<"EXPAND ARRAY"<<endl;
temp_array = array;
array_size = array_size + 2;
array = new int[array_size];
array = temp_array;
}
array[slot] = value; //Set current array slot to value
slot = slot+1;
set_array(array); //Use set values to update private data
set_temp_array(temp_array);
set_array_size(array_size);
set_temp_array_size(temp_array_size);
set_slot(slot);
}
}
char Set::search_array(int value)
{
array = get_array();
array_size = get_array_size();
slot = get_slot();
int array_value;
char match = 'n';
int i =0;
while(i < slot) //Searches array for a match if there is return y otherwise return n
{
if( array[i] == value)
{
match = 'y';
}
else
{
match = 'n';
}
i = i+1;
}
return match;
}
//Set Functions
void List::set_array(int* value)
{
array = value;
}
void List::set_array_size(int value)
{
array_size = value;
}
void List::set_temp_array(int* value)
{
temp_array = value;
}
void List::set_temp_array_size(int value)
{
temp_array_size = value;
}
void List::set_slot(int value)
{
slot = value;
}
//Get Functions
int* List::get_array(void) const
{
return array;
}
int* List::get_temp_array(void) const
{
return temp_array;
}
int List::get_array_size(void) const
{
return array_size;
}
int List::get_temp_array_size(void) const
{
return temp_array_size;
}
int List::get_slot(void) const
{
return slot;
}
set.h
#ifndef set_H_INCLUDED
#define set_H_INCLUDED
class List
{
public:
//Constructor
List();
//Print Functions
void header (void) const;
void menu (void) const;
//Modification Functions
void set_value (const int);
void print_list(void) const;
void test_copy_constructor(void) const;
//Set functions
void set_array( int*);
void set_temp_array(int*);
void set_array_size( int);
void set_temp_array_size(int);
void set_slot(const int);
//Get functions
int* get_array (void) const;
int* get_temp_array (void) const;
int get_array_size (void) const;
int get_temp_array_size (void) const;
int get_slot(void) const;
private:
int array_size;
int *array;
int *temp_array;
int temp_array_size;
int slot = 0;
};
class Set : public List
{
public:
//Modification Functions
void set_value (const int);
char search_array(const int);
private:
int array_size = 2;
int *array;
int *temp_array;
int temp_array_size = 2;
int slot = 0;
};
#endif
List::List()
{
int array_size;
int *array = new int[array_size];
// ...
}
What value is array_size supposed to have? How large an int array is supposed to be allocated?
It seems to me that this local variable declaration is superfluous; remove it, and use the member variable, instead. (You've initialised the member variable to 2 at its point of declaration, using a new C++11 feature which allows you to do so with a variable that is not static const.)
Don't forget to hand back that allocated memory when you're done with it. In general I would propose that you use std::vector for this.

I am not sure what I am doing wrong but I keep getting an error c++

for (int i = peekIndex; i < pdp->size(); i++)
{
string x = pdp->peek();
if (x.at(0) == 's')
{
out << pdp->peek() << endl;
pdp->moveForward();
}
else
{
pdp->moveForward();
}
}
The error I get is
terminate called after throwing and instance of std::out_of_range
what(): basic_string::at()
Abort
The peek method returns a string in the position of the peekIndex.
The moveFowrard method increments the peekIndex.
pdp is a vector of size 100. I am supposed to peek and print only words that start with 's' that have been pushed to the <vector>. I am basically done but this part is proving somewhat difficult.
Thanks
#include<iostream>
#include<vector>
#include<string>
using namespace std;
class StringDeque {
protected:
vector<string>* elements;
int frontItem; //CLASS INV: indexes item with least index
int rearSpace; //CLASS INV: indexes space after item with greatest index
int upperBound; //For array[0..n-1] this is "n" not "n-1".
public:
StringDeque(int guaranteedCapacity):
elements (new vector<string>( 2*guaranteedCapacity))
frontItem (guaranteedCapacity),
rearSpace ( guaranteedCapacity),
upperBound ( 2*guaranteedCapacity)
{}
proteted:
virtual bool isEmpty() const { return frontItem == rearSpace; }
virtual bool isFull() const { return rearSpace == upperBound || frontItem == 0; }
virtual int size() const { return rearSpace - frontItem; }
virtual string popRear() {
if (isEmpty()) {
cerr<< "Later we'll define and throw an EmptyQException"<< endl;
return "";
} else {
return elements->at(--rearSpace);
}
}
virtual string popFront() {
if (isEmpty()) {
cerr<<"Later we'll define and throw an EmptyQException"<<endl;
return "";
} else {
return elements->at(frontItem++);
}
}
/** Directions include similarly testing for "full" in the C++ code.
*/
virtual void pushFront(string newItem) {
elements->at(--frontItem)= newItem;
}
virtual void pushRear(string newItem) {
elements->at(rearSpace++) = newItem;
}
virtual string toString() {
string out = "";
for (int i = frontItem; i < rearSpace; i++) {
out += elements->at(i) + " ";
}
return out;
}
};
class PeekDeque : public StringDeque {
private:
int peekIndex;
public:
PeekDeque(int guaranteedCapacity):
StringDeque(guaranteedCapacity),
peekIndex(guaranteedCapacity/2)
{}
virtual void moveFrontward() {
if (peekIndex == upperBound) {
cerr<<"Cannot move past total capacity"<<endl;
} else{
elements->at(peekIndex ++);
}
}
virtual void moveRearward () {
if (peekIndex == -1) {
cerr<<"Cannot move below total capacity"<<endl;
} else{
elements ->at( peekIndex--);
}
}
virtual string popFront() {
cerr<<"Attempt to pop from empty PeekDeque"<<endl;
}
virtual string popRear() {
cerr<<"Attempt to pop from empty PeekDeque"<<endl;
}
virtual string peek() {
if (isEmpty()) {
cerr<<"Cannot peek an Empty index"<<endl;
return "";
} else {
return elements->at(peekIndex + 1);
}
}
virtual string toString() {
string out = "";
for (int i = frontItem; i < rearSpace; i++) {
out += elements->at(i) + " ";
}
return out;
}
};
int main(){
PeekDeque* pdp = new PeekDeque(101);
pdp->pushFront("oh");
pdp->pushFront("say");
pdp->pushFront("can");
pdp->pushFront("you");
pdp->pushFront("see");
pdp->pushRear("any");
pdp->pushRear("bad bugs");
pdp->pushRear("on");
pdp->pushRear("me?");
for(int i = peekIndex; i<pdp->size(); i++){
string x =
if(x.at(0)=='s'){
cout<<pdp->peek()<<endl;
pdp->moveForward(); }
else{
pdp->moveForward();
}
}
}
May be your test should be:
if(!x.empty() && x.at(0)=='s')
I can't tell exactly, without seeing more context, but I'm pretty sure x.empty() is a probable case.
UPDATE:
pdp is a vector of size 100
Are you sure to have used the pdp.resize(100,std::string()); method to ensure all positions are initialized correctly?
it is not empty i have pushed 8 things to pdp
Also std::vector<>::resize() and std::vector<>::push_back() might not work together as you expect. Use either std::vector<>::push_back() or std::vector<>::resize() to give it a pre-allocated size and manipulate entries by index. Always check for std::vector<>::size() for indexed access.
UPDATE 2:
But the real answer is apparently simpler. You have:
virtual string peek() {
if (isEmpty()) {
cerr<<"Cannot peek an Empty index"<<endl;
return ""; // This will certainly result in a string that is empty!
Here's how your container looks like after initial pushes:
0 202
| ... | ... | ... | ... |
^ ^ ^
| | rearSpace
| peekIndex
frontItem
Now, size() returns rearSpace - frontItem, but iteration starts from peekIndex and thus goes beyond rearSpace index, peeking uninitialized (empty) strings.
That's certainly an approximate answer, since your work with indices is a mess. Please be really careful and think it through.