Comparing Character Literal to Std::String in C++ - c++

I would like to compare a character literal with the first element of string, to check for comments in a file. Why use a char? I want to make this into a function, which accepts a character var for the comment. I don't want to allow a string because I want to limit it to a single character in length.
With that in mind I assumed the easy way to go would be to address the character and pass it to the std::string's compare function. However this is giving me unintended results.
My code is as follows:
#include <string>
#include <iostream>
int main ( int argc, char *argv[] )
{
std::string my_string = "bob";
char my_char1 = 'a';
char my_char2 = 'b';
std::cout << "STRING : " << my_string.substr(0,1) << std::endl
<< "CHAR : " << my_char1 << std::endl;
if (my_string.substr(0,1).compare(&my_char1)==0)
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
std::cout << "STRING : " << my_string.substr(0,1) << std::endl
<< "CHAR : " << my_char2 << std::endl;
if (my_string.substr(0,1).compare(&my_char2)==0)
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
std::cout << "STRING : " << my_string << std::endl
<< "STRING 2 : " << "bob" << std::endl;
if (my_string.compare("bob")==0)
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
}
Gives me...
STRING : b
CHAR : a
NOPE...
STRING : b
CHAR : b
NOPE...
STRING : bob
STRING 2 : bob
WOW!
Why does the function think the sub-string and character aren't the same. What's the shortest way to properly compare chars and std::string vars?
(a short rant to avoid reclassification of my question.... feel free to skip)
When I say shortest I mean that out of a desire for coding eloquence. Please note, this is NOT a homework question. I am a chemical engineering Ph.D candidate and am coding as part of independent research. One of my last questions was reclassified as "homework" by user msw (who also made a snide remark) when I asked about efficiency, which I considered on the border of abuse. My code may or may not be reused by others, but I'm trying to make it easy to read and maintainable. I also have a bizarre desire to make my code as efficient as possible where possible. Hence the questions on efficiency and eloquence.

Doing this:
if (my_string.substr(0,1).compare(&my_char2)==0)
Won't work because you're "tricking" the string into thinking it's getting a pointer to a null-terminated C-string. This will have weird effects up to and including crashing your program. Instead, just use normal equality to compare the first character of the string with my_char:
if (my_string[0] == my_char)
// do stuff

Why not just use the indexing operator on your string? It will return a char type.
if (my_string[0] == my_char1)

You can use the operator[] of string to compare it to a single char
// string::operator[]
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str ("Test string");
int i; char c = 't';
for (i=0; i < str.length(); i++)
{
if (c == str[i]) {
std::cout << "Equal at position i = " << i << std::endl;
}
}
return 0;
}

The behaviour of the first two calls to compare is entirely dependent on what random memory contents follows the address of each char. You are calling basic_string::compare(const char*) and the param here is assumed to be a C-String (null-terminated), not a single char. The compare() call will compare your desired char, followed by everything in memory after that char up to the next 0x00 byte, with the std::string in hand.
Otoh the << operator does have a proper overload for char input so your output does not reflect what you are actually comparing here.
Convert the decls of and b to be const char[] a = "a"; and you will get what you want to happen.

Pretty standard, strings in c++ are null-terminated; characters are not. So by using the standard compare method you're really checking if "b\0" == 'b'.
I used this and got the desired output:
if (my_string.substr(0,1).compare( 0, 1, &my_char2, 1)==0 )
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
What this is saying is start at position 0 of the substring, use a length of 1, and compare it to my character reference with a length of 1. Reference

Related

How do I print const char?

#include <iostream>
using namespace std;
int main() {
int age = 20;
const char* pDept = "electronics";
cout << age << " " << pDept;
}
The above code is normal.
Why shouldn't I use cout << *pDept instead of cout << pDept above?
Both of them are legal in C++. Which one to use depends on what you want to print.
In your case, pDept is a pointer that points to a char in memory. It also can be used as a char[] terminated with \0. So std::cout << pDept; prints the string the pointer is pointing to.
*pDept is the content that pDept points to, which is the first character of the string. So std::cout << *pDept; prints the first character only.

if-statement on different typeid's

I am currently working on a code and I am trying to use a if-statement on a variable which was taken from a .txt file with a basic string. Its supposed to look like
if (a.variable == "string") {}
When I use
std::cout << a.variable << std::endl;
std::cout << "string" << std::endl;
I get the same results but when using
std::cout << typeid(a.variable).name() << std::endl;
std::cout << typeid("string").name() << std::endl;
I get different results:
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
and
A5_c.
Could this be the reason why the if-statement failed? Unless I am incorrect, the first typeid stands for a basic string.
I am grateful for any input!
The code I use for reading it looks like:
std::string::size_type beginoption = section.find("=",position);
beginoption = beginoption +1;
std::string::size_type endoption = section.find("\n",position);
optionstorage = section.substr(beginoption, endoption - beginoption);
Two objects in C++ don't have to be the same type to compare as equal. You can compare string objects to string literals because there is an operator== overload that accepts std::string and char const * arguments. (The typeid() operator returns a different value because the two expressions have different types; one is a string object and the other is a char array -- but you can indeed still compare them.)
You mentioned that your "if statement is failing" but when you inspect the contents of the strings, they appear to be the same -- they may actually not be the same. For example, in your code, if a.variable has trailing whitespace, you would not see this in the output and yet the strings would also not be equal.
Try writing both strings surrounded by some characters. I suspect that you will see there is some extra whitespace somewhere:
std::cout << '[' << a.variable << ']' << std::endl;
std::cout << '[' << "string" << ']' << std::endl;
Consider also displaying a.variable.size(). If it's not 6, then the two strings cannot be equal since they have different lengths.
For the purposes of typeid, a.variable is of type std::string while the string literal "string" is of type char const [7].
That explains the output of
std::cout << typeid(a.variable).name() << std::endl;
std::cout << typeid("string").name() << std::endl;

