0

I'm continuing my studies for uni with C++ and I'm running into some serious comprehension issues concerning pointers, const arguments and all the very basics of class implementations (which are so easy in Java compared to C++)

I usually work with Java, so C++ is very new to me.

This is my simple header for a class "Person":

#ifndef Person_h
#define Person_h

class Person
{
private:
    char* name;
    char* adress; 
    char* phone;

public:
    Person();
    Person(char const *name, char const *adress, char const *phone);
    Person(const Person &other);
    ~Person();

    void setName(char const *name);
    char* getName() const;
    void setAdress(char const *adress);
    char* getAdress() const;
    void setPhone(char const *phone);
    char* getPhone() const;
};

#endif // !Person_h

And here the problem starts. Why should I use char pointers instead of actual char variables? I'm guessing it's some conventions to spare memory or to improve performance?

This is the way our professor codes and tries to make us understand the use of pointer and const etc.

Now here's my implementation of the class:

#include "Person.h"
//Person.h class implementation

Person::Person()
{
    Person::name = new (char[64]);
    Person::adress = new (char[64]);
    Person::phone = new (char[64]);
}

Person::Person(const char *name, const char *adress , const char *phone)
{
    Person::name = new (char[64]);
    Person::adress = new (char[64]);
    Person::phone = new (char[64]);

    setName(name);
    setAdress(adress);
    setPhone(phone);
};

Person::Person(Person const &other)
{
    Person::name = new (char[64]);
    Person::adress = new (char[64]);
    Person::phone = new (char[64]);

    setName(other.getName);
    setAdress(other.getAdress);
    setPhone(other.getPhone);
};

Person::~Person()
{
    delete [] name;
    delete [] adress;
    delete [] phone;
};

void Person::setName(const char *name)
{
    this->name = name;
};

char* Person::getName() const
{
    return name;
};

void Person::setAdress(char const *adress)
{
    this->adress = adress;
};

char* Person::getAdress() const
{
    return adress;
};

void Person::setPhone(char const *phone)
{
    this->phone = phone;
};

char* Person::getPhone() const
{
    return phone;
};

We should learn to manually allocate memory to elements and try to take care of the overall memory management. Therefore the use of const arguments for the setter functions. I guess this is in order to not alter the element argument? I'm very confused, basically...

And my IDE (MS VisualStudio 2015) underlines the following line as error:

void Person::setName(const char *name)
{
    this->name = name;    //error
};

"a value of type 'const char *' cannot be assigned to an entity of type 'char *'"

Then why should I use const when I can't assign these values? Or how can I "un-const" those, without making the member variable itself const?

This whole matter is just one big confusion to me now.

