How do you return a string? - c++

I am trying to return a string from a array with 4 hexadecimal values. I have a huge list of hex arrays and need to use it in multiple functions. That's why I want to create a function of comparing the hex arrays and return a string.
int comparehex(byte hex[]){
char * buffer = new char [16];
byte hex1[4] = {0x4C, 0x79, 0x52, 0xA8};
byte hex2[4] = {0xC5, 0x86, 0xA4, 0xB5};
for (byte i = 0; i <=3; i++){
if (hex1[i] != hex[i]){
break;
}
if (i == 3){
return "string";
}
}
return false;
}
The code that I wrote won't even compile:
main.cpp: In function ‘int comparehex()’:
main.cpp:46:14: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]
46 | return "string";
| ^~~~~~~~
| |
| const char*
How can I return a string?

Function Declaration general rule:
return_type function_name( parameter list );
in your case:
int comparehex(byte hex[])
return_type : int
function_name : comparehex.
parameters : byte array.
As per declaration, function is supposed to return int.
but as per your code
return "string"; // returns a STRING
}
}
return false; // return a boolean
To return a string output, declare the return_type as std::string as in.
to do that you need to include "string" library.
#include <string>
std::string comparehex(byte hex[])
Although the return of boolean is cast to int (implicit type conversion).it is not a good practice and is considered unsafe.
refer to Implicit type conversion in C for more details.

Here is an example of returning const char* with nullptr as a special type of "sentinel value" to mean "false":
There are a lot of potential things to address here, and we don't really understand your purpose of the function or use-case, but let me just address your immediate code and one viable solution.
There are many potential ways to handle this. Again, here is just one. But, I have to make some assumptions to even answer. Let's assume that:
Your function needs to return either a string literal OR false (or something equivalent to represent this).
This means you will NOT be generating a string at run-time inside the function. You will ONLY return a string literal (meaning: a compile-time-constant string with double quotes around it like this: "some string literal") which is set in your source code and fixed at compile-time. Otherwise, my example may not meet your needs, and would need some changes.
You will never need to return true. Rather, the existence of a string indicates true as well.
In this case:
// 1. Change this:
int comparehex(byte hex[])
// to this:
const char* comparehex(byte hex[])
// 2. change this:
return false;
// to this:
return nullptr;
// now this line is fine too:
return "string";
Now, the function returns either nullptr to indicate false, OR a string literal such as "string".
You'd simply check to see if "false" was intended by checking like this:
const char* str = comparehex(some_hex_array);
if (str == nullptr)
{
// `comparehex()` essentially returned `false`, so do what you need to do here
}
else
{
// str was set to some string, so use its value (ex: print it)
printf("%s\n", str);
}
Final notes:
Again, if you're generating a new string inside the function at run-time, rather than returning a string literal set at compile-time, the above 2 changes are not sufficient.
Also note that the above code is rather "C-like". It is perfectly valid C++, but only one of many ways to handle the above scenario.
And lastly, nullptr here can be considered a type of "sentinel value", which means simply that it is a special value of your return type (const char*) to indicate a special meaning: false in this case. And therefore, by extension, this sentinel value of nullptr also possesses the special meaning of whatever you intend "false" to mean.
Related
For another generic example of returning const char*, see my const char * reset_cause_get_name(reset_cause_t reset_cause) function in my answer in C here: STM32 how to get last reset status. I don't return NULL (the C analogue to C++'s nullptr) for cases where no match is found, but I could. (In my example I set it to "TBD" instead of NULL).
See also: What exactly is nullptr?

In your case, you could add another parameter for passing by reference:
int comparehex(byte hex[], std::string& result_string);
In your code, before returning, set the result_string parameter to the string you want to return.

Related

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.

convert bitfield to string C++

