Get first char from std::string - c++

I need to get the first character of an std::string with a minimum amount of code.
It would be great if it would be possible to get the first char in one line of code, from an STL std::map<std::string, std::string> map_of_strings. Is the following code correct:
map_of_strings["type"][0]
EDIT
Currently, I am trying to use this piece of code. Is this code correct?
if ( !map_of_strings["type"].empty() )
ptr->set_type_nomutex( map_of_strings["type"][0] );
The prototype of the set_type function is:
void set_type_nomutex(const char type);

That should work if you've put a non-empty string into map_of_strings["type"]. Otherwise, you'll get an empty string back, and accessing its contents will probably cause a crash.
If you can't be sure whether the string exists, you can test:
std::string const & type = map["type"];
if (!type.empty()) {
// do something with type[0]
}
Or, if you want to avoid adding an empty string to the map:
std::map<std::string,std::string>::const_iterator found = map.find("type");
if (found != map.end()) {
std::string const & type = found->second;
if (!type.empty()) {
// do something with type[0]
}
}
Or you could use at to do a range check and throw an exception if the string is empty:
char type = map["type"].at(0);
Or in C++11, the map also has a similar at which you can use to avoid inserting an empty string:
char type = map.at("type").at(0);

The c_str() method will return a pointer to the internal data. If the string is empty, then a pointer to a NULL-termination is returned, so a simple one-liner is safe and easy:
std::string s = "Hello";
char c = *s.c_str();

It's not exactly clear from your question what your problem is, but the thing likely to go wrong with map_settings["type"][0] is that the returned string may be empty, resulting in undefined behavior when you do [0]. You have to decide what you want to do if there is no first character. Here's a possibility that works in a single line.
ptr->set_type_nomutex( map_settings["type"].empty() ? '\0' : map_settings["type"][0]);
It gets the first character or a default character.

string s("type");
char c = s.at(0);

Related

Calculate length of string object using pointers instead of char arrays

I'm working on an exercise to calculate the length of a string using pointers.
Here's the code I've written below:
int main() {
std::string text = "Hello World";
std::string *string_ptr = &text;
int size = 0;
//Error below: ISO C++ forbids comparison between pointer and integer [-fpermissive]
while (string_ptr != '\0') {
size++;
string_ptr++;
}
std::cout << size;
}
In a lot of examples that I've seen, the string is often a char array which I also understand is a string. However, I want to try calculate it as a string object but I'm getting the error below.
Is it possible to calculate it where the string is an object, or does it need to be a char array?
If you just want the size of the string, well, use std::string::size():
auto size = text.size();
Alternatively, you can use length(), which does the same thing.
But I'm guessing you're trying to reimplement strlen for learning purposes. In that case, there are three problems with your code.
First, you're trying to count the number of characters in the string, and that means you need a pointer to char, not a pointer to std::string. That pointer should also point to constant characters, because you're not trying to modify those characters.
Second, to get a pointer to the string's characters, use its method c_str(). Getting the address of the string just gets you a pointer to the string itself, not its contents. Most importantly, the characters pointed to by c_str() are null terminated, so it is safe to use for your purposes here. Alternatively, use data(), which has been behaving identically to c_str() since C++11.
Finally, counting those characters involves checking if the value pointed to by the pointer is '\0', so you'll need to dereference it in your loop.
Putting all of this together:
const char* string_ptr = text.c_str(); // get the characters
int size = 0;
while (*string_ptr != '\0') { // make sure you dereference the pointer
size++;
string_ptr++;
}
Of course, this assumes the string does not contain what are known as "embedded nulls", which is when there are '\0' characters before the end. std::string can contain such characters and will work correctly. In that case, your function will return a different value from what the string's size() method would, but there's no way around it.
For that reason, you should really just call size().
First things first, the problem is irrelevant. std::string::size() is a O(1) (constant time) operation, as std::string's typically store their size. Even if you need to know the length of a C-style string (aka char*), you can use strlen. (I get that this is an exercise, but I still wanted to warn you.)
Anyway, here you go:
size_t cstrSize(const char* cstr)
{
size_t size(0);
while (*cstr != '\0')
{
++size;
++cstr;
}
return size;
}
You can get the underlying C-style string (which is a pointer to the first character) of a std::string by calling std::string::c_str(). What you did was getting a pointer to the std::string object itself, and dereferencing it would just give you that object back. And yes, you need to dereference it (using the * unary operator). That is why you got an error (which was on the (string_ptr != '\0') btw).
You are totally confused here.
“text” is a std::string, that is an object with a size() method retuning the length of the string.
“string_ptr” is a pointer to a std::string, that is a pointer to an object. Since it is a pointer to an object, you don’t use text.size() to get the length, but string_ptr->size().
So first, no, you can’t compare a pointer with an integer constant, only with NULL or another pointer.
The first time you increase string_ptr it points to the memory after the variable text. At that point using *string_ptr for anything will crash.
Remember: std::string is an object.

How can I convert const char* to string and then back to char*?

