4

I'm new to this C++ environment and I am having difficulty with my constructor. Here is my code:

class Student {
    char name[20];
    long number;
public:
    Student (char nm[20], long val) : 
         name(nm), number(val) {}

When I compile it, it gives me an error saying incompatible types in assignment of char* to char[20].

How can i fix this??

vsoftco
  • 55,410
  • 12
  • 139
  • 252
Ananymus
  • 55
  • 1
  • 1
  • 6

4 Answers4

11

Your constructor argument nm is, actually, not an array! Yes, I know it looks like one, because you wrote char nm[20]. But, actually, it's char* nm. That translation is performed automatically when you write an array type in a function parameter list. Yes, it's stupid. Blame C.

So, the error message is telling you that you cannot assign a pointer to an array. Fair enough. Doesn't really matter anyway, since the language also doesn't let you assign arrays to arrays. Lol.

This is why, since 1998, we've had std::string to fix all these terrible problems:

class Student {
    std::string name;
    long number;
public:
    Student (std::string nm, long val) : 
         name(nm), number(val) {}
};

If you must use an array, you can do this:

class Student {
    std::array<char, 20> name;
    long number;
public:
    Student (std::array<char, 20> nm, long val) : 
         name(nm), number(val) {}
};

because std::array, introduced in 2011, is a handy wrapper around raw arrays that can be assigned (and don't have that weird decay to pointers!).

"Ah, but my teacher told me to use raw arrays," I hear you say. A shame, but we can fix that too. Either accept the array by reference, or take in a pointer to it (as you're doing now! but this drops the dimension 20 from the type and makes things unsafe -.-) and do a manual copy of each element from the source to the destination. Certainly not ideal, but it may be what your teacher is expecting if this is homework:

class Student {
    char name[20];
    long number;
public:
    Student (char (&nm)[20], long val) : 
         number(val)
    {
       assert(sizeof(nm) == sizeof(name));
       std::copy(std::begin(nm), std::end(nm), std::begin(name));
    }
};

class Student {
    char name[20];
    long number;
public:
    Student (char* nm, long val) : 
         number(val)
    {
       // just have to hope that the input is a pointer to **20** elements!
       std::copy(nm, nm+20, name);
    }
};
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

You can't assign to an array.

You can iterate over the array, and copy each item individually - eg. :

Student (char nm[20], long val) : 
     number(val) {
    for (size_t i = 0; i < 20; ++i) {
        name[i] = nm[i];
    }
}

Alternatively (as suggested in a comment by @LogicStuff), you can use std::string :

class Student {
    std::string name;
    long number;
  public:
    Student (const std::string& nm, long val) : 
         name(nm), number(val) {
    }
};
Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
  • 3
    You mean use `std::string`. – LogicStuff Nov 19 '15 at 12:54
  • And even if you could assign arrays, you couldn't assign a _pointer_ to an array, which is what the OP is doing (as `nm`, misleadingly, is not a `char[20]` at all but in fact a `char*`). – Lightness Races in Orbit Nov 19 '15 at 12:54
  • @LightnessRacesinOrbit : that's why I said *to* an array. – Sander De Dycker Nov 19 '15 at 12:56
  • My point is that you did not explain this crucial fact about arrays in C and C++, and how it's going to hold the OP back in this goal. – Lightness Races in Orbit Nov 19 '15 at 13:00
  • @LightnessRacesinOrbit : I guess I don't see the point in explaining impossible scenario's ("even if you could ..."). Otherwise I would also have explained that even if you could assign a pointer to an array, you couldn't figure out the size, and then even if you could figure out the size, you'd really just be passing an array by value, but then you still can't assign *to* an array, so it all comes down to that in the end. Unless you want to take it further : even if you could assign to an array, ... but then we're really off the tracks. – Sander De Dycker Nov 19 '15 at 13:18
0

Arrays passed by value as arguments to a function are implicitly converted to pointers to their first elements.

Thus for example the following constructor declarations are equivalent

Student (char nm[20], long val);
Student (char nm[100], long val);
Student (char nm[], long val);
Student (char *nm, long val);

Arrays have neither the copy constructor nor the copy assignment operator. It means that you may not write like this

Student (char nm[20], long val) : 
     name(nm), number(val) {}
     ^^^^^^^^

You should change the constructor.

First of all it is better then the first parameter is declared with qualifier const. In this case you may pass to the constructor a string literal

The constructor can look the following way

#include <cstring>

//...

Student ( const char nm[20], long val) : number(val) 
{
    std::strncpy( name, nm, 20 );
    name[19] = '\0';
}

In this declaration I used nm[20] only for exposition.

Otherwise you should use standard class std::string instead of the character array.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
-1

In C++ you can think of arrays as simply pointers to their first array-element. Maybe this makes it a bit more clear why you can't assign an array to another since you, thus, try to assign an array to the pointer to an array-element.

Instead of doing so, you can either iterate through the array and copy it value by value or you may use std::memcpy or std::copy to do the job. I'd recommend you to use std::copy.

ZweeBugg
  • 51
  • 5