C++ comparing the index of a string to another string? - c++

How can I compare a single character from a string, and another string (which may or may not be greater than one character)
This program gives me almost 300 lines of random errors. The errors don't reference a specific line number either, just a lot of stuff about "char* ", "", or "std::to_string".
#include <iostream>
#include <string>
using std::cout;
using std::string;
int main() {
string str = "MDCXIV";
string test = "D";
if (test == str[4]) { // This line causes the problems
cout << test << endl;
}
return 0;
}

str[4] is a char type, which will not compare with a string.
Compare apples with apples.
Use
test[0] == str[4]
instead.

You need to convert str[4] (which is a char) to a string before you can compare it to another string. Here's a simple way to do this
if (test == string(1, str[4])) {

You're comparing a char to a std::string, this is not a valid comparison.
You're looking for std::string::find, as follows:
if( test.find( str[4] ) != std::string::npos ) cout << test << "\n";
Note that this will return true if test contains str[4].

You're mixing types. It doesn't know how to compare a string (test) to a char (str[4]).
If you change test to a char that will work fine. Or reference the specific character within test you want to compare such as if (test[0] == str[4]) it should compile and run.
However, as this is merely an example and not really the true question what you'll want to do is look at the functionality that the std::string class supplies

Also you need "D" to be a char value not a string value if you are comparing it like that.
std::string myString = "Hello World";
const char *myStringChars = myString.c_str();
You have to turn it into a char array before can access it. Unless you do.
str.at(i);
which you can also write as
str[i] <-- what you did.
Essentially, this all boils down to test needs to initialized like char test = 'D';
Final Output..
#include <iostream>
#include <string>
using std::cout;
using std::string;
int main() {
string str = "MDCXIV";
char test = 'D';
if (test == str[4]) { // This line causes NO problems
cout << test << endl;
}
return 0;
}

I think you might be mixing python with c++. In c++ 'g' refers to a single character g not a string of length 1. "g" refers to an array (string) which is 1 character long and looks like ['g']. So as you can see, if you compare a single character to an array of characters no matter if the array is a single character long, this operation is not defined.
This will work if define it yourself by building a class which is able to compare string of one character long to a single character. Or just overload the == operator for doing just that
Example:
#include <iostream>
#include <string>
using std::cout;
using std::string;
using std::endl;
bool operator == ( const string &lh, const char &rh) {
if (lh.length() == 1) return lh[0] == rh;
return 0;
}
int main() {
string str = "MDCXIV";
string test = "D";
if (test == str[4]) {
cout << test << endl;
}
else cout << "Not a match\n";
return 0;
}

Related

How to remove whitespace from a expression using a function with const char* pointer

I am working with a small piece of code and want to remove all the whitespaces from a simple expression. I am taking char array expression and passing it to an function with const char* pointer,but i am not able to remove the whitespace. here is what i tried, but didn't get desired output.
#include <iostream>
using namespace std;
void evaluate(const char *expression){
if (*expression == '\0') cout<<"Invalid"<<endl;
while(*expression){
if(*expression == ' '){
*expression++ ;
}
expression++;
}
cout<<expression;
}
int main()
{
char expr[] = "1 + 2 * 3";
evaluate(expr);
return 0;
}
It will be great if someone can help me with this.
Thanks in advance.
Use std::string and the erase-remove idiom
#include <iostream>
#include <string>
void evaluate(const char *expression){
if (*expression == '\0') std::cout << "Invalid\n";
std::cout << expression;
}
int main()
{
char expr[] = "1 + 2 * 3";
std::string exprString = expr;
exprString.erase(
std::remove(std::begin(exprString), std::end(exprString), ' '),
std::end(exprString));
evaluate(exprString.c_str());
return 0;
}
In this code I added string but I recommend to completely remove the C-strings in this code and replace them by std::string.
You can't change the C-string inside the function because it's const.
If I understand your intent is simply to output the expression without spaces when calling evaluate(), you can simplify things by outputting each character that is not a space with:
#include <iostream>
using namespace std;
void evaluate (const char *expression) {
if (!*expression) {
cout << "Invalid\n";
return;
}
while (*expression) {
if (*expression != ' ')
cout << (char)*expression;
expression++;
}
cout << '\n';
}
int main() {
char expr[] = "1 + 2 * 3";
evaluate(expr);
}
Example Use/Output
$ ./bin/rmws_const_char
1+2*3
*expression++
This only increments the pointer (and needlessly evaluates what it was pointing at). It does not modify the original character array.
If you want the expression in memory without spaces, rather than just for output purposes, I suggest that you build a new array with the spaces removed.

How to read the last character in a string

I was trying to print the last character of a string, for example str[]="This is an example", I tried to print the 'e' of "example" with some functions, but none of them funct as I expected. I know it's more simple to write in the code the position number of the last character, but as in strrchr function, the code work by itself. Is there a function that works similar?
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int main ()
{
char str[] = "This is an example";
char * pch;
pch=strrchr(str,'s');
cout<<str<<endl;
cout<<"Last time 's' was found was in position: "<<pch-str+1<<endl;
cout<<"Last character in this example is "<<str[X];
return 0;
}
From the documentation for strrchr:
The terminating null-character is considered part of the C string. Therefore, it can also be located to retrieve a pointer to the end of a string.
Thus, strrchr(str, '\0')[-1] will have the last character. Note that this is only safe if you're sure str isn't empty.
Simple: use the standard strlen function, as follows:
int main ()
{
char str[] = "This is an example";
char * pch;
pch=strrchr(str,'s');
cout<<str<<endl;
cout<<"Last time 's' was found was in position: "<<pch-str+1<<endl;
size_t X = strlen(str) - 1; // X will be the index of the last character!
cout<<"Last character in this example is "<<str[X];
return 0;
}
Or, just for fun, if you want to handle the case where the string could be empty:
size_t X = strlen(str); X -= !!X; // Non-zero: decrement, Zero: Leave as is
cout<<"Last character in this example is "<<str[X];
Then, for an empty string, cout << str[X] will show whatever the implementation does for a NULL character.
If you don't mind to use std::string this snippet would do the job.
#include <string>
#include <iostream>
int main() {
std::string str = "This is some text";
std::cout << str.back() << std::endl;
}
I assume you choose char[] to avoid allocation or something similar so am not going to discuss std::string as an option.
Three solutions, one in modern C++ using string_view, one using templates ;
and one using std::size and the index operator.
Solution 1.1:
I recommend you use this, its nearly optimal and is much more readable than the alternative. It also doesn't require as much boiler plate to handle empty strings, or strings without null termination.
#include <string_view>
#include <iostream>
int main()
{
std::string_view str = "This is an example";
auto X = str.find_last_of('s');
//
// Make sure the character exists in the string
if (X != std::string_view::npos)
{
std::cout<< str << std::endl;
std::cout<< "Last time 's' was found was in position: " << X << std::endl;
}
else
{
std::cout<<"Character did not exist in string.\n";
}
if (!str.empty()) std::cout<< "Last character in this example is " << str.back();
else std::cout << "Cannot get the last character in an empty string!";
return 0;
}
You can run the solution here:
https://onlinegdb.com/SJK2hjPEB
The same code will work with std::string.
Solution 1.2
This is a compile time only solution, it relies on the string being aggregate constructed or constructed as a string.
template <size_t N>
constexpr char LastCharacter(char (&input)[N])
{
static_assert(N >= 1, "A character array representing a string must have atleast 1 character AND a null terminator.");
return (input[N - 1] == '\0') ? input[N - 2] : input[N - 1];
}
Tests and examples shown here:
https://onlinegdb.com/HJ_IXEd4H
Solution 2
This has the required checks to avoid issues with empty strings.
In this version it is a compile time error to have an empty array. str[] = "" is not an empty array it has 1 character, a null. An empty string has no last character, this needs to be handled. It also should be handled for the strrchr.
If you must use strrchr(...) then consider checking whether the result is nullptr. If a nullptr is returned then the character wasn't found in the string:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <cassert>
using namespace std;
int main ()
{
char str[] = {'h', 'e','l', 'l', 'o', '\0'};
//
// Prevent use with an empty array (1 character + 1 null character minimum)
if (std::size(str) > 1)
{
//
// Only allow null terminated strings.
assert( str[std::size(str) - 1] == '\0' );
//
// There skip the last null character and get the last character
// No null character, not compensation needed
cout<<"Last character in this example is "<< str[ std::size(str) - 2 ];
}
else
{
cout << "Cannot process empty string\n";
}
return 0;
}
https://onlinegdb.com/SkrP2Q_NB
Please note, defining strings as arrays enables strings to exist without null terminators. In that case the above solution does not function. If you want to handle that case you need to check for the existance of a null terminator and if it is present compensate in code. assert causes an error if there isn't a null terminator.
--
To elaborate on the problem with strrchr. The function requires a null terminated string.
The terminating null-character is considered part of the C string.
Therefore, it can also be located to retrieve a pointer to the end of
a string.
http://www.cplusplus.com/reference/cstring/strrchr/
This was quoted by the previous answer, but for completeness also here.
The datatype you are using allows a character array with no null termination:
char data[] = {'a', 'b', 'c'};
That is what the assert handles in the solution 2.

Check if a string exists in array

For a school assignment I need to check whether a string entered by the user is stored in a pre-defined word array.
I want to implement a function to perform the check, that may look like this:
bool exists(dict words, char check) { /* how to implement this? */ }
But I have no clue whether this will work or how to implement it. Can anyone help?
Here's my code:
#include <iostream>
#include <string>
using namespace std;
struct dict {
string word;
};
int main() {
dict words[5];
words[0].word = 'abc';
words[1].word = 'bcd';
words[2].word = 'cde';
words[3].word = 'def';
words[4].word = 'efg';
char user_input[100];
cin.getline(user_input, 100);
if (...) { // how do I check if the user input is in my word array?
cout << "found\n";
}
else {
cout << "not found\n";
}
}
First of all, dict is a structure and char is type able to hold single character, so you would rather need to have:
bool exists(const dict* words, const string& check);
From this point, I would say, that:
const dict* should be changed to const vector<dict>&.
std::getline is able to read input directly into string, so no plain char array is needed.
But since it's a school assignment, I suppose, that you have some limitations (and can't use neither std::vector nor std::find, that would do the job). So:
bool exists(const dict* words, size_t count, const std::string& check)
{
for(size_t n = 0; words && (n < count); ++n)
{
if(words[n].word == check)
return true;
}
return false;
}
Example:
dict langs[3];
langs[0].word = "C++";
langs[1].word = "Java";
langs[2].word = "Python";
std::string s_1 = "Java";
std::string s_2 = "C++ 11";
printf("exists(%s) : %s\n", s_1.c_str(), exists(langs, 3, s_1) ? "yes" : "no");
printf("exists(%s) : %s\n", s_2.c_str(), exists(langs, 3, s_2) ? "yes" : "no");
Output:
exists(Java) : yes
exists(C++ 11) : no
Link to sample code.
As the other answer has already pointed out, you should add a size parameter to the function signature in order to be able to iterate the array (especially to know when to stop iteration.). Then a simple loop with a comparison will do the trick.
Note that you shouldn't normally need to use raw arrays in C++, but rather one of the containers from the standard library, e.g., std::vector. Also, you should use std::string and std::getline() for your user input, and you should fix your string literals (use double quotes "..." instead of single quotes '...'). Further, you should avoid using namespace std; conciouslessly. Have a look at the links at the end of this post for some further reading on these points.
Example code:
#include <iostream>
#include <string>
#include <vector>
bool exists(std::string const & user_input,
std::vector<std::string> const & words)
{
for (int i = 0; i < words.size(); i++)
if (user_input == words[i])
return true;
return false;
}
int main() {
std::vector<std::string> words(5);
words[0] = "abc";
words[1] = "bcd";
words[2] = "cde";
words[3] = "def";
words[4] = "efg";
std::string user_input;
std::getline(std::cin, user_input);
if (exists(user_input, words))
std::cout << "found\n";
else
std::cout << "not found\n";
}
Example output:
$ g++ test.cc && echo "abc" | ./a.out
found
The following might be beyond the scope of your school assignment, but maybe this will be helpful for future visitors to this question.
Note that an array (which std::vector is) is not the most efficient data structure to perform this sort of task, as you have to iterate the entire array to check every single item (linear complexity).
The C++ standard library also provides the container types std::set and std::unordered_set (the latter since C++11). Here the search space is organized in a special way (binary search tree: logarithmic complexity, hash table: constant complexity on average) to improve lookup time of the key type (std::string in this case).
Here's an example:
#include <iostream>
#include <string>
#include <set>
typedef std::set<std::string> set_type;
bool input_exists(std::string input, set_type const & words) {
return words.find(input) != words.end();
}
int main() {
set_type words = {"abc", "bcd", "cde", "def", "efg"};
std::string input;
if (std::getline(std::cin, input)) {
std::cout << "input: '" << input << "' ";
if (input_exists(input, words))
std::cout << "found\n";
else
std::cout << "not found\n";
}
}
Example output:
$ g++ test.cc -std=c++11
$ echo "abc" | ./a.out
input: 'abc' found
$ echo "abcdefg" | ./a.out
input: 'abcdefg' not found
For reference:
http://en.cppreference.com/w/cpp/container/vector
http://en.cppreference.com/w/cpp/string/basic_string
http://en.cppreference.com/w/cpp/string/basic_string/getline
http://en.cppreference.com/w/cpp/language/string_literal
Why is "using namespace std" considered bad practice?
http://en.wikipedia.org/wiki/Binary_search_tree
http://en.wikipedia.org/wiki/Hash_table
http://en.cppreference.com/w/cpp/container/set
http://en.cppreference.com/w/cpp/container/set/find
http://en.cppreference.com/w/cpp/container/unordered_set
http://en.cppreference.com/w/cpp/container/unordered_set/find
http://en.wikipedia.org/wiki/Computational_complexity_theory