I want to convert a bitfield to a string.
Visual Studio 2008 gives an invalid null pointer exception.
Maybe it has something to do with the size of the array. it must be 8 but the output says it is 4, but why?
class Converter
{
public:
string bitfieldToString (bool b_input[])
{
string c_conv;
int i;
for(i = 0; i < sizeof(b_input) ; i++)
{
if(b_input[i]=false){
c_conv.append("0");
}
else if (b_input[i]=true){
c_conv.append("1");
}
else c_conv = "Input is not a bitfield";break;
}
cout<<c_conv<<" "<< sizeof(b_input)<<endl;
return (0);
}
};
int main(void)
{
Converter converter;
bool b2[8] = {0,1,0,0,1,0,1,1};
converter.bitfieldToString(b2);
return (0);
}
Thank you!
Now everything works as intended.
and sorry for that dump question. I am new to C++.
The exception is because you return (0);. That's interpreted as a null pointer, used to initialise a std::string with a constructor which requires a valid pointer to a C-style string - not a null pointer.
That should be return c_conv;
The size mismatch is because b_input isn't an array. As a function parameter, bool b_input[] is a pointer. You can't pass an array to a function by value; and there's no way to determine the array size from the pointer alone. So sizeof(b_input) gives you the size of a pointer, not the array, and everything goes wrong.
There are a few options. You could pass the size as a second parameter; but that's error-prone. You could infer the size as a template argument, by taking the array by reference:
template <size_t size>
string bitfieldToString (bool (&b_input)[size])
You could use std::array or std::vector, which have handy size() member functions. (But be careful with vector<bool>, since it's a special case that doesn't always behave quite like a standard container.) Or you could use std::bitset, which has a handy to_string function that does exactly what you want.
Finally, enable your compiler's warnings - it should tell you not to use = where you mean ==. And there's not much point checking for the case of a boolean being neither true nor false. You can reduce the whole loop body to
c_conv.append(b_input[i] ? '1' : '0');
There is a lot wrong in your code.
First of all, the null pointer exception comes from return (0); at the end of the bitfieldToString fuction. You have defined it to return a string; when you return 0 instead, C++ thinks 0 is a char* pointer and will try to convert it - a NULLpointer - into a string, which will crash. You should probably be returning c_conv instead.
Second, sizeof(b_input) will always be the size of a bool pointer. On a 32-bit system it will be 4, on a 64-bit system 8. You cannot get the length of an array passed as argument with sizeof; you will need to add a length parameter to your function.
Third, inside your for loop, you are assigning to b_input[i] instead of comparing the values. Use ==, not =.
Fourth, in the last else branch, you are missing braces. Essentially, the break will always break out of the loop after the very first iteration.

Annoying C++ gcc warning message

I've written the following program to match regular expressions in C++
#include <regex.h>
#include <iostream>
using namespace std;
/*
* Match string against the extended regular expression in
* pattern, treating errors as no match.
*
* return true for match, false for no match
*/
bool match(const char *string, char *pattern)
{
int status; regex_t re;
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0)
return false;
/* report error */
status = regexec(&re, string, (size_t) 0, NULL, 0);
regfree(&re);
if (status != 0) {
return false; /* report error */
}
return true;
}
int main()
{
string str = "def fadi 100";
bool matchExp = match(str.c_str(), "^[Dd][Ee][Ff][' '\t]+[A-z]+([,])?[''\t]+[0-9]+$");
cout << (matchExp == true ? "Match": "No match") << endl;
}
The program works fine just as expected, but when I compile the code using gcc with the -Wall -Werror arguments (Linux environment), I get a very annoying warning message saying the following:
main.cpp: In function ‘int main()’:
main.cpp:33:90: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
Is there a way to force the compiler to believe that str.c_str() is the same as char * str? if so, how?
No, there isn't. That conversion was deprecated in C++03 and is illegal in C++11; don't do it.
Deprecation of that conversion comes from the fact that string literals are read-only, hence const; accessing them using a pointer to non-const char could possibly lead to modifying const objects, hence invoking undefined behavior. The warning isn't annoying; it is meant to save you from possibly crashing your application - or worse.
Also, you are wrong in reading the warning message; it isn't about c_str(), it is about passing string literal as char *.
The only way to really fix your code is to change second parameter of your match to be const char *, not char *, and copy the passed string to a new, buffer, internal to that function (why not in main()? Because with internal buffer, you have less boilerplate on the caller's side).
I'd also like to suggest totally different solution, since the question is tagged "C++": Boost.Regex.
Is there a way to force the compiler to believe that str.c_str() is the same as char * str?
That's actually not the issue here - you are already passing str.c_str() as a const char*.
The issue is that the second parameter is (also) a string literal, but has type char*. Try changing the second parameter to const char*.
If that still raises errors (due to the regex.h functions not specifying the correct const-ness), you're going to have to do something like this in main() or match():
char pattern[] = "^[Dd][Ee]...etc";
bool matchExp = match(str.c_str(), pattern);
See here for the reason why.
The problem is that a string literal should be only assigned to a pointer of a const char, so you need to change match to take a char const* pattern (which should be possible when you pass a string literal)
Make 2 parameter of function match const char *, warning is because of it

Get first char from std::string

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);

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.)