EDIT: I have to use C-strings for my exams, that's in order to understand pointer and memory management referring to our prof.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
GenerationLost
  • 179
  • 1
  • 1
  • 15
  • 2
    > Why should I use char pointers instead of actual char variables? < You shouldn't, there is `std::string` for that. – myaut Jul 20 '17 at 10:44
  • 2
    You ought to use `std::string` to hold string data, rather than bare pointers. Seems to me like you need a good C++ book. – Bathsheba Jul 20 '17 at 10:44
  • 2
    When assigning C-style strings, you don't use `=` but `strcpy` to copy the string value. – Bo Persson Jul 20 '17 at 10:44
  • 2
    In C and C++ pointers can be used to pass a single variable or an array of variables. However the pointer itself contains no information on whether it contains an address of a single item or an address of first item inside of array. So you need to figure it out from context. In your case `name` is assumed to be a pointer to null-terminated array of chars (that is C-style string). – user7860670 Jul 20 '17 at 10:47
  • @BoPersson thanks, now I get it... so this is all C related. Was wondering about the absence of String in C++ but we use C aspects like C-style string to get a better understanding of "behind the hood"-actions. – GenerationLost Jul 20 '17 at 10:51
  • Another problem with your code is name collision between function parameters and class fields. The common workaround for this is to prefix class fields with `m_`. And the assignment `this->m_name = name;` won't work anyway because assignment of a pointer to a const to a pointer to non-const violates const-correctness and therefore is prohibited. – user7860670 Jul 20 '17 at 10:51
  • @myaut @Bathsheba gotta get along with C string 'cause this is all exam related, but for future studie of C++ I'll use `std::string` then, thanks – GenerationLost Jul 20 '17 at 10:53
  • @VTT in Java you avoid these collisions with the `this`-pointer, isn't this the same in C++? – GenerationLost Jul 20 '17 at 10:55
  • `char*` in c++ is just a useless layer of pointers, just use `std::string` – Vivick Jul 20 '17 at 10:58
  • @Vivick sorry, gotta use C-Strings bc it's important for my exams, edited my entry post – GenerationLost Jul 20 '17 at 11:04
  • Try reading a [good C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – Passer By Jul 20 '17 at 11:10
  • _that's in order to understand pointer and memory management referring to our prof_ Then he should have taught you to implement a string class and use it. –  Jul 20 '17 at 11:13
  • To some extent, yes. However it is easy to forget to type `this->` and mess up things. – user7860670 Jul 20 '17 at 11:28

3 Answers3

3

In layman's terms, the reason why this->name = name; does not work when name is const and this->name is non-const, is because your function is promising that the contents of name will be treated as read-only, but by assigning this pointer to a non-const pointer you would then be free to modify the data as you please, thus breaking your promise.

Your teacher is obviously trying to teach you old-style C++ with pointers, (essentially, object-oriented C,) so you should not go ahead and replace char pointers with strings. Your teacher will probably be unhappy if you do that.

There is a number of reasons why we use char* instead of char[].

  • One reason is efficiency: if it was possible to pass a char[], then the entire contents of that char[] would need to be copied to the stack. When you pass a char*, you are only copying the pointer to the characters, which is usually a single machine word.

  • Another reason is that it is actually impossible. The compiler has no built-in knowledge of the fact that your char[] is zero-terminated so as to allocate enough stack space for it and copy it to the stack. The creators of the language preferred to not put such built-in knowledge in the language. Instead, they decided that a char[] should be implicitly converted to char*, so that from within your function you can receive it as a char* and do what you want with it.

  • Another reason is that if your char[] was just a bit too large, then your stack would overflow.

So, for all these reasons, when we want to pass values of types that are larger (or considerably larger) than machine words, we do not pass the values themselves, we pass pointers or references to them.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
2

Doing e.g.

this->name = name;

is problematic for two reasons: First of all because of you trying to assign a variable of one type to a variable of a closely related but still different type. But that's not the big problem.

The big problem is that you attempt to reassign the original pointer this->name (which points to some memory you have allocated) with another pointer (which points somewhere else).

The result is similar to

int a = 5;
int b = 10;
a = b;

and then wondering why a is no longer equal to 5.

There are two solutions here: The first one is keep using pointers and then copy the string instead of assigning pointers. This is done with the std::strcpy function.

The solution I recommend though, is to stop using pointers for strings and instead use the standard C++ std::string class. Then you can use simple assignment to copy strings. They also handle their own memory, so you don't have to worry about memory leaks, pointers, freeing invalid pointers or keeping track of the actual size of the strings.

The std::string class of C++ shares some similarities with the Java String class, so if you come from a Java background it should not be hard for you to adjust. The biggest different is that in C++ using std::string you actually can compare strings directly with ==.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Gotta use C-strings for my exams for better understanding, that's why we don't use the standard C++ String, but thanks for the explanation, now I get the real problem with the pointer assignment. – GenerationLost Jul 20 '17 at 11:01
1

In modern C++ you should be still aware of memory management, but for the sake of readability, exception safety and bugs you should use containters, which do the work for you, as std::string.

const char *name means, that you have a pointer, which points to a memory section, which itself is const, which means, that the data inside this memory section shouldn't change.

The pointer itself can change.

When you assign

this->name = name;

you are just assigning a pointer this->name to the pointer of name. But this you can do only when the pointer are of convertible type. If you change the type of this->name from char* to type const char*, the compiler shouldn't complain.

But before you assign there anything new, you should clean up the memory, e.g. delete[] this->name

PatrickF
  • 594
  • 2
  • 11