I'm just starting c++ and am having difficulty understanding const char*. I'm trying to convert the input in the method to string, and then change the strings to add hyphens where I want and ultimately take that string and convert it back to char* to return. So far when I try this it gives me a bus error 10.
char* getHyphen(const char* input){
string vowels [12] = {"A","E","I","O","U","Y","a","e","i","o","u","y"};
//convert char* to string
string a;
int i = 0;
while(input != '\0'){
a += input[i];
input++;
i++;
}
//convert a string to char*
return NULL;
}
A: The std::string class has a constructor that takes a char const*, so you simply create an instance to do your conversion.
B: Instances of std::string have a c_str() member function that returns a char const* that you can use to convert back to char const*.
auto my_cstr = "Hello"; // A
std::string s(my_cstr); // A
// ... modify 's' ...
auto back_to_cstr = s.c_str(); // B
First of all, you don't need all of that code to construct a std::string from the input. You can just use:
string a(input);
As far as returning a new char*, you can use:
return strdup(a.c_str()); // strdup is a non-standard function but it
// can be easily implemented if necessary.
Make sure to deallocate the returned value.
It will be better to just return a std::string so the users of your function don't have to worry about memory allocation/deallocation.
std::string getHyphen(const char* input){
Don't use char*. Use std::string, like all other here are telling you. This will eliminate all such problems.
However, for the sake of completeness and because you want to understand the background, let's analyse what is going on.
while(input != '\0'){
You probably mean:
while(*input != '\0') {
Your code compares the input pointer itself to \0, i.e. it checks for a null-pointer, which is due to the unfortunate automatic conversion from a \0 char. If you tried to compare with, say, 'x' or 'a', then you would get a compilation error instead of runtime crashes.
You want to dereference the pointer via *input to get to the char pointed to.
a += input[i];
input++;
i++;
This will also not work. You increment the input pointer, yet with [i] you advance even further. For example, if input has been incremented three times, then input[3] will be the 7th character of the original array passed into the function, not the 4th one. This eventually results in undefined behaviour when you leave the bounds of the array. Undefined behaviour can also be the "bus error 10" you mention.
Replace with:
a += *input;
input++;
i++;
(Actually, now that i is not used any longer, you can remove it altogether.)
And let me repeat it once again: Do not use char*. Use std::string.
Change your function declaration from
char* getHyphen(const char* input)
to
auto hyphenated( string const& input )
-> string
and avoid all the problems of conversion to char const* and back.
That said, you can construct a std::string from a char_const* as follows:
string( "Blah" )
and you get back a temporary char const* by using the c_str method.
Do note that the result of c_str is only valid as long as the original string instance exists and is not modified. For example, applying c_str to a local string and returning that result, yields Undefined Behavior and is not a good idea. If you absolutely must return a char* or char const*, allocate an array with new and copy the string data over with strcpy, like this: return strcpy( new char[s.length()+1], s.c_str() ), where the +1 is to accomodate a terminating zero-byte.

access first letter of a string in a set c++

I have a set of strings and I need to access each one and compare the first letter of the string to a char and stop if they are the same. How do I go through that? I tried with
char* p;
for (std::set<string>::iterator iter=myset.begin(); iter!=myset.end();iter++)
{p = *iter;
if (p==characterForComparison) return 0;
}
but that does not pass the compiler, it says
error C2440: '=' : cannot convert from 'std::basic_string<_Elem,_Traits,_Ax>' to 'char *'
How do I solve this? What I need is fairly simple, so I need as simple a solution as I can get, just go through all the strings, compare the first letter, and if they are the same, return 0;
To compare first character of std::string just do:
if (!(*iter).empty() &&
(*iter)[0] == characterForComparison)
{
}
To access first element in a string, string provides operator[], front(), or use begin to get reference to first element. see std::string page.
Since your set contains std::strings, dereferencing the iterator gives you a string, not its first character. Use operator [] instead:
p = (*iter)[0];
*iter is a string, try
char p;
//...
p = (*iter)[0]
You have two problems. The first is that you try to assign a std::string object to a char*. The second is if you want the first character, then p should be declared as a character and not a pointer to a character.
And of course, there's really no need to store the character in a temporary variable like p, at least not in such a simple case such as yours. Use it directly from the string like
if ((*iter)[0] == characterForComparison) { /* do something */ }
if you can use C++11:
for(auto s : myset)
{
if(s[0] == characterForComparison)
{
return 0;
}
}
A C++ string is not convertible to a C-style string. *iter gives you a C++ string.
If you want to actually compare the first character of a string, then.
if ((*iter)[0] == 'a')
would do the trick.
If you actually need a const char *, you can use:
p = iter->c_str();
Note however that this is a CONSTANT string, you shouldn't modify it.
You can also use the STL algorithms.
If you can use C++11:
bool set_condition(const char c, const set<string>& s)
{
auto position =
find_if(s.cbegin(), s.cend(), [c](const string& s) { return s[0] == c; } );
return (position != s.cend() );
}
try to wrap the char in an instance of std:string:
std:string comp(characterForComparison);
and
retrieve the first character with [0]

Conversion from string to char - c++

For a program I'm writing based on specifications, a variable is passed in to a function as a string. I need to set that string to a char variable in order to set another variable. How would I go about doing this?
This is it in the header file:
void setDisplayChar(char displayCharToSet);
this is the function that sets it:
void Entity::setElementData(string elementName, string value){
if(elementName == "name"){
setName(value);
}
else if(elementName == "displayChar"){
// char c;
// c = value.c_str();
setDisplayChar('x');//cant get it to convert :(
}
else if(elementName == "property"){
this->properties.push_back(value);
}
}
Thanks for the help in advanced!
You can get a specific character from a string simply by indexing it. For example, the fifth character of str is str[4] (off by one since the first character is str[0]).
Keep in mind you'll run into problems if the string is shorter than your index thinks it is.
c_str(), as you have in your comments, gives you a char* representation (the whole string as a C "string", more correctly a pointer to the first character) rather than a char.
You could equally index that but there's no point in this particular case.
you just need to use value[0] and that returns the first char.
char c = value[0];

Std::string get assigned by a function returning a char *

Update: for the getValue function I have no control, so is there anything I can do from my side?
I have a kind of dumb question about string and char * basic.
I'm using a function that returns a char * value,
const char *getValue(const char *key)
{
//if key found, and valueString is a string
return valueString.c_str();
//else
return NULL;
}
then I initialized a string to hold the return value,
std::string value = getValue(key);
problem is, whenever the value is not found, which means the function returns NULL, my assignment line will run into an exception. But when there is a legal return value, everything is working fine.
I'm wondering
1. Is this usage totally wrong? means I should never mix char * with string?
2. If not, then when there is a legal pointer returned, does my string automatically make a copy and store it?
3. What is the best way to do this?
Thanks.
First of all, if valueString is local to that function, using the pointer you return will give undefined behavior.
Second, whether returning a null pointer is reasonable will depend on how you use that pointer, of which you've told us nothing.
Unless you absolutely, positively must fiddle with pointers, just return a string and make your life a whole lot easier.
It is not a goot idea to report of occurrence of error (if key not found) by returning NULL. In this case you should generate meaningful exception inside the function. Something like NotFoundEx.
if you have no control over that function, you should wrap it into your safe code:
const char* getSafeValue(const char *key)
{
const char* value = getValue(key);
if(value == NULL)
throw NotFoundEx();
return value;
}
std::string value = getSafeValue(key);
Since you have no control over what the getValue() function does, you need to check the return value for NULL before assigning it to the std::string.
std::string value; // value is an empty string
const char *retVal = NULL;
if( ( retVal = getValue(key) ) != NULL ) {
value.assign( retVal );
}
Since you are working with std::string values anyway, I would just return a std::string instead of a char*:
std::string getValue(const char *key)
{
if (key found)
return valueString;
else
return std::string();
}
You want a std::string with an out of bound value. (char *) might not be the ideal way to do it (see boost::optional for a better way), but it will work (assuming you aren't using a stack-local variable) — if you check for the out of bound value. That is, the problem here is not really mixing (char *) and std::string, it is that you aren't checking for "not found" but blindly assuming something sensible will happen in that case.
Don't assume; determine what you need to do if the key is not found, and check for the NULL (or other out of band, if you choose to use something else).
First question: where does the data come from? You cann't return the
results of c_str() on a local variable; it's undefined behavior, and
you've just been unlucky that it seems to work. If valueString is
just a copy of some more long lasting data, then you can call c_str
directly on it. More generally, however: whatever you return, you'll
have to verify that it is valid before trying to use it. The simplest
solution (but not always possible) is just to use a sentinal value in
the string, e.g.:
std::string
getValue( std::string const& key )
{
// ...
return condition ? valueString : std:;string();
}
for example, using an empty string as the sentinal.
If the semantics of the function don't provide a convenient sentinal
value—for example, if the function can return an empty string as a
valid value—then you'll have to do something else.
If the return value is the result of a lookup in some long
lived container, then you may be able to return a pointer to the element
in the container. In general, however, pointers pose the problem of
what they point to; if you don't have something whose lifetime is
sufficient, then you don't want to use a pointer.
Another possibility is for the caller to provide the default value:
std::string
getValue( std::string const& key, std::string const& ifNotFound )
{
// ...
return condition ? valueString : ifNotFound;
}
This shifts the responsibility of defining the sentinal off to the
callee. In cases like string, there's almost always some value that the
callee can't do anything with, and so can use as a sentinal.
The most general alternative is some sort of Fallible or Maybe
class: a class object which combines a status (typically just a bool)
and an instance of the actual data type. Whether the data are valid or
not depends on the value of the status, so you still have to check that:
Fallible<std::string>
getValue( std::string const& key )
{
// ...
return condition
? Fallible<std::string>( valueString )
: Fallible<std::string>();
}
This often works out well internally as well:
Fallible<std::string>
getValue( std::string const& key )
{
Fallible<std::string> results;
// ...
// At some point, I've got a valid return value, so I do:
results.validate( valueString );
// in a condition, of course...
return results;
}
(Just an example of a frequent and convenient pattern.)