I'm new to this so I know this is probably something simple.
I have a function like this
void GroceryList::addRecord(char* itemName, char* itemType, char rating){
//do some code;
}
My problem is I am having trouble creating proper arguments to pass to the function.
I've tried something like
void main() {
string itemName;
cin >> itemName;
string itemType;
cin >> itemType;
string rating;
cin >> rating;
gradeBook.addRecord(itemName, itemType, rating);
}
I didn't expect it to work as the function is expecting char* but I can't for the life of me figure out how to get the user input into a variable that I can pass to the function. I've been search for literally 13 hours trying what I can find but no luck so far.
Well, don't use char*.
void GroceryList::addRecord(const std::string& itemName, const std::string& itemType, const std::string& rating) { /* ... */ }
You can get const char* (not char*) from string with c_str() member function, e.g. itemName.c_str(), but unless you're doing interop with C libraries, you don't need that.
Change the function prototype to
void GroceryList::addRecord(string itemName, string itemType, string rating){
//do some code;
}
I also recommend const correctness in your code, if you are not going to change the arguments, pass them by ref with const (for performance)
void GroceryList::addRecord(const string& itemName, const string& itemType, const string& rating){
//do some code;
}
All depends on the actual method body which you didn't describe.
Use std::string::c_str(); that's what it's for:
gradeBook.addRecord(itemName.c_str(), itemType.c_str(), rating.c_str());
This function returns a const char *. However, the addRecord function doesn't seem to be const-correct, so you need to fix that.
You can use string and then when passing just call c_str() on the string. For the rating you can just use a char.
Then calling the function looks like:
gl.addRecord(itemName.c_str(), itemType.c_str(), rating);
For this to work you'll need to change the function signature to const char* instead of char*.
The simple answer is that you can't. If you can modify
GroceryList::addRecord, change it to use std::string const&. If you
can't modify it, then you have to ask the question: why does it use
char*? There are two possible answers: the author didn't understand
const, or was too lazy to use it, and in fact doesn't modify the
pointed to strings. In this case, something like
const_cast<char*>( itemName.c_str() ) can be used; it's wordy, but
that's the price you pay when the code's author doesn't do his job
correctly. The other possible answer is that the code does modify
something through the pointer. In this case, the only solution involves
making a copy of the string into a char[], and passing it.
Related
I have a quick question regarding C++ and references to values. I have been asked to write a function that takes the input from const std::string& and use the input to perform some tasks. The issue is, I have no idea how to access the value. I know it is a pass-by reference value but I don't know how to access it within the function.
This is the code that I was given:
#include "rle.hpp"
std::string func_send(const std::string&)
{
//Implement !
return {};
}
std::string func_receive(const std::string&)
{
// Implement!
return {};
}
The code you were given makes no sense, at least there is no way to acces the parameter because it has no name. Moreover std::string str = std::string&; is invalid syntax, I don't know what it is supposed to mean. Give the parameter a name:
std::string func_send(const std::string& str)
// ^------------ !!!
{
std::string some_other_string = str;
return {}; // missing semi-colon
}
Can I manipulate string in setter? For example I want to set it length to 20. Is it that possible and is it the best practice? I get "Non const function is called on const object". Code tried:
void setName(const string &name) {
if (name.size() > 20)
{
name.reserve(20);
}
Employee::name = name;
}
No, in your example name is a const string reference so you can only use const methods on it (basically meaning you can't modify name). The reserve is not a const method. The const string& name means that name is the same string as the caller supplied, the const means that you may not modify it.
What you could do however is to create a copy of name somehow. The most obvious way is maybe to create a copy inside the method, this means that you can keep the function signature (which may be a good thing IMHO):
void setName(const string &name) {
string tname = name;
if (tname.size() > 20)
{
tname.reserve(20);
}
Employee::name = tname;
}
Another way you could do it is to pass name by value which means that the argument will be a copy of what was supplied by the caller (one could argue that one shouldn't alter the signature of the method to reflect the implementation, but that's a matter of opinion):
void setName(string name) { // note no ampersand
What you can't/shouldn't do is to only remove the const because that would mean that the argument is the same string as the caller supplied. It will fail to compile if the caller don't supply a mutable name and if supplied a mutable name the callers copy would change as well (since it's the same).
It seems to me that you are addressing the problem in the wrong way.
The code posted calls reserve when the size of the string passed is higher then 20, but that is a non-binding request to shrink the string (which is const, BTW).
If you want to limit that string member of your class to a particular size while passing a const reference in a setter, all you have to do is copying into it only a substring of the passed string.
I get "Non const function is called on const object"
Of course. That's the whole point of const in the first place!
if (name.size() > 20)
{
name.reserve(20);
}
This does not make sense at all. It literally says: "If the string has more than 20 characters, then make sure that it can internally hold at least 20 characters".
Now, the call may also have the effect that the string's internal capacity shrinks to whatever size greater than 20 it represents to the outside world. For example, if your string has size 30 and its current capacity is 1000, then reserve(20) may shrink the capacity to 30.
However, this is a low-level memory-management concern a beginner typically doesn't or shouldn't care about. If, what I believe, your intention is merely to cut the string, then you need resize.
I would solve your problem like this, plain and simple:
void setName(std::string const& name)
{
this->name = name;
if (this->name.size() > 20)
{
this->name.resize(20);
}
}
You cannot mutate const references: this means that you will not be able to call std::string::reserve as it's not const-qualified.
Consider taking name by value:
void setName(string name)
{
if (name.size() > 20)
{
name.reserve(20);
}
Employee::name = name;
}
In this case, a copy of the string passed to setName will be made, which can be mutated leaving the original unchanged.
I create a class named Employee, in private, I have a Name as a string . here is my class declaring:
class Employee
{
string Name;
public:
Employee();
void SetName(string);
void StringToEmployee(string);
~Employee();
}
this is definition of StringToEmployee(string) method:
void Employee::StringToEmployee(string s)
{
char *first = s, *end = s+strlen(s), *last = NULL;
last = find(first, end, ',');
string temp(first, last- first);
SetName(temp);
}
The error occurs when I debug to the line string temp(first, last- first), it's seem to the compiler does not allow me to construct a new string in method. cause I have also changed into string temp; then temp.assign(first, last-first). the error still remain. How could I create a new string in a method?
You should be using iterators and taking advantage of the features of the standard library, rather than raw pointers and C-style string functions. Not only will this give you more idiomatic and easier to understand C++ code, but it will also implicitly resolve many of your errors.
First, the implementation of StringToEmployee should be rewritten as follows:
void Employee::StringToEmployee(std::string s)
{
const std::string temp(s.begin(),
std::find(s.begin(), s.end(), ',');
SetName(temp);
}
But since you are not modifying the s parameter and do not need a copy of it, you should pass it by constant reference:
void Employee::StringToEmployee(const std::string& s)
{
const std::string temp(s.begin(),
std::find(s.begin(), s.end(), ',');
SetName(temp);
}
Also, you should consider redesigning your Employee class. Currently, you have a default constructor that creates an invalid Employee object, and then you have member functions that allow you to turn that invalid Employee object into a valid one by settings its members. Instead, you could have a constructor that did all of this initialization for you, in one step. Not only would your code be cleaner and easier to understand, but it would be more efficient, too!
Perhaps something like:
class Employee
{
std::string Name; // name of this employee
public:
Employee(const std::string& name); // create Employee with specified name
void SetName(const std::string& newName); // change this employee's name
~Employee();
};
Employee::Employee(const std::string& name)
: Name(s.begin(), std::find(s.begin(), s.end(), ','))
{ }
void Employee::SetName(const std::string& newName)
{
Name = std::string(s.begin(), std::find(s.begin(), s.end(), ','));
}
Employee::~Employee()
{ }
A couple of quick notes:
You'll see that I always explicitly write out std:: whenever I use a class from the standard library's namespace. This is a really good habit to get into, and it's not really that hard to type an extra 5 characters. It's particularly important because using namespace std; is a really bad habit to get into.
I pass objects (like strings) that I don't need to modify or have a copy of inside of the method by constant reference. This is both easier to reason about, and also potentially more efficient (because it avoids unnecessary copies).
Inside of the constructor, I have used what may appear to be a funny-looking syntax, involving a colon and some parentheses. This is called a member initialization list, and it's something you should get used to seeing. It's the standard way for a class's constructor to initialize its member variables.
For some reason you want to assing std::string to char*.
Judging from other your code, you want to work with raw char array, so, you need to put correct pointers to first and last like this:
char *first = &s[0], *end = (&s[0]) + strlen(s.c_str()), *last = NULL;
And this part:
string temp(first, last- first);
is incorrect, because last - first is pointer, and, as I understand, you want to use std::string(const char*, size_t) constructor. But instead, you are using iterator-based constructor and system is correctly dying, because first pointer is larger, than second one.
As you see, your method is error-prone. I recommend re-do this part of code, using iterators, like this:
void Employee::StringToEmployee(string s)
{
auto found = find(s.begin(), s.end(), ',');
string temp(s.begin(), found);
SetName(temp);
}
I'm writing a password generator that can read and write to a file. I have a function that takes an empty string, then modifies it. The function would look something like this:
void password_create(string *passwd)
Inside that function, I call a write function that writes out to a file with the password, it would look something like this:
void write_out(string file_name, string *passwd)
Then the total code looks like this:
void password_create(string *passwd) {
*passwd = "something";
write_out(&passwd);
}
The compile complains that I can't convert std::basic_string<char>** to std::basic_string<char>*.
I'm relatively new to C++, and this program is just to help me get acquainted with the language. I can pass passwd into the write_out() function without a * or & to denote a pointer or reference just fine. It won't give me an error if I type:
*passwd = "something";
write_out(passwd);
It doesn't affect the overall completion of the program, I was just curious as to why I get that error.
The variable passwd is already a pointer to a std::string, therefore taking the address of it via &passwd will give you something of type std::string** - so if write_out expects a parameter of type std::string* but receives the std::string** then the compiler will give you an error as you saw. So don't use & when passing passwd to write_out():
write_out(passwd);
But all that aside, you should just pass the std::string variables by reference rather than by pointer, as mentioned in the comments and the other answer.
Don't use pointers, in c++ prefer using pass by reference:
void password_create(std::string &passwd) {
passwrd = "something";
...
Then ensure that you create the string as you intend:
std::string myString;
password_create(myString);
That way you will have the memory you expect and you dont need to worry about pointer semantics.
No need to overcomplicate things. I dont see where pointers are needed in this case at all. Just make a function to generate a password and return it.
#include <string>
#include <fstream>
using namespace std;
string password_create() {
return "generated password";
}
void write_password_to_file(string file, string password) {
ofstream stream(file);
stream << password;
stream.close();
}
int main() {
auto password = password_create();
write_password_to_file("pathtofile.txt", password);
return 0;
}
As mentioned in the other answers you should actually take the std::string parameter by reference instead of a pointer.
Well assuming that the write_out() has some signature like
write_out(char* passwd);
or
write_out(const char* passwd);
you can pass std::string::operator[]():
void password_create(string *passwd) {
*passwd = "something";
write_out(&(*passwd)[0]);
}
I am a beginner in C++.I have a function which returns some parameters that i need ,to use in the rest of my program.I am trying to access that function within another class.I am confused with the way i can do it...Can anyone please help me..?
Following is my code :
void SampleProgram :: myFunction()
{
string sInput;
GetInfo getInfo(sInput); //creating instance of the class containing the function
string sSw="";
string sName="ram";
string sList="list";
getInfo.getRequiredInfo(sSw,sName,sList); //calling the function
}
How can i access the output parameters of getRequiredInfo() ..?and save it if the ouput parameters are as following :string name,int status
Please help me...
You'd have to show us the declaration of getRequiredInfo(), but presumably it's something like
X result = getInfo.getRequiredInfo(sSw,sName,sList);
We don't know what X is without seeing that declaration.
In case getRequiredInfo get the address of the strings, try this:
getInfo.getRequiredInfo(&sSw, &sName, &sList);
Now the function can change the value of the arguments.
You can able to return single value in function.
so You can create struct containing string and int and return that as the result.
struct
{
string name;
int k;
}result;
result r = getInfo.getRequiredInfo(sSw,sName,sList); //calling the function
you can save the output parameters like these:
string _name;
int nk;
_name = r.name;
nk = r.k;
The simplest would be return a pair<string,int> from the function. So your function signarutre would be pair<string,int> getRequiredInfo(const string& s1, const string& s2, constr string& s3);. You can then access the string and int part usinf first and second members of the pair.
It sounds as though getRequiredInfo has the behaviour of both reading from and writing to some of the parameters you've passed in.
In C++, unlike in C#, there's no way to specify that a function should, or must, change the value of a given parameter. Indeed, if you have defined your function like this:
void GetInfo::getRequiredInfo(string a, string b, string c);
then all three parameters will be passed by value meaning any changes made to them inside the function will be changing copies of those objects, rather than the objects themselves.
As other contributors have suggested, if you really want to change the parameters you passed in, you could either do so by passing references:
void GetInfo::getRequiredInfo(string a, string& b, string& c);
or (more typically) by passing pointers:
void GetInfo::getRequiredInfo(string a, string* b, string* c);
However, if you want your function to simply read the parameters and return a value (which is the more accepted term for what you're calling 'output parameters') then you have to express your tuple of "name + status" as a single value.
You could use the built in pair template as someone else just suggested:
pair<string,int> getRequiredInfo(string a, string b, string c);
Or you could define your own struct to do it, like someone else suggested:
struct NameAndStatus
{
string name;
int status;
};
NameAndStatus getRequiredInfo(string a, string b, string c);