C++: Find method - c++

so if i were to enter patricia(don't worry im converting it toupper) that string would be loaded into my vector.
My question is about the find functions. i am counting down characters correct? so if i were to enter patricia and j would be on ABBOT, PATRICIA the value in comma would be 5. Ok im good so far, but what happens in my found variable?
bool NameSearch::findFirstNames(vector<string> &vsFirst, string name)
{
int j = 0;
bool bName = false;
vsFirst.clear();
while(j < total)
{
int comma;
comma = names[j].find(',');
//Confused here
int found = names[j].find(name, comma);
if(found > -1)
{
vsFirst.push_back(names[j]);
bName = true;
}
j++;
}
return bName;
}

The if (found > -1) test probably works on your platform but is technically dubious.
The return type of std::string::find() is std::string::size_type, and if the substring you're searching is not found, the returned value is std::string::npos (on the other hand, if the substring is found, the returned value is the character index of its first occurrence).
Now the std::string::npos value happens to be the greatest possible value of type std::string::size_type, and if that is unsigned int on your implementation, that means the comparison with the signed int -1 will yield true.
However, no assumptions can be made in general on the type of std::string::size_type Thus, I suggest to rewrite the test as:
if (found != std::string::npos)
{
...
}

This is misleading code. std::string::find() returns a size_t, not an int.
int comma;
comma = names[j].find(',');
This is misleading code. When std::string::find() fails, it returns std::string::npos, not -1. In your environment, it's equivalent to -1 by coincidence.
if(found > -1)
The if statement is effectively trying to check "if a result was found" by making sure it isn't std::string::npos.

There are two other answers, that point out what is wrong with this code, but I feel like none of them explains to you, what the author was doing, and that's the explanation you want. :)
Let's look at the following snippet first.
int comma;
comma = names[j].find(',');
As pointed out, it should be rewritten as:
size_t comma;
comma = names[j].find(',');
There are 4 overloads of the find method in the std::string
The code above uses this one:
size_t find (char c, size_t pos = 0) const;
It returns the index, at which the character passed as the first argument (in your case it's ',') appears in the string or std::string::npos if that character isn't found. Apparently the author is sure the ',' character must be present in the string names[j] and doesn't check the result.
In the line:
int found = names[j].find(name, comma);
which again should be rewritten as:
size_t found = names[j].find(name, comma);
the following overload of the find method is used:
size_t find (const string& str, size_t pos = 0) const;
This one searches the string names[j] for the first occurrence of the string passed as the first argument (in your case name) and returns the index at which the match starts if there is a match or std::string::npos otherwise.
As you can see, both mentioned overloads of the find method have a second parameter with default value of 0. This second parameter allows a user to specify, at what index to start the search in the searched string (in your case names[j])
The call:
comma = names[j].find(',');
is equivalent to the call:
comma = names[j].find(',', 0);
and it means: look for the character ',' int the string names[j] starting from the beginning and return the index of the first occurrence of that character or std::string::npos, if there is no such character in that string.
The call:
size_t found = names[j].find(name, comma);
means: look for the substring equal to name in the string names[j], but start from the position where the comma was found and return the index of the first occurrence of that substring or std::string::npos if there is no such substring in that string, after the comma.
Maybe comma_position instead of comma would have been a better name for the variable.

Related

While iterating through a string, why am I NOT getting out of range error, even though I'm already beyond its length?

My code is literally this:
int main(){
string s = "Success!\n";
for (int i=0; i<10; ++i) cout<<s[i];
return 0;
}
string s is of length 8; and even though I've used an iterator 'i' that goes beyond the string's length, I do not get any error. Why?
Output is:
Success!
WITH A NEWLINE, I have not even put a newline character
string s is of length 8
no it's not, it's 9.
and even though I've used an iterator 'i' that goes beyond the string's length, I do not get any error
You're not going beyond the string's length, you go equal to the string's length. This is defined as returning a null character. Even if you went beyond the string's length with operator[], this is undefined behavior, not expected to throw an exception.
I have not even put a newline character
... yes you did.
As per the definition of subscripting (bracket) operator for string:
char& operator[] (size_t pos);
If pos is equal to the string length, the function returns a reference to the null character that follows the last character in the string (which should not be modified).
"Success!\n" is a string of length 9. With S at index 0, ! at index 7, and \n at index 8. So when you reference s[9], it's returning back the null \0 char.
Instead of cout << s[i] use cout << s.at(i) and you will get the results you want.

String Comparison Issue (C++)

Problem Solved: StringVariable[position] (in this case Word[e]) outputs a value that is defined as a char variable type rather than the string variable type I had expected it to. Thank you all for your help!
When I run my Hangman game I get the following error:
Error 2 error C2678: binary '!=' : no operator found which takes a left-hand operand of type 'std::string' (or there is no acceptable conversion)
Error 1 error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::string' (or there is no acceptable conversion)
4 IntelliSense: no operator "!=" matches these operands
3 IntelliSense: no operator "==" matches these operands
I commented in the code where this error points to and copied in the functions related to the problem. The functions were then run in the main() function to simplify the code.
This section of the code is meant to check if the guess is equal to the letter in the word. Let me know if I need to provide further explanation.
Related Code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//Functions
void GrabWord();
void DiscoverLet();
void guess();
//Variables
int NumL, Fl, F, count[10];
string G, Word;
//Grab Word from .txt and define NumL
void GrabWord()
{
//Grab Random Line from .txt
//Random Line >> Larray
Word = "short";
NumL = Word.size();
}
//Checks if Guess matches any letters
void DiscoverLet()
{
for(int e = 0; e < NumL; e++)
{
//Error Points to the following two comparisons
if(G == Word[e])
{
count[e] = 1;
}
else if(G != Word[e])
{
Fl++;
}
else
{
cout << "Error: DiscoverLet(), G to Word[]\n";
}
}
if(Fl == NumL)
{
F = F + 1;
}
Fl = 0;
}
The proper string comparison that you are looking for is called find:
if(Word.find(G) > std::string::npos)
{
count[e] = 1;
}
else
{
Fl++;
}
The reason why your comparison does not work was that you Word[e] was grabbing a character of the string and it was being compared to a string variable.
Judging by your code it looks like you wanted to count the number of times the letter appears in the string. If you wanted to count the number of times the letter appears in the string then you can use the find function like this:
int count = 0;
int foundIdx = 0;
for(int i = 0; i < NumL; i++)
{
foundIdx = Word.find(G, foundIdx+1);
if (foundIdx == std::string::npos)
{
break;
}
count++;
}
if(G == Word[e])
...
else if(G != Word[e])
In these comparisons, G is a string and Word[e] is a character in a string. There is no operator to perform the respective comparisons.
G is a variable of type string. Word is also a type of string. So as you might already know that strings are nothing but array of chars. So Word[e] points to a character of the Word string. So
if(G == Word[e])
Here, you are comparing a string with a character. But C++ has no idea how to do that! I mean C++ does not know how to evaluate the expression. Because the operator == for comparing a string and a char is not overloaded inside string class. Same goes for the line
if(G != Word[e])
If you're trying to find out if Word[e] character appears in the G string, you should run another loop searching character by character of the string G. Or you can use find function.
The reason of the error is because you are comparing string to a character. You can use ==, !=, >, <, etc on character, but certainly not strings. And also, the string G appears to be empty. Hope this helps and correct me if I'm wrong! Happy coding!
G is string type but Word[e] is char type. You should convert Word[e] to String to compare with G by std::to_string or use method string::find with G to find content Word[e] in G.
The comparison won't work that way. You need to understand what is the difference between a char and a std::string. A variable of type char represent a single letter. A char cannot be multiple character, and cannot be empty. Is strictly one, single letter. Nothing less, nothing more.
A std::string can be seen as a managed array of char. It's size can be 0 to very big. This type expose the array access operator, the [n], and that operator returns a character from the string at position n. It's return type is char.
Since G is supposed to be an input letter from the user, I'd suggest you to declare G as a char. In fact, it will solve your problem.
The reason for that a string cannot be compared to a single character. A string is designed to be comparable to another whole string. And a character can be compared with another integral, or put it simpler, another char. So if you change the type of G to char, your comparison will work as expected.

Bounds of std::string::find_first_of

Suppose I have a string foo and I want to search for the second period, if any.
I'm using this code:
std::size_t start = foo.find_first_of('.');
if (start != std::string::npos){
std::size_t next = foo.find_first_of('.', start + 1);
/*and so on*/
I'm wondering if this is well-defined if the first period is at the end of the string.
I think it is since start + 1 will be on the null-terminator, so I'm not in any danger of accessing any memory I shouldn't.
Am I correct?
If the first dot is at the end of the string, it's at index size() - 1.
So then start + 1 == size(), meaning that find_first_of will look in the interval [size(), size()). This is an empty interval, so no memory accesses will be made at all.
There may well not be a null-terminator at that point. (The standard does not guarantee it: c_str() is required to add one if necessary).
But your code is fine in any case. The behaviour on setting a pointer to point to 1-past-an-array is well-defined, so it's permissible to call the function with start + 1 is start is the last character in your string. Internally, a dereference of that pointer will not take place you're outside the region that find_first_of will search.
The C++ Standard does not impose any restriction on the value of the second parameter.
The function tries to calculate an actual position xpos the following way
pos <= xpos and xpos < size()
If it is unable to find such a velue it returns std::string::npos
For example
std::string s( "AB" );
auto pos = s.find_first_of( "A", std::string::npos );
if ( pos == std::string::npos ) std::cout << "Not found" << std::endl;
The output is
Not found

How to use std::stod properly

I am working on writing a simple linear line calculator. For example, a user can enter two equations (strings) such as y=5x+3 and y=-3x+6. The most basic feature of this calculator is that it will return the intersection point of these two lines.
The obstacle I can't seem to figure out is how to parse the string into two pieces of data: the slope, and the y-intercept. This is a simple calculator, so the format of both lines will be y=mx+b, however, both the slope and/or y-intercept may be non-integer numbers (i.e. floats).
I came across a function in the string library called stod, which converts a number in a string to a numerical value (am I understanding this correctly?).
http://www.cplusplus.com/reference/string/stod/
My question is, will this function do the job? If so, how exactly do I use the "idx" parameter? I don't quite understand it.
If this isn't going to work, how can I parse this user-entered data?
both equations are strings (y=mx+b)
m and b have private variables dedicated in storing the decimal value (i.e. double m_ and double b_ are private member variables)
This is how the idx parameter works:
#include <string>
#include <iostream>
int main(void)
{
std::string data = "y=5.9568x+3.14"; //say you have a string like this..
double y, x, m, b;
y = 0;
x = 0;
std::size_t offset = 0; //offset will be set to the length of characters of the "value" - 1.
m = std::stod(&data[2], &offset); //So we want to get the value "5.9568
b = std::stod(&data[offset + 3]); //When we reach this line, offset has a value of 6
std::cout<<b;
return 0;
}
So now you're asking why does it have a value of 6? Well because:
5.9568 is exactly: 6 characters in length. Thus on the next line when we do
b = std::stod(&data[offset + 3]);
we are actually feeding it a pointer to address of x + 3.. and that turns out to be right at the beginning of the 3.14.
In other words it's equivalent to:
std::stod(&data[9]);
So that idx parameter is actually the index/length of the double in characters within the string. If the string is:
str = "3.14159"
Then std::stod(str, &idx) will make idx equal to: 6.
if the string is:
str = "y = 1024.789" then std::stod(&str[4], &idx) will make idx equal to: 8 STARTING FROM &str[4]..
Here's something simple with no error checking to get you started:
Assuming your input string is always exactly of the form y=mx+b and you wish to parse it to obtain the numerical values of m and b you can first tokenize the string with y, =, x, and as delimiters.
An example of a tokenizing function can be found here. Here it is reproduced:
void tokenize(const std::string &str,
std::vector<std::string> &tokens,
const std::string &delimiters)
{
// Skip delimiters at beginning.
std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
std::string::size_type pos = str.find_first_of(delimiters, lastPos);
while (std::string::npos != pos || std::string::npos != lastPos)
{
// Found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// Skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = str.find_first_of(delimiters, lastPos);
}
}
The first argument is the string to tokenize, the second is a reference to a vector<string> which the function will put the tokens in, and the third argument is a string containing all the delimiter characters. You can use it with the delimiters mentioned above like this:
string s = "y=-3x + 10";
vector<string> tokens;
tokenize(s, tokens, "y=x ");
For the example string above tokens will contain the following strings: -3, +, and 10.
Now you can iterate over tokens and call stod() on each token. You can put the results of stod() in a vector<double>:
vector<double> doubles;
for (vector<string>::iterator iter = tokens.begin(); iter != tokens.end(); ++iter) {
try {
doubles.push_back(stod(*iter)); // size_t* idx is an optional argument
} catch (...) {
// handle exceptions here. stod() will throw an exception
// on the "+" token but you can throw it away
}
}
Now doubles should have exactly 2 elements -- one for the slope and another for the intercept. Assuming the slope came first (the string was of the form y=mx+b instead of y=b+mx) then you can extract them from doubles:
double m = doubles[0];
double b = doubles[1];
Parsing the initial string is more complicated if the user is allowed different forms like y=b+mx (in that case the intercept came first), and much more complicated if the user can enter even stranger (but valid) forms like x*m+b=y (now you can't just assume that the number before the x character is the slope). It's not clear from your question exactly what alternate forms are considered valid, but nonetheless this should get you started.
Finally, as to your question about *idx, stod() puts into it the position of the first character after the number it parsed. This allows you to easily parse multiple numbers in a single string by skipping the number that was just parsed. Using the example at your reference link with some added comments:
std::string orbits ("365.24 29.53");
std::string::size_type sz; // alias of size_t
double earth = std::stod (orbits,&sz);
// sz now holds the position of the first character after 365.24, which is whitespace
// the next call to stod() will start from the sz position
double moon = std::stod (orbits.substr(sz));

Is the integer n in the string s? Is 4 in Ab56c4D? (C++)

Is there a standard function which will return a bool for this?
I'm writing a program that plays the game of life and the user enters two strings, S23 and B3 are examples. In my main loop I just want to check if an integer (the number of living surround cells) is in one of the strings.
Thanks for your help with this question. ;)
http://www.cplusplus.com/reference/string/string/find/
Searches the string for the content specified in either str, s or c, and returns the position of the first occurrence in the string.
Return Value:
The position of the first occurrence in the string of the searched content.
If the content is not found, the member value npos is returned.
First you need to get a string version of the integer value, then you can try to find it in the other string:
std::ostringstream oss;
oss << some_integer;
if (some_string.find(oss.str()) != std::string::npos)
// match...
Loop through the characters in the string and if the character ( (int)cur_char) ) is between 48 and 57 return true.