Changing class object with function c++ - c++

How do I change a class object such as "per.name" using a function? Is prototyping necessary? Function call? Is this passed by value or reference?
#include <iostream>
#include <string>
using namespace std;
class Person {
public:
char* name;
int age;
double weight;
double height;
};
int main()
{
Person per;
per.name = "John"; //change per.name
cout << per.name << endl;
}
I want to change the name John. Is this made as a copy?

char* name; allows you to store a non-const pointer to some character, or NUL-terminated variable-length text. Because it's non-const, the C++ compiler won't let you point it at text that you're not allowed to modify, such as a string literal (your "John").
You would be better off adding...
#include <string>
...atop your file and changing the definition of the name member variable to:
std::string name;
That will then store a copy of any text you assign into the field in the Person object instance.
(Some very old C++ compilers did allow non-const character pointers to be pointed at string literals for compatibility with early C Standards, and current compilers will sometimes still support that if explicitly requested using command line arguments, with any attempt to "write through" the pointer to modify the text typically resulting in a program crash at runtime. If you're using a textbook or reference material that suggested pointing a char* at a string literal, get a better, modern reference.)

Related

C++ Combine strings for 'system' function error

I'm having this c++ error which I can't really understand(I'm new to c++). I think the code should work, but it does not. So I came to ask for help.
Code:
#include <iostream>
#include <cstdlib>
using namespace std;
class Cpy{
public:
string exc;
void cpy(string pyfile){
exc = "python" + pyfile;
system(exc);
}
};
int main(){
Cpy ex;
ex.cpy("example.py");
}
std::system() expects its string in the form of a pointer to a null-terminated array of char. You cannot hand it an std::string directly. You can use the c_str() method of std::string to get a pointer to a null-terminated version of the std::string's contents:
system(exc.c_str());
Also, you most likely forgot to put a space between "python" and your argument.
Apart from that, exc should most likely be a local variable inside your cpy() method rather than a member of the class Cpy.
Instead of passing an std::string object by value I'd consider to rather pass the pyfile argument to cpy() in form of an std::string_view (if your compiler supports C++17) or a plain const char*. Furthermore, if you want to build more complex strings, you might want to consider using an std::ostringstream instead of just concatenating string objects:
void cpy(string_view pyfile)
{
ostringstream cmd;
cmd << "python " << pyfile;
system(exc.str().c_str());
}
For just two strings, it won't matter. But if you want to concatenate many more strings or, e.g., also incorporate numbers and other stuff that needs formatting into your string, using a stringstream would generally seem to be a better idea.

Return a local C-string for function with C++ string return value

The following piece of code compiles and runs without errors and with the expected output:
#include <string>
#include <iostream>
using namespace std;
string getString()
{
char s[] = "Hello world!";
return s;
}
int main()
{
cout << getString() << endl;
}
My question is, will this always work? Ordinarily if you return a C-string that was declared locally you can run into some undefined behavior, but in this case is that still a problem since it is run through the string constructor and (presumably) copied into dynamic memory?
return s;
That line is equivalent to:
return std::string(s);
And that will make a copy of the string, so it's fine.
reference: http://en.cppreference.com/w/cpp/string/basic_string/basic_string (constructor #5)
Constructs the string with the contents initialized with a copy of the null-terminated character string pointed to by s.
Edit: One more detail. You mention
copied into dynamic memory?
And the answer is maybe, perhaps, it doesn't really matter.
The semantics provided by std::string make no specification towards this, it just guarantees that it can be copied/moved around and accessed in a consistent matter. How it acheives this is up to the library implementor.
In fact, popular implementations of std::string use something called the "Small String Optimization". Where strings under a certain length are stored within the string object itself.

Cannot Get C++ Function to Use String from User

Please help.
I have this program from here that calls a function in a header file.
#include <iostream>
#include "md5.h"
#include <string>
using namespace std;
int main(){
string x;
char* v_MD5String;
MD5 md5 ;
v_MD5String = "Hello World";
x = puts(md5.digestString(v_MD5String));
cout << x;
return 0;}
The function called:
char* digestString( char *string ){
Init() ;
Update( (unsigned char*)string, strlen(string) ) ;
Final() ;
return digestChars ;}
The above works, however when I use input from the user it compiles, but the run crashes without any errors.
In the program, this is changed:
v_MD5String = "Hello World";
to this:
cin >> v_MD5String;
What should I do to get this to work?
Thanks.
So, if I understand correctly, you have the following function declared in a header file which you cannot modify:
char* digestString( char *string );
You should first know that this is questionable coding style. The function takes a char * rather than a char const *, which implies that the passed data is changed, yet it also returns something. I had to dig around in the implementation posted on the page you linked to find out that string is really an input parameter, so that the author just forgot about using const and the data is not going to be changed anyway.
(The data not going to be modified is at least my assumption upon superficial code analysis and some compile tests. You should ask the author to be really sure!)
If you use this function in C++, your first task should be to provide a safer, easy-to-understand wrapper function which uses real C++ strings (the std::string class), not C strings (which happen to be completely unencapsulated pointers to characters in memory, which is fine in the C world but not in C++). You already use one std::string in your program. That's good. Now use it more:
std::string SafeDigestString(MD5 &md5, std::string const &input)
{
// the input of digestString will never be modified:
return md5.digestString(const_cast<char *>(input.c_str()));
}
Both the const & and the parameter name make it clear that we are dealing with input.
Note that I used a const_cast<char *> to pass the std::string's C-compatible data representation, which is char const *, to the digestString function. This is one of the rare cases where a const_cast is appropriate; it's also a typical one, namely making up for shortcomings with regards to const declarations in other code you have to use. If all functions in the MD5 class correctly declared their input parameters const, then no const_cast would be needed.
Also note that I just prepend every std identifier with std::, rather than having using namespace std. This is often the better, simpler, more consistent choice.
Now that we have our safe C++ mechanism in place, main becomes drastically simpler:
int main()
{
MD5 md5;
std::string result = SafeDigestString(md5, "Hello World");
std::cout << result << "\n";
}
We have laid the base to implement user input, which is best done with the std::getline function:
int main()
{
MD5 md5;
std::string input;
std::getline(std::cin, input);
std::string result = SafeDigestString(md5, input);
std::cout << result << "\n";
}

Segmentation fault on instationation of more than 1 object

I have a class called "Vertex.hpp" which is as follows:
#include <iostream>
#include "Edge.hpp"
#include <vector>
using namespace std;
/** A class, instances of which are nodes in an HCTree.
*/
class Vertex {
public:
Vertex(char * str){
*name=*str;
}
vector<Vertex*> adjecency_list;
vector<Edge*> edge_weights;
char *name;
};
#endif
When I instantiate an object of type Vector as follows:
Vertex *first_read;
Vertex *second_read;
in.getline(input,256);
str=strtok(input," ");
first_read->name=str;
str=strtok(NULL, " ");
second_read->name=str;
A segmentation fault occurs when more than 1 object of type Vector is instantiated. Why would this occur if more than 1 object is instantiated, and how can i allow multiple objects to be instantiated?
*name=*str;
You cannot dereference a pointer until you first make it point to something.
You probably meant something like:
Vertex(char * str) {
name=strdup(str);
}
But you should really be using std::string.
I think the way how you copy strings is wrong.
*name=*str;
Both name ans str are of type char*. You are dereferencing those pointers. This means you look at the position at the memory where they point and interpret it as char.
When you call it first time something is at location pointed by str and first character of it is copied to random address (as you never initialized name).
Second time you are not so lucky. strtok called on NULL return NULL strtok at cplusplus
Now you tried to work with memorry pointed by null pointer and it is bad.
You need to allocate memory for name and use proper copy function.
name = new char[SomeMaxLenght];
strcpy(name, str);
That's a very C way of doing things, which is incredibly non recommended in modern C++. Remember, C++ should be treated as a different language, not a strict superset of C.
First things first, you should really get a good book by looking at that list, as you seem to be missing many basics.
As for your problem, the main issue is that name is uninitialized, so you run into what is called undefined behavior (i.e. anything can happen; in your case it crashes on the second instantiation). I could go in depth on how to fix it by dynamically allocating memory, but why bother? Just use a std::string:
class Vertex {
std::string name; // string instead of char *
public:
Vertex(const std::string &str) { // pass by const reference
name = str; // I should really use an initializer list there, but oh well
}
// the rest of the class is the same
};
See how that's simpler? Now you don't have to mess around with pointers, which are painful to use. So, in short: use the standard library. And get a good book. Really.

C++: How to build Strings / char*

I'm new to C++. I want to make a char*, but I don't know how.
In Java is it just this:
int player = 0;
int cpu = 0;
String s = "You: " + player + " CPU: " + cpu;
How can I do this? I need a char*.
I'm focusing on pasting the integer after the string.
You almost certainly don't want to deal with char * if you can help it - you need the C++ std::string class:
#include <string>
..
string name = "fred";
or the related stringstream class:
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
int main() {
int player = 0;
int cpu = 0;
ostringstream os;
os << "You: " << player << " CPU: " << cpu;
string s = os.str();
cout << s << endl;
}
if you really need a character pointer (and you haven't said why you think you do), you can get one from a string by using its c_str() member function.
All this should be covered by any introductory C++ text book. If you haven't already bought one, get Accelerated C++. You cannot learn C++ from internet resources alone.
If you're working with C++, just use std::string. If you're working with char*, you probably want to work with C directly. In case of C, you can use the sprintf function:
char* s = // initialized properly
sprintf( s, "You: %d CPU: %d", player, cpu );
Just call s.c_str( );.Here you you can see more.
PS. You can use strcpy to copy the content to new variable and then you will be able to change it.
char * means "pointer to a character".
You can create a pointer to a 'string' like this:
char* myString = "My long string";
Alternatively you can use std::string:
std::string myStdString("Another long string");
const char* myStdString.c_str();
Notice the const at the beginning of the last example. This means you can't change the chars that are pointed to. You can do the same with the first example:
const char* = "My long string";
Consider using stringstreams:
#include <iostream>
#include <sstream>
using namespace std;
int main ()
{
int i = 10;
stringstream t;
t << "test " << i;
cout << t.str();
}
It probably would have been for the best if C++ had overloaded the "+" operator like you show. Sadly, they didn't (you can though, if you want to).
There are basicly three methods for converting integer variables to strings in C++; two inherited from C and one new one for C++.
The itoa() routine. This is actually non-standard, but most compilers have it. The nice thing about it is that it returns a pointer to the string, so it can be used in functional-style programming.
sprintf(). The second holdover from C, this routine takes a destination string, a format string, and a list of parameters. How many parameters there are, and how they are interpreted depend on how the "format" string parses. This makes sprintf both immensely powerful and immensely dangerous. If you use this approach, I can pretty much guarantee you will have crash bugs your first few tries.
std::ostringstream. The C++ way. This has pretty much all the power of sprintf(), but is much safer. The drawback here is that you have to declare it, and it is not a string, so you still have to convert it to one when you are done. That means at least three lines of code are required to do anything with an ostringstream. It is also really ugly, particularly if you try any special formatting.