Passing null string to function as an argument - c++

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”
}

Related

Trouble Understanding How to Pass a String in C++

Could somebody possibly breakdown the proper way to pass a string to a function, have that function put it into a vector and another function print contents of the vector? I'm sure there are tons of duplicates and I have looked at them all(mostly) and still have not been able to apply any of it to this problem, or at least it seems that way to me.
#include <cstdio>
#include <string>
#include <vector>
using namespace std;
static vector<string> added_messages;
static void addMessage(string message);
static void displayMessages();
int main()
{
string message = "Testing 1 2 3";
addMessage(message);
//printf("%s\n", message);
return 0;
}
void addMessage(string s)
{
added_messages.push_back(s);
//printf("%s\n", s);
}
void displayMessages()
{
if (added_messages.size() != 0) {
for (string i : added_messages)
printf("%s\n", i);
}
added_messages.clear();
}
It mostly prints out garbage:4÷/4⌠/
I'm fairly new to C++ and coming from Java, I just can't figure this out. Thanks.
Get in the habit of declaring string parameters as const reference.
Instead of this:
void addMessage(string s)
{
...
}
This:
void addMessage(const string& s)
{
...
}
Not only does this avoid making a copy of the string, it also lets you pass string instances as well as string literals and char* variables that point to strings. That is, the above enables all of the following:
addMessage("Foobar");
const char* psz = <some other string>
addMessage(psz);
std::string s = "A string";
addMessage(s);
And then to print the string correctly with printf, use the .c_str() member function to get the pointer address of the contents.
Instead of this:
printf("%s\n", s);
This:
printf("%s\n", s.c_str());
And it goes without saying that cout is preferred over printf:
cout << s << endl;
Putting it altogether:
static vector<string> added_messages;
static void addMessage(const string& message);
static void displayMessages();
int main()
{
string message = "Testing 1 2 3";
const char* psz = "Yet, another messsage);
addMessage(message);
addMessage("Another Message as a string literal);
addMessage(psz);
// sample printf statements
printf("%s\n", message.c_str());
printf("%s\n", psz);
// sample cout statements - notice it can handle both pointers and string instances
cout << message << endl;
cout << psz << endl;
cout << "Hello World" << endl;
return 0;
}
void addMessage(const string& s)
{
added_messages.push_back(s);
printf("%s\n", s.c_str());
}
void displayMessages()
{
for (const string& i : added_messages)
{
printf("%s\n", i.c_str());
}
added_messages.clear();
}
You can't use printf("%s") on string() object - this is the reason you are having the garbage in the output. "%s" expects C string, ie a pointer to char ended with a zero byte.
If you need to print a string() object, use c_str() method to get a C string representation, ie in your case i.c_str(). C++ is mixing C concepts with C++ concepts, so be aware. Use iostream header and std::cout << i to output your object is a C++ way.
About argument passing. In your example, you are doing it okay, but keep in mind that in your case you are doing it by value, ie a copy of the object is created. More efficient is passing by reference.
This should work:
for(std::size_t i = 0; i < added_messages.size(); i++)
printf("%s\n",added_messages[i].c_str());

setters function inside constructor c++

I'm trying to use a setter function inside of a constructor, which I've never done before. It's giving me the following error:
[Error] no match for call to '(Laptop) (const char [5], const char [3], int, int)'
well do i need to write the setter function too ? i mean outside the constructor ? i mean like this
void Laptop::setBrand(char a[])
{
brand=a;}
I think the error is in the second constructor, that takes four arguments, but I'm not able to find it.
Here is the code:
#include <iostream>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
using namespace std;
class Laptop{
private:
char brand[10];
char processor[10];
int ram;
int hardDrive;
public:
void setBrand(char Bra[]);
void setProcessor(char Pro[]);
void setRam(int Ram);
void setHardDrive(int HDrive);
char *getBrand();
char *getProcessor();
int getRam();
int getHardDrive();
Laptop();
Laptop(char [],char [],int ,int );
};
Laptop::Laptop(){
cout<<"Default constructor called...\n";
strcpy(brand,"None");
strcpy(processor,"None);
ram=0;
hardDrive=0;
}
i think the error is in the constructor
Laptop::Laptop(char Bra[],char Pro[],int Ram,int HDrive)
{
cout<<"Parameterized constructor called...\n";
setBrand(Bra );
setProcessor(Pro );
setRam(Ram);
setHardDrive(HDrive);
}
char *Laptop::getBrand()
{
return brand;
}
char *Laptop::getProcessor()
{
return processor;
}
int Laptop::getRam()
{
return ram;
}
int Laptop::getHardDrive()
{
return hardDrive;
}
int main()
{
Laptop laptopObj1;
Laptop laptopobj1("Dell","i5",4,500);
cout<<"Brand :"<<laptopObj1.getBrand()<<"\n";
cout<<"Processor :"<<laptopObj1.getProcessor()<<"\n";
cout<<"Ram :"<<laptopObj1.getRam()<<"\n";
cout<<"HardDrive :"<<laptopObj1.getHardDrive()<<"\n";
cout<<"Brand :"<<laptopObj2.getBrand()<<"\n";
cout<<"Processor :"<<laptopObj2.getProcessor()<<"\n";
cout<<"Ram :"<<laptopObj2.getRam()<<"\n";
cout<<"HardDrive :"<<laptopObj2.getHardDrive()<<"\n";
}
You have alot of errors here..
Laptop laptopObj1,laptopObj2;
...
laptopObj2("Dell","i5", 4, 500);
You cant use the constructor twice. You used the constructor Laptop() in the first line for both of the object, and then tried to use the second constructor for laptopObj2.
You can change the second line to:
laptopObj2 = Laptop("Dell","i5", 4, 500);
Or even better to define it there:
Laptop laptopObj1;
....
Laptop laptopObj2("Dell","i5", 4, 500);
Another problem is inside your Laptop() constructor definition:
Laptop::Laptop(char Bra[],char Pro[],int Ram,int HDrive)
{
.....
setBrand(Bra []); // Remove the []
setProcessor(Pro []); // Remove the []
....
}
And one more problem: You have no definitions for some functions of the class:
void setBrand(char Bra[]);
void setProcessor(char Pro[]);
void setRam(int Ram);
void setHardDrive(int HDrive);
void display();
EDIT:
One of the objects of c++ is std::string (#include <string>). You can use it instead of char str[]- just simpler way to declare strings in c++. For example, in your case:
/* Replace this: */
char brand[10];
char processor[10];
void setBrand(char Bra[]);
void setProcessor(char Pro[]);
char *getBrand();
char *getProcessor();
/* With this: */
string brand;
string processor;
void setBrand(const string &Bra);
void setProcessor(const string &Pro);
string getBrand();
string getProcessor();
You are passing two const char* as parameter, so you should change this :
Laptop::Laptop(char Bra[],char Pro[],int Ram,int HDrive)
to this:
Laptop::Laptop(const char* ,const char* ,int Ram,int HDrive)
You really should use std::string rather than char[].
On the question of constructors, there is no need to call setters, as the following code demonstrates. C++ has a shortcut for that capability. I have used std::string and fixed all typos.
#include <iostream>
#include <string>
using namespace std;
class Laptop
{
private:
string brand;
string processor;
int ram;
int hardDrive;
public:
void setBrand(string Bra);
void setProcessor(string Pro);
void setRam(int Ram);
void setHardDrive(int HDrive);
string getBrand();
string getProcessor();
int getRam();
int getHardDrive();
Laptop();
Laptop(string, string, int, int);
};
Laptop::Laptop()
: brand("None")
, processor("None")
, ram(0)
, hardDrive(0)
{
cout << "Default constructor called...\n";
}
Laptop::Laptop(string Bra, string Pro, int Ram, int HDrive)
: brand(Bra)
, processor(Pro)
, ram(Ram)
, hardDrive(HDrive)
{
cout << "Parameterized constructor called...\n";
}
string Laptop::getBrand()
{
return brand;
}
string Laptop::getProcessor()
{
return processor;
}
int Laptop::getRam()
{
return ram;
}
int Laptop::getHardDrive()
{
return hardDrive;
}
int main()
{
Laptop laptopObj1;
Laptop laptopObj2("Dell", "i5", 4, 500);
cout << "Brand :" << laptopObj1.getBrand() << "\n";
cout << "Processor :" << laptopObj1.getProcessor() << "\n";
cout << "Ram :" << laptopObj1.getRam() << "\n";
cout << "HardDrive :" << laptopObj1.getHardDrive() << "\n";
cout << "Brand :" << laptopObj2.getBrand() << "\n";
cout << "Processor :" << laptopObj2.getProcessor() << "\n";
cout << "Ram :" << laptopObj2.getRam() << "\n";
cout << "HardDrive :" << laptopObj2.getHardDrive() << "\n";
}
Mike

char "string" not updating in function

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.

Unexpected result while passing struct to a function

I want to pass a struct to function something like below (I know i can pass single member to function like input(int age, string s) but i want to pass whole struct like input(student s) )
#include <iostream>
using namespace std;
struct student
{
string name;
int age;
};
void input(student s)
{
cout << "Enter Name: ";
cin >> s.name;
cout << "Enter age: ";
cin >> s.age;
}
int main(int argc, char *argv[]) {
struct student s1;
input(s1);
cout << "Name is: " << s1.name << endl;
cout << "Age is: " << s1.age << endl;
}
Above code does not produce correct output, I want to use above code with pointer so to get expected output.
Test:If i input name to "abc" and age to 10. It does not get printed in main
Your function makes a local copy of the input. It looks like you need to pass by reference:
void input(student& s) { .... }
// ^
By default, function arguments are passed by value, so this issue is not specific to classes. For example,
void increment_not(int i) { ++i; }
int i = 41;
increment_not(i);
std::cout << i << std::endl; // prints 41
Your function passes student s by value, that's why the variable s1 in main doesn't change.
Change it to pass reference:
void input(student& s)
// ^
You need to pass the struct by reference, rite now you are passing it by copy so whatever changes are made they are on copy of the passed object.
void input(student& s){....}

Concatenate string and variable in function parameter?

This is what I'm trying to do:
showMessage("ERROR: THE MAX IS:" + max);
Basically I want to concatenate a variable (in this case an int) with a string to pass it as a parameter.
How can I do this in C++?
Here's one way:
std::ostringstream msg;
msg << "ERROR: THE MAX IS: " << max;
showMessage(msg.str());
Personally, if you're going that route for displaying something, no need to have the user do extra work:
#include <iostream>
template<typename T>
void showMessage(T &&t) {
std::cout << t << "\n";
}
template<typename Head, typename... Tail>
void showMessage(Head &&head, Tail&&... tail) {
std::cout << head;
showMessage(std::forward<Tail>(tail)...);
}
int main() {
showMessage("value1: ", 5, " and value2: ", 'a');
}
Here's a live example. Any stream should work, including a string stream and file stream. Keep in mind this is very similar to just using a stream and only really worth it if you do other stuff along with displaying it.
A combination of std::string and std::to_string() gives a touch of C++11 goodness:
#include <iostream>
#include <string>
using namespace std;
int main() {
int max = 42;
std::string mess("ERROR: THE MAX IS: ");
mess += std::to_string(max);
std::cout << mess;
}
LIVE EXAMPLE
If you want to use the string as an argument to a function accepting a const char*, you can use std::string::c_str() to get the C-style string of the std::string:
func(mess.c_str());
There isn't a stock C++ way to do this, string literals are that, and they're generally constant. You'll either need to use an overloaded string class or you'll need to make showMessage take arguments and do some kind of formatting for you.
// simple version - take a single string.
void showMessage(const std::string& message) {
// your old code, e.g. MessageBoxA(NULL, message.c_str(), "Message", MB_OK);
}
// complex version, take lots of strings.
void showMessage(std::initializer_list<std::string> args) {
std::string message = "";
for (auto str : args)
message += str;
showMessage(message);
}
int main(int argc, const char* argv[]) {
showMessage("Simple version");
showMessage({ "This program is: ", argv[0], ". Argument count is: ", std::to_string(argc) });
return 0;
}