How do I take a character pointer of 20 characters to output the contents plus the extra whitespace?

This is my first C++ related question and I'm new to character pointers and their usage. I think I've got it down but for an assignment the required output for this program is
So each first and last name is a character pointer of 20 characters (I could probably size it down but whatever) and when I output it now it looks like
cout << stu[i]->first << " " << stu[i]->last << " " << (float)stu[i]->mean << endl; and outputs the same thing as above but with a single space between each piece of data. How would I get it to print out the whitespace of the rest of the char pointer so it creates nice neat columns?
Thanks!
There is no magic whitespace in memory a char* points to. If you want to align your output you could use std::setw():
#include <iostream>
#include <iomanip>
int main()
{
char const *foo{ "Jamie" };
char const *bar{ "Reynolds" };
std::cout << std::setw(10) << foo << std::setw(10) << bar << '\n';
}

How to use Arrays, with Strings

I'm a C++ programmer, who's still in the nest, and not yet found my wings. I was writing a Calendar program, and I discovered, that C++ does not support a string type. How do I make an Array, that will be able to store strings of characters?
I've thought of creating an enumerated data type, as the array type. While, it will work, for my Calendar, it won't work if say I was creating a database of the names of students in my class.
http://prntscr.com/7m074w I got; "error, 'string' does not name a type."
that C++ does not support a string type.
Wrong info, you can create an character array as follows
char array[length];
//Where length should be a constant integer
Otherwise you can depend on standard template library container, std::string
If you have C++11 compiler you can depend on std::array
The C++ Standard Library includes a string type, std::string. See http://en.cppreference.com/w/cpp/string/basic_string
The Standard Library also provides a fixed-size array type, std::array. See http://en.cppreference.com/w/cpp/container/array
But you may also want to learn about the dynamically-sized array type, std::vector. See http://en.cppreference.com/w/cpp/container/vector
The language also includes legacy support for c-strings and c-arrays, which you can find in a good C++ or C book. See The Definitive C++ Book Guide and List
An example of how to use an array/vector of strings:
#include <string>
#include <array>
#include <vector>
#include <iostream>
int main() {
std::array<std::string, 3> stringarray;
stringarray[0] = "hello";
stringarray[1] = "world";
// stringarray[2] contains an empty string.
for (size_t i = 0; i < stringarray.size(); ++i) {
std::cout << "stringarray[" << i << "] = " << stringarray[i] << "\n";
}
// Using a vector, which has a variable size.
std::vector<std::string> stringvec;
stringvec.push_back("world");
stringvec.insert(stringvec.begin(), "hello");
stringvec.push_back("greetings");
stringvec.push_back("little bird");
std::cout << "size " << stringvec.size()
<< "capacity " << stringvec.capacity()
<< "empty? " << (stringvec.empty() ? "yes" : "no")
<< "\n";
// remove the last element
stringvec.pop_back();
std::cout << "size " << stringvec.size()
<< "capacity " << stringvec.capacity()
<< "empty? " << (stringvec.empty() ? "yes" : "no")
<< "\n";
std::cout << "stringvec: ";
for (auto& str : stringvec) {
std::cout << "'" << str << "' ";
}
std::cout << "\n";
// iterators and string concatenation
std::string greeting = "";
for (auto it = stringvec.begin(); it != stringvec.end(); ++it) {
if (!greeting.empty()) // add a space between words
greeting += ' ';
greeting += *it;
}
std::cout << "stringvec combined :- " << greeting << "\n";
}
Live demo: http://ideone.com/LWYevW
You can create an array of characters by char name[length];.
C++ also has a data type string. You can create an array of strings and store what values you'd like. here .
So
use array of characters
use string data type
For Example -
#include <iostream>
#include <string>
int main ()
{
//To Create a String
std::string s0 ("Initial string");
return 0;
}
C++ does have a string type: string from #include <string>
If you don't want to use that, you can also use char* name = "YourTextHere..." or `char[length+1] name = "YourTextHere"

Why setting null in the middle of std string doesn't have any effect

Consider
#include <string>
#include <iostream>
int main()
{
/*
hello
5
hel
3
*/
char a[] = "hello";
std::cout << a << std::endl;
std::cout << strlen(a) << std::endl;
a[3] = 0;
std::cout << a << std::endl;
std::cout << strlen(a) << std::endl;
/*
hello
5
hel o
5
*/
std::string b = "hello";
std::cout << b << std::endl;
std::cout << b.length() << std::endl;
b[3] = 0;
std::cout << b << std::endl;
std::cout << b.length() << std::endl;
getchar();
}
I expect std::string will behave identical to char array a. That's it, insert null character in the middle of the string, will "terminate" the string. However, it is not the case. Is my expectation wrong?
A std::string is not like a usual C string, and can contain embedded NUL characters without problems. However, if you do this you will notice the string is prematurely terminated if you use the .c_str() function to return a const char *.
No - std::strings are not NUL-terminated like C "strings"; the std::string records its length independently.
#Lou is right: don't do that. Instead, do this:
b.erase (3, b.length());
Yes, your expectation is wrong. std::string is meant to be different from C strings (e.g. not necessarily stored in consecutive memory / an array).
To duplicate the first section's behavior, try std::cout << b.c_str() instead of std::cout << b.
I expect std::string will behave identical to char array a.
Why? Nothing in the documentation, anywhere, having to do with std::string says it does this.
My suggestion, stop treating like C++ as C plus some stuff.