for the program I'm writing I need to find the location of a specific word inside a string array, but I don't know how. This is the code I made but it doesn't work:
int location;
string input;
cout << "Type your name" << endl;
cin >> input;
for (int i = 0; i <= count; i++)
{
call_DB[i].name;
if (call_DB[i].name == input)
{
location = i;
}
}
What is wrong with that code and what can I do to fix it? Thank you.
Try std::find_if, which searches the array for item satisfying provided predict function.
auto iter = std::find_if(call_DB, call_DB + count, [&input](const YOUR_CALL_DB_TYPE& item ){ return item.name == input; });
if(iter == call_DB + count)
printf("Not found\n");
else
printf("Found: %s\n", iter->name.c_str());
If such item is found, the index is the distance from array base, size_t index = iter - call_DB;
You can get an iterator to the array element using std::find_if:
auto it = std::find_if(std::begin(db), std::end(db), [&name](auto const& x) {
return x.name == name;
});
And if you want the index into the array:
auto index = it - std::begin(db);
Related
sorry for such a stupid question but I couldn't find any obvious answer.
I need to read from stdin first an int n with the size of an array, and then integer values from a string in the format "1 2 3 4 5 6" with n elements.
If I knew the number of parameters at compile time I could use something like a scanf (or the safe alternatives) with a format string like "%d %d %d %d %d %d", but here I will only know that value at run time.
What would be the best way to do this in C++? Performance is important but more than that safety.
How should I read a format string of variable length in C++ from stdin?
You should not attempt to do such thing. Only ever use constant format strings.
I need to read from stdin first an int n with the size of an array, and then integer values
What would be the best way to do this in C++?
Read one value at a time. Repeat using a loop.
Here's a function that does what errorika describes:
const int SIZE = //as much of your memory as you'd like the user to have access to
***caller function must include this:
//allocate a string to hold some data;
char* buffer = NULL;
buffer = malloc (SIZE * sizeof(char));
if (buffer == NULL) {
printf("malloc error terminating\n");
return;
}
***
void getEntry(char* buffer) {
int count = 0;
int maxlen = SIZE - 1;
char a = '0';
for (int i = 0; i < SIZE; i++) {
buffer[i] = '0';
}
while (a != '\n' && count < maxlen) {
a = fgetc(stdin);
buffer[count] = a;
count++;
}
if (a == '\n') {
buffer[count - 1] = '\0';
}
else {
buffer[count] = '\0';
do {
a = fgetc(stdin);
} while (a != '\n');
}
}
This is all basic C code but user entry is evil. Here is what I've come up with for more C++ idiomatic user input functions (query is just the message string you pass in):
template<typename T>
void getInput(const std::string query, T& entry) {
std::string input;
std::cout << query << std::endl;
getline(std::cin, input);
std::stringstream buffer{input};
buffer >> entry;
}
OR
template<typename T>
void getInput2(std::string query, T& entry) {
bool validInput = false;
while (validInput == false)
{
validInput = true;
std::cout << query << std::endl;
std::cin >> entry;
if (std::cin.fail()) {
validInput = false;
std::cout << "Unacceptable entry\n" << std::endl;
}
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
I am attempting to use recursion and keep getting overflow errors. I am not sure what to do.
I want to feed one of my functions with all the anagrams but I am not sure how. I can't fit everything into one function, so I made two: one that makes the anagrams and one that searches through the dictionary to find all the matches. But it's not working, and I have no idea what else to do. And in my anagram function, I want to return back to my permutation function, but I can't without returning a string. I need it to return nothing and go back to the function.
#include <iostream>
#include <fstream>
#include <istream>
#include <string>
using namespace std;
const int MAXRESULTS = 20; // Max matches that can be found
const int MAXDICTWORDS = 30000; // Max words that can be read in
const int MAXPERMUTATIONS = 720; //enough permutations for a 6 letter word
//Beginning of assignment functions
//Read Dictionary function that uses recursion
int readDictionary(istream &, string[]);
//Permuation function
int recursivePermute(string, const string[], int, string[]);
//Print function
void recurPrint(const string[], int);
//swap characters in a string
void swap(string*, string*);
//permutation function
string Permutator(string, int, int, int);
//
//End of Assignment functions
int main()
{
string Permutations[MAXPERMUTATIONS];
string results[MAXRESULTS];
string dict[MAXDICTWORDS];
ifstream dictfile; // file containing the list of words
int nwords; // number of words read from dictionary
string word;
dictfile.open("words.txt");
if (!dictfile) {
cout << "File not found!" << endl;
return (1);
}
nwords = readDictionary(dictfile, dict);
cout << "Please enter a string for an anagram: ";
cin >> word;
//Make all the permutations and store them in an array
int numMatches = recursivePermute(word, dict, nwords, results);
if (numMatches == 0)
cout << "No matches found" << endl;
else
recurPrint(results, numMatches);
}
/***************************************************************************************************
Name: readDictionary
input: ifstream reference, string array
Description: This function returns the number of words added into the array from the dictionary.
****************************************************************************************************/
int readDictionary(istream &file, string DicArr[])
{
int counter = 0;
if (counter > MAXDICTWORDS)
return counter;
if (getline(file, DicArr[0]))
{
counter++;
return counter += readDictionary(file, DicArr + 1);
}
else
return counter;
}
/*****************************************************************************************************
Name: recursivePermute
Input: string, const string array, int, string array
Description: Places all the permutations of word, which are found in dict into results.
Returns the number of matched words found. This number should not be larger than
MAXRESULTS since that is the size of the array. The size is the number of words
inside the dict array.
*******************************************************************************************************/
int recursivePermute(string word, const string dict[], int size, string results[])
{
//count to iterate through the dictionary array and keep in bounds
//numresults to keep track of the number of results
int numResults = 0;
//if statement to if the number of results goes over the limit
if (numResults > MAXRESULTS)
return numResults;
if (size == 0)
return numResults;
//if there is a match check the dictionary
if (word == dict[0])
{
results[0] = word;
numResults++;
}
numResults += recursivePermute(Permutator(word, 0, word.length() - 1, 0), dict + 1, size - 1, results);
return numResults;
}
/*******************************************************************************************************
Name: recurPrint
Input:const string array, int
Description: Prints out the results
*********************************************************************************************************/
void recurPrint(const string results[], int size)
{
if (size == 1)
{
cout << "matching word \"" << results[0] << "\" found!\n" << endl;
return;
}
if (size == 0)
return;
cout << results[size - 1];
recurPrint(results, size - 1);
}
/****************************************************************************************************
name: swap
input: string pointer
description: This functions swaps two characters in a string
*****************************************************************************************************/
void swap(string* a, string* b)
{
string temp;
temp = *a;
*a = *b;
*b = temp;
}
/******************************************************************************************************
********************************************************************************************************/
string Permutator(string word, int beg, int end, int count)
{
string a;
if (count == end)
return word;
if (beg == end)
return;
if(count <= end)
{
swap(word[beg], word[count]);
Permutator(word, beg + 1, end, count);
swap(word[beg], word[count]);
Permutator(word, beg, end, count + 1);
}
}
/******************************************************************************************************
*******************************************************************************************************/
ok, so I've narrowed down my problem. I am having issues with this function, which I am using to feed each permutation into my other function that will check each permutation against the dictionary which is an array of strings.
string Permutator(string word, int beg, int end, int count)
{
if (count == end)
return word;
if (beg == end)
if (count <= end)
{
swap(word[beg], word[count]);
Permutator(word, beg + 1, end, count);
swap(word[beg], word[count]);
}
}
This would work if it was void, but I need it to return a string, but when I change the return type my entire algorithm goes out of whack. The loops, which in this assignment can only be recursions, do not work as they are supposed to. I am out of ideas not sure what else I can do.
std::map<std::string, std::vector<std::string>> seems appropriate:
std::vector<std::string> allWords /*= */;
std::map<std::string, std::vector<std::string>> dictionary;
for (const std::string& word : allWords) {
auto w = word;
std::sort(w.begin(), w.end());
dictionary[w].push_back(word);
}
And then
std::vector<std::string>
find_words_from_anagram(const std::map<std::string, std::vector<std::string>>& dictionary,
const std::string& word)
{
auto w = word;
std::sort(w.begin(), w.end());
auto it = dictionary.find(w);
if (it == dictionary.end()) {
return {}; // No match.
}
return it->second;
}
Trick is to normalize entry instead of checking for all permutations.
I'm working on a project in my data stucts book and for some reason even though it's nearly verbatim from what's written I'm still getting a runtime error that I can't identify.
Here is my code:
int main()
{
cout << "Enter an expression, to check if its balanced.\n";
string exp;
while (getline(cin, exp) && (exp != ""))
{
cout << exp;
if(is_balanced(exp))
{
cout << " is balanced.";
}
else
{
cout << " is not balanced.";
}
cout << "Enter another expression: \n";
}
return 0;
}
bool is_balanced(const string& expression) // pass reference to the input expression
{
//create stack to hold parantheses
stack<char> s;
bool balanced = true; //to hold return value
string::const_iterator iter;
expression.begin(); // sets a read-only iterator at the beginning of the expression
while (balanced && (iter != expression.end())) //while 'balanced' and not at end of expression cont. looping
{
char nx_ch = *iter;
if (is_open(nx_ch))
{
s.push(nx_ch);
}
else if (is_closed(nx_ch))
{
if (s.empty())
{
balanced = false;
}
else
{
char tp_ch = s.top(); // if the stack isn't closed set the char as tp for comparisson
s.pop(); // remove top char
balanced = OPEN.find(tp_ch) == CLOSE.find(nx_ch);
}
}
++iter;
}
if(!s.empty())
{
balanced = false;
return balanced && s.empty();
}
else
{
return balanced && s.empty();
}
}
The error occurs at this line: if(is_balanced(exp))
In the main and reads:
Debug Assertion Failed! ... Expression: string iterators incompatible
Everything I've read about the error says it happens when you compare to iterators, but that doesn't make sense if I can't even get it through the constructor. Any help to better understand this would be wonderful. Thanks in advance.
string::const_iterator iter; does not initialise the iterator.
Then you are reading its value in iter != expression.end().
The behaviour on doing that is undefined.
Did you mean string::const_iterator iter = expression.begin();?
This isn't how you set a variable:
string::const_iterator iter;
expression.begin(); // sets a read-only iterator at the beginning of the expression
This is how you set a variable:
string::const_iterator iter = expression.begin(); // sets a read-only iterator at the beginning of the expression
I have a delete function that is supposed to delete a string in an array by writing over it with the previous strings.
The look function see's that Overide matches and should be deleted. But the code i wrote for the loop in Delete is not removing that first spot in the array that Overide has taken up, and the output remains unchanged.
Also each phrase after + is being added into the array so four spots are taken in the array, and sorry i could not make that part look better the formatting screwed it up.
int AR::Look(const std::string & word)
{
int result = -1;
for(int i=0; i<counter; ++i)
{
if( con[i].find(word) != std::string::npos)
result = i;
}
return result;
}
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout<<"word not found\n";
}
else
{
for(int i=0; i<counter-1,i++;)
{
con[i]= con[i+1];
}
}
}
AR their
Ar(1);
theirAr + "Overload the +" + " operator as a member function " + "with chaining to add a string " + "to an Arrary object.";
cout<<theirAr<<endl<<endl;
cout<<"testing Delete and Look. <<endl;
theirAr.Delete("XXXXXX");
theirAr.Delete("Overload");
cout<<"Output after Delete and Look called\n";
cout<<theirArray<<endl<<endl;
You are locating the String but only use the value to write an error if it does not appear; if you find the string at pos N you will delete the first string anyway:
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout<<"word not found\n";
}
else
{
for(int i=0;i<counter-1,i++;) <--- Why don't you use loc here???
{
con[i]= con[i+1];
}
}
}
Also, your Look method would be better returning after the first match:
for ... {
if( con[i].find(word) != std::string::npos)
return i;
}
return -1;
Not sure if this is your problem, but shouldn't this be like so?
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout<<"word not found\n";
}
else
{
for(int i=loc;i<counter-1,i++;) // changes in this line
{
con[i]= con[i+1];
}
}
}
Start at where you found the string and start shuffling them backwards. Also, what shortens the array? i.e. drops the last element off. Looks like that is missing too.
Try this instead:
int AR::Look(const std::string & word)
{
for (int i = 0; i < counter; ++i)
{
if (con[i].find(word) != std::string::npos)
return i;
}
return -1;
}
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout << "word not found" << endl;
}
else
{
for (int i = loc+1; i < counter; ++i)
{
con[i-1] = con[i];
}
--counter;
}
}
I am currently trying to count the number of words in a file. After this, I plan to make it count the words between two words in the file. For example. My file may contain. "Hello my name is James". I want to count the words, so 5. And then I would like to count the number of words between "Hello" and "James", so the answer would be 3. I am having trouble with accomplishing both tasks.
Mainly due to not being exactly sure how to structure my code.
Any help on here would be greatly appreciated. The code I am currently using is using spaces to count the words.
Here is my code:
readwords.cpp
string ReadWords::getNextWord()
{
bool pWord = false;
char c;
while((c = wordfile.get()) !=EOF)
{
if (!(isspace(c)))
{
nextword.append(1, c);
}
return nextword;
}
}
bool ReadWords::isNextWord()
{
if(!wordfile.eof())
{
return true;
}
else
{
return false;
}
}
main.cpp
main()
{
int count = 0;
ReadWords rw("hamlet.txt");
while(rw.isNextWord()){
rw.getNextWord();
count++;
}
cout << count;
rw.close();
}
What it does at the moment is counts the number of characters. I'm sure its just a simple fix and something silly that I'm missing. But I've been trying for long enough to go searching for some help.
Any help is greatly appreciated. :)
Rather than parse the file character-by-character, you can simply use istream::operator<<() to read whitespace-separated words. << returns the stream, which evaluates to true as a bool when the stream can still be read from.
vector<string> words;
string word;
while (wordfile >> word)
words.push_back(word);
There is a common formulation of this using the <iterator> and <algorithm> utilities, which is more verbose, but can be composed with other iterator algorithms:
istream_iterator<string> input(wordfile), end;
copy(input, end, back_inserter(words));
Then you have the number of words and can do with them whatever you like:
words.size()
If you want to find "Hello" and "James", use find() from the <algorithm> header to get iterators to their positions:
// Find "Hello" anywhere in 'words'.
const auto hello = find(words.begin(), words.end(), "Hello");
// Find "James" anywhere after 'hello' in 'words'.
const auto james = find(hello, words.end(), "James");
If they’re not in the vector, find() will return words.end(); ignoring error checking for the purpose of illustration, you can count the number of words between them by taking their difference, adjusting for the inclusion of "Hello" in the range:
const auto count = james - (hello + 1);
You can use operator-() here because std::vector::iterator is a “random-access iterator”. More generally, you could use std::distance() from <iterator>:
const auto count = distance(hello, james) - 1;
Which has the advantage of being more descriptive of what you’re actually doing. Also, for future reference, this kind of code:
bool f() {
if (x) {
return true;
} else {
return false;
}
}
Can be simplified to just:
bool f() {
return x;
}
Since x is already being converted to bool for the if.
To count:
std::ifstream infile("hamlet.txt");
std::size_t count = 0;
for (std::string word; infile >> word; ++count) { }
To count only between start and stop:
std::ifstream infile("hamlet.txt");
std::size_t count = 0;
bool active = false;
for (std::string word; infile >> word; )
{
if (!active && word == "Hello") { active = true; }
if (!active) continue;
if (word == "James") break;
++count;
}
I think "return nextword;" should instead be "else return nextword;" or else you are returning from the function getNextWord every time, no matter what the char is.
string ReadWords::getNextWord()
{
bool pWord = false;
char c;
while((c = wordfile.get()) !=EOF)
{
if (!(isspace(c)))
{
nextword.append(1, c);
}
else return nextword;//only returns on a space
}
}
To count all words:
std::ifstream f("hamlet.txt");
std::cout << std::distance (std::istream_iterator<std::string>(f),
std::istream_iterator<std::string>()) << '\n';
To count between two words:
std::ifstream f("hamlet.txt");
std::istream_iterator<std::string> it(f), end;
int count = 0;
while (std::find(it, end, "Hello") != end)
while (++it != end && *it != "James")
++count;
std::cout << count;
Try this:
below the line
nextword.append(1, c);
add
continue;