Why is it that below code is always returning the last player in the array?
The operator bool operator > (Player &P) { return Age > P.Age; }seems not to be working properly. I see it as "compare the age of the element in the left object to the age of the element in the right object". Any suggestions?
Note: I don't intend to use std::vector or std::string.
#include <iostream>
using namespace std;
class Player {
int Age;
char *Name;
public:
Player() {}
void setName(char *n) { Name = n; }
void setAge(int a) { Age = a; }
bool operator > (Player &P) { return Age > P.Age; }
void showName(){ cout << Name; }
};
int main()
{
Player *ArrayPlayers = new Player[2];
ArrayPlayers[0].setName("Player1");
ArrayPlayers[0].setAge(27);
ArrayPlayers[1].setName("Player2");
ArrayPlayers[1].setAge(29);
ArrayPlayers[2].setName("Player3");
ArrayPlayers[2].setAge(24);
Player *Oldest = &ArrayPlayers[0];
for (int i = 0; i < 3; i++) {
Player *Current = &ArrayPlayers[i];
if (Current > Oldest) {
Oldest = Current;
}
}
cout << "Oldest player is: ";
Oldest->showName();
getchar();
}
It's because you are comparing pointers (Player*) not Player instances. The simplest fix to achieve the desired result is to dereference:
if (*Current > *Oldest) {
This will invoke your operator> implementation for the Player class.
Related
Quite new to programming and in need of some help, I'm looking to sort an class array in ascending order based on age, but I can only get the code to work in descending order. I may be overlooking something small since I've worked on this far too long so I'd appreciate any help!
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
string name;
int age;
Person(string name = "empty", int age = 0)
{
setName(name);
setAge(age);
}
void setName(string x) {
name = x;
}
string getName() {
return name;
}
void setAge(int y) {
age = y;
}
int getAge() {
return age;
}
void displayinfo()
{
cout << "Name: " << name; cout << " Age: " << age << endl;
}
};
void swap(Person &p, Person &q)
{
Person temp;
temp.name = p.name;
temp.age = p.age;
p.name = q.name;
p.age = q.age;
q.name = temp.name;
q.age = temp.age;
}
int main()
{
int userValue;
Person po("Jessica", 24);
Person po2("Robert", 49);
Person po3("Maria", 47);
Person po4("John", 19);
Person family[4] = {po,po2,po3,po4};
int sort(family[4].getAge());
{
for(int i = 0; i < 3; i++)
if (family[i].getAge() < family[i+1].getAge())
{
swap(family[i], family[i+1]);
}
}
for(int i = 0; i < 4; i++)
family[i].displayinfo();
}
int sort(family[4].getAge()); is not a function declaration (and you can't implement a function inside of another function). It is actually a variable declaration. It is declaring a variable int sort that is initialized with the value from family[4].getAge() (which is undefined behavior since index 4 is out of bounds of your family[] array).
So, you are declaring an unused sort variable, and then you enter your for(int i = 0; i < 3; i++) loop, which DOES NOT perform a full sort of the array. For what you are attempting, use the standard std::sort() algorithm instead, eg:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
class Person
{
public:
string name;
int age;
Person(string name = "empty", int age = 0)
{
setName(name);
setAge(age);
}
void setName(string x) {
name = x;
}
string getName() const {
return name;
}
void setAge(int y) {
age = y;
}
int getAge() const {
return age;
}
void displayinfo() const
{
cout << "Name: " << name; cout << " Age: " << age << endl;
}
};
int main()
{
Person po1("Jessica", 24);
Person po2("Robert", 49);
Person po3("Maria", 47);
Person po4("John", 19);
Person family[4] = {po1, po2, po3, po4};
std::sort(family, family + 4,
[](const Person &p1, const Person &p2) {
return p1.getAge() < p2.getAge();
}
);
for(int i = 0; i < 4; i++) {
family[i].displayinfo();
}
return 0;
}
Live Demo
Note that your family[] array holds copies of the Person objects that you initialize it with. To avoid the overhead of those copies, you can sort pointers instead, eg:
int main()
{
Person po1("Jessica", 24);
Person po2("Robert", 49);
Person po3("Maria", 47);
Person po4("John", 19);
Person* family[4] = {&po1, &po2, &po3, &po4};
std::sort(family, family + 4,
[](const Person *p1, const Person *p2) {
return p1->getAge() < p2->getAge();
}
);
for(int i = 0; i < 4; i++) {
family[i]->displayinfo();
}
return 0;
}
Live Demo
Or, you can get rid of the individual p0... objects altogether and initialize the array directly instead, eg:
int main()
{
Person family[4]{
{"Jessica", 24},
{"Robert", 49},
{"Maria", 47},
{"John", 19}
};
std::sort(family, family + 4,
[](const Person &p1, const Person &p2) {
return p1.getAge() < p2.getAge();
}
);
for(int i = 0; i < 4; i++) {
family[i].displayinfo();
}
return 0;
}
Live Demo
This is my code:
#include<iostream>
#include<string.h>
using namespace std;
class Zichara
{
private:
char *name;
int price;
void copy(const Zichara &from)
{
name = new char[strlen(from.name) + 1];
strcpy(name, from.name);
price = from.price;
}
public:
Zichara(const char *name, int price) {
this->name = new char[strlen(name) + 1];
strcpy(this->name, name);
this->price = price;
}
Zichara(const Zichara &from)
{
copy(from);
}
~Zichara() {
delete [] name;
}
friend class PlaninarskiDom;
};
class PlaninarskiDom {
private:
char name[15];
int prices[2];
char star;
bool isZichara;
Zichara *zich;
void copy(const PlaninarskiDom &from) {
strcpy(name, from.name);
star = from.star;
isZichara = from.isZichara;
zich = from.zich;
for(int i = 0; i < 2; i++) {
prices[i] = from.prices[i];
}
}
public:
PlaninarskiDom(const char *name = "", int prices = 0, const char star = '\0') {
strcpy(this->name, name);
this->star = star;
isZichara = 0;
zich = 0;
this->prices[0] = 0;
this->prices[1] = 0;
}
PlaninarskiDom(const char *name, int *prices, const char star) {
strcpy(this->name, name);
this->star = star;
isZichara = 0;
zich = 0;
this->prices[0] = prices[0];
this->prices[1] = prices[1];
}
PlaninarskiDom(const PlaninarskiDom &from) {
copy(from);
}
~PlaninarskiDom() {
delete [] zich;
}
PlaninarskiDom& operator = (const PlaninarskiDom &from) {
if(this == &from) return *this;
delete [] zich;
copy(from);
return *this;
}
void setZichara(Zichara &z) {
if(isZichara == 0) {
zich->copy(z);
isZichara = 1;
}
}
void operator --() {
if((int)star >= 65 && (int)star <= 70) {
++star;
if((int)star == 69) {
++star;
}
}
}
bool operator <= (char c) {
return star >= c;
}
void presmetajDnevenPrestoj(int day, int month, int &price) {
if(day < 0 || day > 31 || month < 0 || month > 12) {
throw 99;
}
else if(month >= 4 && month <= 8) {
price = prices[0];
}
else {
price = prices[1];
}
if(isZichara) {
price += zich->price;
}
}
friend ostream& operator << (ostream &, const PlaninarskiDom &);
};
ostream& operator << (ostream &os, const PlaninarskiDom &rhs) {
cout << rhs.name << " klasa:" << rhs.star << endl;
if(rhs.isZichara) {
cout << " so zichara" << endl;
}
return os;
}
int main(){
PlaninarskiDom p; //креирање на нов објект од класата планинарски дом
//во следниот дел се вчитуваат информации за планинарскиот дом
char imePlaninarskiDom[15],mestoZichara[30],klasa;
int ceni[12];
int dnevnakartaZichara;
bool daliZichara;
cin>>imePlaninarskiDom;
for (int i=0;i<2;i++) cin>>ceni[i];
cin>>klasa;
cin>>daliZichara;
//во следниот дел се внесуваат информации и за жичарата ако постои
if (daliZichara) {
cin>>mestoZichara>>dnevnakartaZichara;
PlaninarskiDom pom(imePlaninarskiDom,ceni,klasa);
Zichara r(mestoZichara,dnevnakartaZichara);
pom.setZichara(r);
p=pom;
}
else{
PlaninarskiDom *pok=new PlaninarskiDom(imePlaninarskiDom,ceni,klasa);
p=*pok;
}
//се намалува класата на планинарскиот дом за 2
--p;
--p;
int cena;
int den,mesec;
cin>>den>>mesec;
try{
p.presmetajDnevenPrestoj(den,mesec,cena); //тука се користи функцијата presmetajDnevenPrestoj
cout<<"Informacii za PlaninarskiDomot:"<<endl;
cout<<p;
if (p<='D')
cout<<"Planinarskiot dom za koj se vneseni informaciite ima klasa poniska ili ista so D\n";
cout<<"Cenata za "<<den<<"."<<mesec<<" e "<<cena; //се печати цената за дадениот ден и месец
}
catch (int){
cout<<"Mesecot ili denot e greshno vnesen!";
}
}
I ran a debugger on this code and it highlighted this:
name = new char[strlen(from.name) + 1];
This is the line of code as the line where the Seg Fault comes from.
This is an exercise for a class I have and I have to do it using dynamic memory allocation.
I've done this exact same thing many times before and there was no such error, so I have no idea why it is appearing, and I couldn't find an answer to this question on Google so far, so I apologize if somewhere out there it does exist.
Thanks everyone for the suggestions, this has been fixed!
You call this method:
void setZichara(Zichara &z) {
if(isZichara == 0) {
zich->copy(z);
isZichara = 1;
}
}
but you never allocate zich so you invoke UB calling a method on nullptr
Note: your PlaninarskiDom::copy() is incorrect as well, as you just assign pointer from another object aka shallow copy, which will lead to multiple destruction, though most probably you did not hit this issue yet. You should do deep copy instead or use std::shared_ptr is you plan to share ownership. Anyway if you are not limited by conditions using smart pointers are preferable when dealing with dynamically allocated objects. Or using special containers like std::vector or std::string which do proper memory management for you.
I'm currently writing a program that will help a college keep track of which students are in what clubs. This code will be pasted into existing code that works, as provided by my professor.
Could someone please look my code over, and help me work through my mistakes? I included comments to explain what everything should do.
Also, please note this is an assignment and I cannot change anything about the class. I'm also a beginner, so keep it simple, please. Your help will be extremely appreciated beyond all measure.
class Club
{
public:
Club();
Club(Club &c);
Club(string cname);
void addMember(string name);
void removeMember(string name);
string getClubName() const;
string setClubName(const string& nameOfClub);
void loadClub();
bool isMember(string& name) const;
string getAllMembers() const;
friend Club mergeClubs(Club& c1, Club& c2);
~Club();
private:
string *members;
int numMembers;
string clubName;
};
Club::Club()
{
clubName = "";
numMembers = 0;
}
Club::Club(Club &c)
{
numMembers = c.numMembers;
members = new string [numMembers];
for (int i = 0; i < numMembers; i++)
{
members[i] = c.members[i];
}
//copy constructor
//watch out for memory leaks
}
Club::Club(string cname)
{
clubName = cname;
//cname should be saved as the club's name in the clubName variable
}
void Club::addMember(string name)
{
string *m;
m = new string [numMembers];
string *members = m;
for (int i = 0; i < numMembers; i++)
{
for (int j = 0; j < name.length(); i++)
{
m[i] = name[j];
}
}
delete [] m;
//adds new member to the club
//records their name in the members variable
//may need a dynamic array to make this work, watch for memory leaks!
}
void Club::removeMember(string name)
{
string *m;
m = new string [numMembers];
string *members = m;
for (int i = 0; i < numMembers; i++)
{
if ( m[i] == name)
{
m[i] = "";
}
}
delete [] m;
//deletes the person from the array in members
//will do nothing if the person is not in the array to begin with
//may require dynamic array to make this work- watch for memory leaks!
//if the person's name appears more than once, just delete the first instance
}
string Club::getClubName() const
{
return clubName;
//getter of clubName
}
string Club::setClubName(const string& nameOfClub)
{
return clubName = nameOfClub;
//setter of clubName
}
void Club::loadClub()
{
//should print "tell me the name of the next member of the club"
//reads into the variable name
//uses addMember() to add that person to the club
//the input should include up to the line break as the name, so it should take in "jane doe" as an entry
//keeps asking for more names until the user enters a blank entry
string name;
do
{
cout << "Tell me the name of the next member of the club, ";
cout << "or submit a blank entry to stopent ering names." << endl;
getline(cin, name, '\n');
addMember(name);
} while (name != "");
}
bool Club::isMember(string& name) const
{
/*for (int i = 0; i < numMembers; i++)
{
for (int j = 0; j < name.length(); j++)
{
if (members[i] == name)
{
return true;
}
else
{
return false;
}
}
}*/
for (int i = 0; i < numMembers; i++)
{
if (members[i] == name)
{
return true;
}
return false;
}
//returns true if the person is a member of the club, false otherwise
}
string Club::getAllMembers() const
{
for (int i = 0; i < numMembers; i++)
{
return members[i];
cout << ", ";
}
cout << endl;
//returns a string of all the names of the members of the club
//commas and spaces separating every entry of the list
//should not be a comma following the last name in the list
}
Club mergeClubs(Club& c1, Club& c2)
{
//creates a new club from 2 existing clubs
//combined club name should be Club 1/Club 2
Club temp;
temp.clubName = c1.clubName + "/" + c2.clubName;
return temp;
}
Club::~Club()
{
delete [] members;
//destructor
//watch out for memory leaks
}
For some reason I cannot fathom I have (mostly) corrected this program for you. There are still some nasty things like passing copies of strings into const functions but fixing these would be mere optimisations. At least this program is logically correct.
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <sstream>
using namespace std;
class Club
{
public:
Club();
Club(const Club &c);
Club(string cname);
void addMember(string name);
void removeMember(string name);
string getClubName() const;
string setClubName(const string& nameOfClub);
void loadClub();
bool isMember(const string& name) const;
string getAllMembers() const;
friend Club mergeClubs(Club& c1, Club& c2);
~Club();
private:
vector<string> members;
string clubName;
};
Club::Club()
: members()
, clubName()
{
}
Club::Club(const Club &c)
: members(c.members)
, clubName(c.clubName)
{
}
Club::Club(string cname)
: members()
, clubName(cname)
{
}
void Club::addMember(string name)
{
members.push_back(name);
}
void Club::removeMember(string name)
{
members.erase(remove(members.begin(), members.end(), name), members.end());
}
string Club::getClubName() const
{
return clubName;
//getter of clubName
}
string Club::setClubName(const string& nameOfClub)
{
return clubName = nameOfClub;
//setter of clubName
}
void Club::loadClub()
{
//should print "tell me the name of the next member of the club"
//reads into the variable name
//uses addMember() to add that person to the club
//the input should include up to the line break as the name, so it should take in "jane doe" as an entry
//keeps asking for more names until the user enters a blank entry
string name;
do
{
cout << "Tell me the name of the next member of the club, ";
cout << "or submit a blank entry to stopent ering names." << endl;
getline(cin, name, '\n');
addMember(name);
} while (name != "");
}
bool Club::isMember(const string& name) const
{
return find(members.begin(), members.end(), name) != members.end();
}
string Club::getAllMembers() const
{
stringstream result;
vector<string>::const_iterator b = members.begin(), e = members.end();
for (bool comma = false ; b != e; ++b, comma = true)
{
if (comma) {
result << ", ";
}
result << *b;
}
return result.str();
}
Club mergeClubs(Club& c1, Club& c2)
{
Club temp(c1.clubName + "/" + c2.clubName);
struct memberAdd {
Club& _club;
memberAdd(Club& club) : _club(club) {}
void operator()(const string& member) {
_club.addMember(member);
}
};
for_each(c1.members.begin(), c1.members.end(), memberAdd(temp));
for_each(c2.members.begin(), c2.members.end(), memberAdd(temp));
return temp;
}
Club::~Club()
{
//destructor
//watch out for memory leaks
}
int main()
{
Club boys("red");
boys.addMember("Ben");
boys.addMember("Paul");
Club girls("blue");
girls.addMember("Lucy");
girls.addMember("Hermione");
Club unisex = mergeClubs(boys, girls);
cout << unisex.getClubName() << " has the following members: " << unisex.getAllMembers() << endl;
}
Some initial comments:
The copy constructor should take a const Club& like this:
Club(const Club& club)
members and numMembers are anachronistic. Use a std::vector for members and drop the numMembers altogether (std::vector has a size() method).
Club::Club does not initialise members or numMembers. This will result in a possible crash in the destrutor. This would be solved if you replaced them with a vector.
the logic in addMember does not make sense.
nor in removeMember
isMember should take a const string& and you would be well advised to write it in terms of std::find() (#include <algorithm>)
I could go on...
I have a program where I am setting up a closed hash table. In each Element of the Hash table, there is a Student class which holds varies members (name, id, year, etc.). I am simply trying to print out what has been added to my array, but I keep getting a SegFault, and I don't know why. It is only in my print function, though. I have copied the line of code to my other functions or put them in different classes, and they work there, but not when I try to print from my print function. I am at the end of my rope, trying to figure out why I can access the memory location of each member, but not it's actual value.
Here is my program:
main.cpp:
using namespace std;
#include <cstdlib>
#include "hash.h"
int main()
{
string temp1;
string temp2;
string temp3;
string temp4;
string temp5;
string temp6;
Hash h;
do{
cout << "set> ";
cin >> temp1;
//Checking for quit command.
if(temp1.compare("quit") == 0)
{
return 0;
}
//checking for add command.
else if(temp1.compare("add") == 0)
{
cin >> temp2;
cin >> temp3;
cin >> temp4;
cin >> temp5;
cin >> temp6;
Student *s1 = new Student(temp2, temp3, temp4, temp5, temp6);
Element e1(s1);
h.add(e1);
}
//checking for remove command.
else if(temp1.compare("remove") == 0)
{
int r;
cin >> r;
h.remove(r);
}
//checking for print command.
else if(temp1.compare("print") == 0)
{
h.print();
}
//Anything else must be an error.
else
{
cout << endl;
cout << "Error! "<< endl;
}
}while(temp1.compare("quit") != 0);
}
hash.h:
#include <string>
#include <iostream>
#include <cstdlib>
using namespace std;
// Student Class
class Student{
private:
string firstName;
string lastName;
string id;
string year;
string major;
public:
//Constructor
Student(string a, string b, string c, string d, string e);
friend class Element;
friend class Hash;
};
//Element class
class Element{
private:
Student *data;
public:
int getKey();
Student* getData();
void printStudent();
//Constructor
Element(Student *e)
{
data = e;
};
friend class Hash;
};
class Hash{
private:
Element **array;
public:
void add(Element);
void print();
void remove(int);
//Constructor
Hash()
{
array = new Element *[10];
};
friend class Student;
};
hash.cpp:
#include "hash.h"
//The Constructor for Student
Student::Student(string a, string b, string c, string d, string e)
{
firstName = a;
lastName = b;
id = c;
year = d;
major = e;
}
//getKey function for Element Class
int Element::getKey()
{
int key = atoi(getData()->id.c_str());
return key;
}
Student* Element::getData()
{
return data;
}
void Element::printStudent()
{
string c = data->firstName;
cout<< "(" << c << ")";
}
//The add command
void Hash::add(Element e1)
{
int x = e1.getKey()%10;
int i = 0;
if(array[x] == NULL || array[x]->getData() == NULL)
{
array[x] = &e1;
}
else
{while(array[x] != NULL || array[x]->getData() != NULL)
{
x=(x+(i*i))%10;
if(array[x] == NULL || array[x]->getData() == NULL)
{
array[x] = &e1;
break;
}
else
{
i++;
}
}}
}
//The remove command
void Hash::remove(int n)
{
Element e2(NULL);
for(int j = 0; j<10; j++)
{
if(n == array[j]->getKey())
{
array[j] = &e2;
cout << "true" << endl;
break;
}
}
cout << "false" << endl;
}
//The Print command
void Hash::print()
{ int k = 0;
while(k<10)
{
if(array[k] == NULL)
{
cout << "(NULL)";
}
else if(array[k]->getData() == NULL)
{
cout << "(DEL)";
}
else
{
cout << "(" << array[k]->getData()->firstName << ")";
}
k++;
}
cout << endl;
}
Thank you for your help.
You have dangling pointers.
This function gets a temporary copy of an Element, calling it e1.
//The add command
void Hash::add(Element e1)
{
It then stores the address of this local variable.
array[x] = &e1;
And when Hash::add leaves scope, e1 no longer exists.
}
array[x] now points to memory that is no longer Element e1.
The general problem you are facing is that you have designed a Hash class that maintains pointers to objects, but has little control or knowledge regarding when those objects get destroyed.
You will need to personally ensure that objects added to your Hash last at least as long as the Hash does.
Simplest solution for your problem could be to store Element instances in Hash by value not by pointers. So:
class Hash{
private:
Element *array;
public:
void add(Element);
void print();
void remove(int);
//Constructor
Hash()
{
array = new Element[10];
};
friend class Student;
};
Now when you store new element or remove existing you copy them:
array[x] = e1; // not &e1 anymore
This is not very good practice, but at least could change your program in some workable state with minimal changes.
I have built a static stack of structures, and everything works - including creating an array of the structures. However, for some reason I can't set the top of the array to a structure.
In my .cpp file, in my push function, I keep erroring on the following line:
stackArray[top] = newStudent;
The error I am receiving is:
"51: no match for 'operator=' in '(((studentstack)this)->studentstack::stackArray + (+(((unsigned int)((studentstack*)this)->studentstack::top) * 24u))) = ((studentstack*)this)->studentstack::newStudent' "
I am including my code below.
Header file:
#ifndef studentstack_H
#define studentstack_H
#include <iostream>
#include <string>
using namespace std;
class studentstack {
private:
int size; // Stack size
int top; // Top of the Stack
struct student {
int ID;
string Name;
string Address;
double GPA;
};
student * stackArray; // Pointer to the stack
student * newStudent; // Pointer to the new student
public: //Constructor
studentstack(int);
// Copy Constructor
studentstack(const studentstack &);
//Destructor
~studentstack();
//Stack Operaations
void push(string, int, double, string);
void pop(int &);
bool isFull() const;
bool isEmpty() const;
};
#endif
studentstack.cpp
#include <iostream>
#include "studentstack.h"
using namespace std;
studentstack::studentstack(int SIZE) {
stackArray = new student[SIZE];
size = SIZE;
top = -1;
int ID = 0;
double GPA = 0;
}
studentstack::studentstack(const studentstack &obj) {
if (obj.size > 0)
stackArray = new student[obj.size];
else
stackArray = NULL;
size = obj.size;
for (int count = 0; count < size; count++)
stackArray[count] = obj.stackArray[count];
top = obj.top;
}
studentstack::~studentstack() {
delete [] stackArray;
}
void studentstack::push(string name, int id, double gpa, string address) {
if (isFull()) {
cout << "The stack is full.\n";
} else {
top++;
newStudent = new student;
newStudent-> Name = name;
newStudent-> ID = id;
newStudent-> Address = address;
newStudent-> GPA = gpa;
stackArray[top] = newStudent;
}
}
void studentstack::pop(int &id) {
if (isEmpty()) {
cout << "The stack is empty.\n";
} else {
id = stackArray[top].ID;
top--;
}
}
bool studentstack::isFull() const {
bool status;
if (top == size - 1)
status = true;
else
status = false;
return status;
}
bool studentstack::isEmpty() const {
bool status;
if (top == -1)
status = true;
else
status = false;
return status;
}
main.cpp
#include "studentstack.h"
#include <iostream>
#include <string>
using namespace std;
int main() {
string name;
int id, var;
string address;
double gpa;
studentstack s[20];
for(int x =0; x<20; x++) {
cout << "New Student Name: " << endl;
cin >> name;
cout << "ID: " << endl;
cin >> id;
cout << "GPA: " << endl;
cin >> gpa;
cout << "Address: " << endl;
cin >> address;
s.push(name, id, gpa, address)
}
cout << "Popping: "
for(int x = 0; x < 5; x++) {
s.pop(var);
cout <<var;
}
return(0);
}
You might want to cut down the example to a minimal piece of code showing the problem. What it comes down to is that you try to assign a student* to a an element in an array of student objects. A pointer to an object is different to an object:
stackArray[0] = new student(); // does NOT work
stackArray[0] = student();
Note, that object are created in C++ by a constructor and not necessarily involving new. When you construct and object using new you still create an object but you also allocate space for it on the heap. By default, objects are created wherever they are defined. For example, student() creates an object on the stack which is then assigned to an object in the memory of stackArray[0].
Not directly related to your question, but note that your main() cannot work. You declare an array of 20 studentstack elements:
studentstack s[20];
and later on you're doing:
s.push(/* ... */);
s.pop(/* ... */);
That doesn't make much sense. s is not a studentstack. It's an array of studentstacks. Arrays in C++ don't have member functions.