I have a function which looks like:
void myFunc(char* myString, char* const buf, int startPos){
myString = &buf[startPos];
std::cout << myString << std::endl; //This outputs fine
}
.
.
.
.
char* myString = 0;
.
.
myFunc(myString, buf, startPos);
std::cout << myString << std::endl; //This doesnt output anything
Why doesn't printing out the string work after I have made the function call?
When you call
myFunc(myString, buf, startPos);
myString is copied to the function parameter. Any changes to the pointer myString does not change the pointer myString in main.
Either use char **mystring in function parameter or pass myString by reference.
void myFunc(char&* myString, char* const buf, int startPos){...}
Why not make the function return the value of mystring?
char* myFunc(char* myString, char* const buf, int startPos){
myString = &buf[startPos];
std::cout << myString << std::endl; //This outputs fine
return myString;
}
Then print the value:
std::cout << myFunc(myString, buf, startPos) << std::endl;
Or, you could do:
myString = myFunc(myString, buf, startPos);
std::cout << myString << std::endl;
If you want to modify something in a function, you have to pass a pointer to that "thing"... in this case, your "thing" is a "pointer-to-char" so you need to pass in a "pointer-to-'pointer-to-char'", so:
void myFunc(char** myString, char* const buf, int startPos){
*myString = &buf[startPos];
std::cout << *myString << std::endl; //This outputs fine
}
and call it with:
myFunc(&myString, buf, startPos);
The &myString takes the address of your "pointer-to-char" which will allow the function to modify it; inside the function, you need the extra *s to dereference this address and get to the value you want to change.
Related
So I have a function that takes in a void* which is then casted to uint8* and then populated. In the caller code, it's then appended to std::string. Sort of like in the example below.
But I want to make it generic such that I could store different types into string without hardcoding for specific type in the caller code. For e.g: if I were to store 0x5 in a char array, I'd have to use to_string() as shown below. However if I have to store a char itself, I wouldn't have to use to_string().
void foo(void *p) {
uint8_t *ptr = reinterpret_cast<uint8_t*>(p);
*ptr = 0x5; // for e.g
// now ptr stores a char. th
*ptr = 'C';
}
int main(void) {
char arr[20] = {0};
std::string str;
foo(arr);
for (int i=0; i<20; i++) {
str += to_string(arr[i]);
}
cout << str; //
}
Here's a sample code: https://cplayground.com/?p=jackal-cormorant-koala
you can see how it doesn't print when an integer is stored mainly cause I didn't use to_string(). I'm just looking to have a generic function that stores the value as it is. If 15 is stored in a char array, string stores "15". If 'A' is stored in a char array, string stores "A"
Although comments about serialization are the way to go, if you only want to create a string with char and int you can overload a function.
std::string store(int n) {
return std::to_string(n);
}
std::string store(char c) {
std::string s;
s += c;
return std::string(s);
}
int main(void) {
//char arr[5] = {0};
std::string str = store(15);
cout << "String: " << str << endl;
// ----------------------------------
str += store('A');
cout << "String: " << str << endl;
//populateString(arr);
}
Output:
String: 15
String: 15A
What is the right way of passing NULL string to a function without creating a variable?
I see compilation error with following code and I don't want to change the definition. Also may have to make change to string so don't want to mark it a constant type.
#include <iostream>
#include <string>
using namespace std;
void
myfunc(int i, string &my) {
if (my.empty()) {
cout << "Empty" << endl;
} else {
cout << "String is " << my <<endl;
}
}
int main ()
{
std::string str1 ("Test string");
myfunc(1, str1);
std::string str2 ("");
myfunc(2, "");
return 0;
}`
my1.cpp:18: error: invalid initialization of non-const reference of type ‘std::string&’ from a temporary of type ‘const char*’
my1.cpp:6: error: in passing argument 2 of ‘void myfunc(int, std::string&)
’
Following compiles but I dont want to create local variable
#include <iostream>
#include <string>
using namespace std;
void
myfunc(int i, string &my) {
if (my.empty()) {
cout << "Empty" << endl;
} else {
cout << "String is " << my <<endl;
}
}
int main ()
{
std::string str1 ("Test string");
myfunc(1, str1);
std::string str2 ("");
myfunc(2, str2);
return 0;
}
The solution here is to have an overload that doesn't have the string parameter.
void myfunc(int i, string &my) {
cout << "String is " << my <<endl;
}
void myfunc(int i) {
cout << "Empty" << endl;
}
int main ()
{
std::string str1 ("Test string");
myfunc(1, str1);
myfunc(2);
}
This is the most simple and clear solution that conveys exactly your intent and functionality.
You shouldn't try to do it your way because if you want to modify the argument then the parameter should be "non-const reference" and so it cannot bind to temporaries. Thus you can't pass a string literal to it.
If you want to make it explicit that you don't pass a string, you could create a tag ala nullptr, although I do not recommend the extra complication when the above variant is clear and understood by everybody at first glance.
struct no_string_tag_t {};
constexpr no_string_tag_t no_string_tag;
void myfunc(int i, string &my) {
cout << "String is " << my <<endl;
}
void myfunc(int i, no_string_tag_t) {
cout << "Empty" << endl;
}
int main ()
{
std::string str1 ("Test string");
myfunc(1, str1);
myfunc(2, no_string_tag);
}
If you really want a single function, then the semantically correct version would have an optional reference.
auto foo(int i, std::optional<std::reference_wrapper<std::string>> my)
{
if (my)
cout << "String is " << my <<endl;
else
cout << "no string" << endl;
}
int main ()
{
std::string str1 ("Test string");
myfunc(1, str1);
myfunc(2, std::nullopt);
}
If you want to keep the function signature and still be able to pass it a temporary, then you are out of luck. C++ has a safety feature in that it does not allow a non-const lreferece to bind to a temporary. The reason for this restriction is that attempting to modify a temporary via a lreference would most likely be bug and not the programmers's intent since the temporary dies out anyway.
You can't pass a temporary to a non-const reference parameter. The object, being temporary, will be destroyed as soon as the function returns. Any changes that the function did to the object would be lost.
If you want to have the chance to modify the string, you can take the string by const reference and return a modified string.
string myfunc( int i, string const &s );
:
str1 = myfunc( 1, str1 );
auto result2 = myfunc( 2, "" );
Your other option is to use a pointer to a string that can be null.
void myfunc( int i, string *s ) {
if (!s) {
cout << "Empty" << endl;
} else {
cout << "String is " << *s <<endl;
}
}
myfunc( 1, &str1 );
myfunc( 2, nullptr );
You can ommit 1 or more arguments in functions calls as long those argument(s) are the last ones in the order or the args prototyped in that function.
You can also give a padron value if the argument is ommited when calling the function.
using namespace std;
void sTest(int a, string x ="TEST", int z=0);
void sTest(int a, string x, int z)
{
cout << x;
}
int main()
{
sTest(5); // displayed “TEST”
}
I am trying to return a C string from a function. The function is suppose to concatinate the 3 integers with commas and return the result as a char array however I'm getting garbage values. I'm assuming I'm not calling malloc correctly. Can someone advise on what's the problem?
using namespace std;
const char * createCommand(int p1, int p2, int p3){
stringstream sstm;
std::string comma = ",";
sstm << p1 << comma << p2 << comma << p3;
std::string str = sstm.str();
const char *cstr = (const char *)malloc( (str.length()+1) * sizeof (char));
cstr = str.c_str();
return cstr;
}
int main() {
const char *cstr2 = createCommand(1,0,250); //I want to return "1,0,250"
printf("char = %s\n",cstr2);
}
Since the other two answers already gave responses to the tune of dealing with the literal problem, I'm going to instead advise on what I consider a pretty significant design flaw causing your problem: returning c-strings.
In the example code you're providing, the use of c-strings at all makes no sense. The following code will achieve what you intend to do with no difficulty or problematic code:
std::string createCommand(int p1, int p2, int p3){
std::stringstream sstm;
std::string comma = ",";
sstm << p1 << comma << p2 << comma << p3;
return sstm.str();
}
int main() {
std::string command = createCommand(1,0,250); //I want to return "1,0,250"
std::cout << "char = " << command << "\n";
}
Even if you're confined to using printf instead of the C++ iostreams library, this design is still better:
std::string createCommand(int p1, int p2, int p3){
std::stringstream sstm;
std::string comma = ",";
sstm << p1 << comma << p2 << comma << p3;
return sstm.str();
}
int main() {
std::string command = createCommand(1,0,250); //I want to return "1,0,250"
printf("char = %s\n", command.c_str());
}
And if you need the c-string passed to some older, C-based library, this design will still suffice. The point being, there's no reason to use malloc or interface with the underlying c-string representation except through the string itself.
Assignment operator, which works fine for std::string and other objects, cannot have an override for pointers. Therefore, the assignment
cstr = str.c_str();
leaks the memory that you have allocated, and replaces the pointer with the data from the string. Moreover, the pointer that your function returns now, points into memory that is invalidated upon exiting the function, creating an undefined behavior in addition to a leak.
To fix this problem, call std::strcpy(cstr, str.c_str()); Don't forget to call std::free on the result of the call. Edit: you should remove const from the return type of your createCommand function (WhozCraig, thank you for the comment).
Note: I assume that this is only an exercise in using malloc, that you know that using new[] is preferable, and that you wouldn't have to do any of the above if you could return std::string from the function.
You'll need to copy the string with some form of strcpy, before returning the pointer.
const char * createCommand(int p1, int p2, int p3){
stringstream sstm;
std::string comma = ",";
sstm << p1 << comma << p2 << comma << p3;
std::string str = sstm.str();
const char *cstr = (const char *)malloc( (str.length()+1) * sizeof (char));
strcpy(cstr, str.c_str());
return cstr;
}
So I tried operator overloading of [] and it just doesn't work.
I have created this class:
class String
{
private:
char* str;
public:
String(char* str) // constructor
{
this->str = str;
}
char* Val() // returns value of this.str
{
return this->str;
}
char & operator [](int index) { return this->str[index]; }
};
and I tried to use it like so
String* str = new String("example");
cout << str[2] << endl;
the expected result was a print of the letter 'a' but it won't work..
it does work though when I create an object like so:
String str("example");
cout << str[2] << endl;
any suggestions?
String* str = new String("example");
cout << str[2] << endl;
here str is a pointer, so str[2] is not calling your operator, but accesses the third object in memory from the address str which doesn't exist, thus you have Undefined Behavior.
What you need is:
cout << (*str)[2] << endl;
str is a pointer to a String, so in str[2] the compiler is treating str as an array.
You need to access the object - so deference the pointer. i.e. (*str)[2]
In the first example str is a pointer to a String object.
You need to dereference it first, and then call the operator.
I have a piece of code as follows:
char* foo(char* str1)
{
str1 = "Some other text";
cout << "String Inside Function::" << str1 << endl;
return str1;
}
int main()
{
char* str = "This is a string";
cout << "String Before Function call::" << str << endl;
foo(str);
cout<<"String After Function call::"<<str<<endl;
return EXIT_SUCCESS;
}
But the cout after my function call gives me "This is a string" even though I have changed it in my foo function. I'm confused here although I know it has got something to do with me not passing the correct address.
You are changing the pointers value and not what it points to.
// Adding & (aka pass by reference) after the char* you can modify the pointer that you passed into foo function
// but you must understand that it was another place in memory!!!
void foo(char*& str1)
{
// This string saved in global section and here you
// changed not the text in the str1 but the pointer itself
str1 = "Some other text";
cout << "String Inside Function::" << str1 << endl;
}
// Another way to change pointer itself is pass a pointer to the pointer
void foo_v2(char** str1)
{
// You should dereference pointer to pointer (* before str1)
*str1 = "Some other text";
}
// In this case you change the content at the pointer str1
// It very dangerous, you can replace content not only the memory under str1
// but even return address if string placed in stack memory.
// Such terrible things occurred if your string that copied into str1
// occupied more bytes then it can be contained in str1
// More safe way is using for example std::string
void foo2(char* str1)
{
char *s = "Some other text";
strcpy(str1, s, strlen(s));
}
int main()
{
char* str = "This is a string";
cout << "String Before Function call::" << str << endl;
foo(str);
cout<<"String After Function call::"<<str<<endl;
return EXIT_SUCCESS;
}
When you pass a pointer by copy, the function you call gets a copy of that pointer, just as passing by copy of any other type means you can't modify the original, passing by pointer works in the same way.
void f(char* copy)
{
// the copy here is modified to point to test
copy = "Test";
}
void g(char* copy)
{
g[0] = 'C';
}
int main()
{
char* p = nullptr;
// f gets a copy of p, p cannot be modified by f
f(p);
char p2[5] = "copy";
// g gets a copy of p2, the value of p2 (the pointer) cannot be modified by g
// however, g can modify what p2 points to
g(p2);
// prints "Copy" (not "copy")
cout << p2;
}
If you want to change what a pointer "points to" via a function, you have to do that in the same way that you would change any other type passed to a function. Either through a pointer (double pointer in this case) or reference (preferred).
void make_c(char** c)
{
*c = new char[10];
}
void make_c(char*& c)
{
c = new char[10];
}
int main()
{
char* t = nullptr;
// via pointer (double pointer in this case)
make_c(&t);
delete [] t;
// via reference
make_c(t);
delete [] t;
}