Most of the code below deals with the raw pointer.

#include <iostream>  // cout, endl
#include <cstring>   // strlen, strcpy
#include "Student.h" // Student class

Student::Student(const char * login, int age, int year, float GPA)
{
  login_ = 0;
  set_login(login);
  set_age(age);
  set_year(year);
  set_GPA(GPA);
}

Student::~Student()
{
  delete [] login_;
}


// Private copy method
void Student::copy_data(const Student& rhs)
{
  set_login(rhs.login_);
  set_age(rhs.age_);
  set_year(rhs.year_);
  set_GPA(rhs.GPA_);
}

Student::Student(const Student& student) : login(0)
{
  copy_data(student);
}

Student& Student::operator=(const Student& rhs)
{
    // Check for self-assignment
  if (&rhs != this)
    copy_data(rhs);

  return *this;
}

void Student::set_login(const char* login)
{
  delete [] login_;
  
  int len = std::strlen(login);
  login_ = new char[len + 1]; 
  std::strcpy(login_, login);
}

void Student::set_age(int age)
{
  if ( (age < 18) || (age > 100) )
  {
    std::cout << "Error in age range!\n";
    age_ = 18;
  }
  else
    age_ = age;
}

void Student::set_year(int year)
{
  if ( (year < 1) || (year > 4) )
  {
    std::cout << "Error in year range!\n";
    year_ = 1;
  }
  else
    year_ = year;
}

void Student::set_GPA(float GPA)
{
  if ( (GPA < 0.0) || (GPA > 4.0) )
  {
    std::cout << "Error in GPA range!\n";
    GPA_ = 0.0;
  }
  else
    GPA_ = GPA;
}

void Student::display() const
{
  using std::cout;
  using std::endl;

  cout << "login: " << login_ << endl;
  cout << "  age: " << age_ << endl;
  cout << " year: " << year_ << endl;
  cout << "  GPA: " << GPA_ << endl;

}

int Student::get_age() const
{
  return age_;
}

int Student::get_year() const
{
  return year_;
}

float Student::get_GPA() const
{
  return GPA_;
}

const char *Student::get_login() const
{
  return login_;
}