How do I check for stored "\t" in a string?

Can someone explain to me how to properly search for a "tab" character stored in a string class?
For example:
text.txt contents:
std::cout << "Hello"; // contains one tab space
User enters on prompt: ./a.out < text.txt
main.cpp:
string arrey;
getline(cin, arrey);
int i = 0;
while( i != 10){
if(arrey[i] == "\t") // error here
{
std::cout << "I found a tab!!!!"
}
i++;
}
Since there is only one tab space in the textfile, I am assuming it is stored in index [0], but the problem is that I can't seem to make a comparison and I don't know any other way of searching it. Can someone help explain an alternative?
Error: ISO C++ forbids comparison between pointer and integer
First of all, what is i? And secondly, when you use array-indexing of a std::string object, you get a character (i.e. a char) and not a string.
The char is converted to an int and then the compiler tries to compare that int with the pointer to the string literal, and you can't compare plain integers with pointers.
You can however compare a character with another character, like in
arrey[i] == '\t'
std::string::find() might help.
Try this:
...
if(arrey.find('\t') != string::npos)
{
std::cout << "I found a tab!!!!";
}
More info on std::string::find is available here.
Why not using what C++ library provides? You could do it like this:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string arrey;
getline(cin, arrey);
if (arrey.find("\t") != std::string::npos) {
std::cout << "found a tab!" << '\n';
}
return 0;
}
The code is based on this answer. Here is the ref for std::find.
About your edit, how are sure that the input is going to be 10 positions? That might be too little or too big! If it is less than the actual size of the input, you won't look all the characters of the string and if it is too big, you are going to overflow!
You could use .size(), which says the size of the string and use a for loop like this:
#include <iostream>
#include <string>
using namespace std;
int main() {
string arrey;
getline(cin, arrey);
for(unsigned int i = 0; i < arrey.size(); ++i) {
if (arrey[i] == '\t') {
std::cout << "I found a tab!!!!";
}
}
return 0;
}

How do I check if a const char* begins with a specific string? (C++)

I have a const char* variable and I want to check if it begins with a certain string.
For example:
string sentence = "Hello, world!";
string other = "Hello";
const char* c = sentence.c_str();
if(/*"c" begins with "other"*/)
{
//Do something
}
How can I do this using the if statement?
To check whether a C string begins with a certain substring, you could use strncmp().
For C++ strings, there is a std::string::compare() overload that accepts offsets and lengths.
You can use the c function strstr(string1, string2) which returns a pointer to the first occurence of string2 in string1. If the pointer returned is to string1 then string1 begins with what you wanted to match.
const char* str1 = "Hello World";
const char* ptr = strstr(str1, "Hello");
// -----
if(str1 == ptr)
puts("Found");
Keep in mind that you're other variable will need to use it's .c_str() method in the context of the strstr function.
There are a few options that come to mind, one using legacy C calls and another two being more C++ specific.
If you really have a const char *, it's probably best to use the legacy C one but, since your sample code only creates a const char * from a std::string, I've offered other solutions as you seem to be working exclusively with strings as the true source of the data.
In C++, you can use string::compare or string::find thus, though the compare is likely to be more efficient since it only checks at the start of the string rather than checking everywhere and comparing the return value to zero (the find seems more concise so, if you value that and speed is not of the utmost importance, you can use it instead):
if (haystack.compare(0, needle.length(), needle) == 0)
if (haystack.find(needle) == 0)
Using the legacy C stuff, you can do:
if (strncmp (haystack.c_str(), needle.c_str(), needle.length()) == 0)
See the following complete program for an example:
#include <iostream>
#include <string>
#include <cstring>
int main (void) {
std::string haystack = "xyzzy";
std::string needle = "xy";
std::string other = "99";
if (haystack.compare(0, needle.length(), needle) == 0)
std::cout << "xy found\n";
else
std::cout << "xy not found\n";
if (haystack.compare(0, other.length(), other) == 0)
std::cout << "xx found\n";
else
std::cout << "xx not found\n";
return 0;
}
For the other options, simply make changes to the if statements shown above to match the samples given.