Why the number of grades is 0? - c++

#include<iostream>
#include<string>
using namespace std;
class Student {
public:
const int codeStud;
int noGrades = 0;
int* grades = NULL;
Student(int code) :codeStud(code) {
}
Student(int code, int* grades, int noGrades) :codeStud(code) {
this->noGrades = noGrades;
this->grades = new int[noGrades];
for (int i = 0; i < noGrades; i++)
this->grades[i] = grades[i];
}
Student(const Student&existent):codeStud(existent.codeStud) {
this->noGrades = existent.noGrades;
this->grades = new int[this->noGrades];
for (int i = 0; i < this->noGrades; i++)
this->grades[i] = existent.grades[i];
}
int getCode() {
return this->codeStud;
}
int getNoGrades() {
return this->noGrades;
}
void setGrades(int grades[],int noGrades) {
this->noGrades = noGrades;
this->grades = new int[noGrades];
for (int i = 0; i < noGrades; i++)
this->grades[i] = grades[i];
}
};
void main() {
Student s1(101);
cout<<s1.getNoGrades();
int grades[] = { 10,7,8,10,4 };
Student s2(104, grades, 5);
cout << "\n" << s2.getNoGrades();
Student s3 = s2;
cout << "\n" << s3.getCode();
int grades2[] = { 5,5,4,10 };
s1.setGrades(grades2,4);
cout << "\n" << s1.getNoGrades(); // here is the problem
}
After I changed the grades for student 1 it shows that he has 0 grades, when the output should be 4, the number of these grades: 5,5,4,10.
The rest of output is correct, even when I want to know the number of grades for student 1, which is 0 , and then for student 2, which is 5.

I've changed some things in your code to compile it
#include<iostream>
#include<string>
using namespace std;
class Student {
public:
int codeStud;
int noGrades = 0;
int* grades = NULL;
Student(int code) {
codeStud = code;
}
Student(int code, int* grades, int noGrades) {
this->noGrades = noGrades;
this->grades = new int[noGrades];
for (int i = 0; i < noGrades; i++)
this->grades[i] = grades[i];
}
Student(const Student&existent){
this->noGrades = existent.noGrades;
this->grades = new int[this->noGrades];
for (int i = 0; i < this->noGrades; i++)
this->grades[i] = existent.grades[i];
}
int getCode() {
return this->codeStud;
}
int getNoGrades() {
return this->noGrades;
}
void setGrades(int grades[],int noGrades) {
this->noGrades = noGrades;
this->grades = new int[noGrades];
for (int i = 0; i < noGrades; i++)
this->grades[i] = grades[i];
}
};
int main() {
Student s1(101);
cout<<s1.getNoGrades();
int grades[] = { 10,7,8,10,4 };
Student s2(104, grades, 5);
cout << "\n" << s2.getNoGrades();
Student s3 = s2;
int grades2[] = { 5,5,4,10 };
s1.setGrades(grades2,4);
cout << "\n" << s1.getNoGrades(); // here is the problem
}
and output is:
0
5
4
what is correct, because you don't assign number of grades of s1 anywhere in your code before first printing
Also look for:
https://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c
why void main() is not correct

After I corrected the typo (codStud --> codeStud) your code produced the correct results for me. Before I did that I couldn't even compile it, so my guess would be that your IDE just run the latest working version of it that could be compiled successfully (look for error messages somewhere). That's the reason you got the wrong result, because your changes weren't even in that version.
A couple of note about your code:
In your setGrades function check that grades not pointing to something already. For example, if I call Student(int code, int* grades, int noGrades) and after I call setGrades your code leaks memory because it loses the array that Student(int code, int* grades, int noGrades) allocated before.
You should use vector instead of C-style arrays. It will make your code much more cleaner and less error-prone (see my example).
You could make your getter functions to const (like in my example), so it would be guaranteed that those functions don't change the value of any member of the class (you get a compile error if they do). Other than that, you can make the member variables to private.
Implementation using vectors:
#include <iostream> // cout
#include <vector> // vector
using namespace std;
class Student
{
public:
Student(const int code)
: m_code{code}
{
}
Student(const int code, const std::vector<int>& grades)
: m_code{code},
m_grades{grades}
{
}
// Default copy constructor is sufficient because the class can be copied
// memberwise.
int getCode() const {
return m_code;
}
int getNoGrades() const {
return m_grades.size();
}
void setGrades(const std::vector<int>& grades) {
m_grades = grades;
}
private:
const int m_code;
std::vector<int> m_grades;
};
int main()
{
Student s1(101);
cout << s1.getNoGrades();
Student s2(104, {10, 7, 8, 10, 4});
cout << "\n" << s2.getNoGrades();
Student s3 = s2;
cout << "\n" << s3.getCode();
s1.setGrades({5, 5, 4, 10});
cout << "\n" << s1.getNoGrades();
return 0;
}

Related

Create Multiple Objects in a loop c++

I'm a beginner and was researching to find out if you can grab a name from an array to then put that name as the name of the object in a for loop.
The code a specifically created for this question is represented below:
#include <iostream>
using namespace std;
class YourMum{
public:
string name;
YourMum(string aName){
name = aName;
}
};
int main()
{
string names[5] = {"Jeremy_Clarkson", "Boris_Johnson", "Vladmir_Putin", "Peter_Griffin", "MeAndYourMum"};
for(int i = 0; i < 4; i++) {
YourMum names[i];
cout << names[i].name << endl;
cout << "You are great if you answer my question!";
}
return 0;
}
Okay, it's not clear what you're trying to do, but you've got a few things that aren't a good idea.
First, you defined string names[5] and then inside loop you hid names by making a second variable with the same name. While that's legal, it's a bad practice.
Second, you're using the second one (YourMum names) illegally:
You declared it as length i (using a non-standard feature of the compiler) but then reference element i. The elements of an array of length i range from 0..i-1, so [i] is one element past the end.
And you haven't initialized it anyway.
I'm not really clear what you're trying to do, so I can't even provide example code of how to do it.
The YourMum class you have shown is not default constructible, so YourMum names[size]; will not work. Every object of YourMum needs to be passed a parameter in order to create it. You can use placement-new for that, eg:
#include <iostream>
#include <type_traits>
using namespace std;
class YourMum{
public:
string name;
YourMum(string aName){
name = aName;
}
};
int main()
{
string names[5] = {"Jeremy_Clarkson", "Boris_Johnson", "Vladmir_Putin", "Peter_Griffin", "MeAndYourMum"};
std::aligned_storage<sizeof(YourMum), alignof(YourMum)>::type arr[5];
YourMum *mums = reinterpret_cast<YourMum*>(arr);
for(int i = 0; i < 5; i++) {
new (&mums[i]) YourMum(names[i]);
}
for(int i = 0; i < 5; i++) {
cout << mums[i].name << endl;
cout << "You are great if you answer my question!";
}
for(int i = 0; i < 5; i++) {
mums[i].~YourMum();
}
return 0;
}
Or, you can use std::vector instead:
#include <iostream>
#include <vector>
using namespace std;
class YourMum{
public:
string name;
YourMum(string aName){
name = aName;
}
};
int main()
{
string names[5] = {"Jeremy_Clarkson", "Boris_Johnson", "Vladmir_Putin", "Peter_Griffin", "MeAndYourMum"};
std::vector<YourMum> mums;
mums.reserve(5);
for(int i = 0; i < 5; i++) {
mums.emplace_back(names[i]);
}
for(int i = 0; i < 5; i++) {
cout << mums[i].name << endl;
cout << "You are great if you answer my question!";
}
return 0;
}
First of all, you should rename the name variable to something like _name or name_ for lisibility (to differenciate it from variables that aren't in the class), and you should also use the private section of your class to declare it and use getters/setters functions to edit it. Secondly, in your code you are declaring the object inside a loop, so it will get destroyed as soon as the loop iterates again, so if you want to create n objects in a loop and interact with them after you should either use a container class (like std::vector) or use a default constructor (which is better). Here is an updated version of your code:
#include <iostream>
#include <string>
class YourMum
{
public:
YourMum(void) : _name() { }
YourMum(std::string name) : _name(name) { }
std::string getName(void) const { return _name; }
void setName(std::string name) { _name = name; }
private:
std::string _name;
};
int main()
{
std::string names[5] = { "Jeremy_Clarkson", "Boris_Johnson", "Vladmir_Putin", "Peter_Griffin", "MeAndYourMum" };
YourMum mums[5];
for (int i = 0; i < 5; i++)
{
mums[i].setName(names[i]);
std::cout << mums[i].getName() << std::endl
<< "You are great if you answer my question!" << std::endl;
}
// this way you can still access mums here if you want to
return 0;
}
If you want to access to a class by it's name as index what you can also do is using std::map like this
#include <map>
int main()
{
std::string names[5] = { "Jeremy_Clarkson", "Boris_Johnson", "Vladmir_Putin", "Peter_Griffin", "MeAndYourMum" };
std::map <std::string, YourMum> mums;
for (int i = 0; i < 5; i++)
mums[names[i]] = YourMum(names[i]);
std::cout << mums["Jeremy_Clarkson"].getName() << std::endl;
return 0;
}
Try This
> for(int i = 0; i < 4; i++) {
> YourMum name(names[i]);
>
> cout << name.name << endl;
> cout << "You are great if you answer my question!";
> }

How to pass parameters in an objects of array? in c++

class A
{
int id;
public:
A (int i) { id = i; }
void show() { cout << id << endl; }
};
int main()
{
A a[2];
a[0].show();
a[1].show();
return 0;
}
I get an error since there is no default constructor.However thats not my question.Is there a way that ı can send parameters when defining
A a[2];
A good practice is to declare your constructor explicit (unless it defines a conversion), especially if you have only one parameter. Than, you can create new objects and add them to your array, like this :
#include <iostream>
#include <string>
class A {
int id;
public:
explicit A (int i) { id = i; }
void show() { std::cout << id << std::endl; }
};
int main() {
A first(3);
A second(4);
A a[2] = {first, second};
a[0].show();
a[1].show();
return 0;
}
However, a better way is to use vectors (say in a week you want 4 objects in your array, or n object according to an input). You can do it like this:
#include <iostream>
#include <string>
#include <vector>
class A {
int id;
public:
explicit A (int i) { id = i; }
void show() { std::cout << id << std::endl; }
};
int main() {
std::vector<A> a;
int n = 0;
std::cin >> n;
for (int i = 0; i < n; i++) {
A temp(i); // or any other number you want your objects to initiate them.
a.push_back(temp);
a[i].show();
}
return 0;
}

problem passing array of struct to a function throwing undefined reference c++

I'm having issues with passing an array of structures to a function that searches them. I delcare an array of structs outside of main then copy it to a new array of structs inside of main (so I have access to them inside main and can pass them easier). Not sure why it is failing though. Can anyone help me?
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <algorithm>
using namespace std;
const int MAX = 2000000;
const string DFile = "DFile.dms";
const string EFile = "EFile.dms";
const string VFile = "VFile.dms";
struct dogs
{
int did;
int age;
} DFBuffer[MAX];
struct examine
{
int vid;
int did;
int fee;
} EFBuffer[MAX];
struct vet
{
int vid;
int eLevel;
} VFBuffer[MAX];
void readDF(ifstream&);
void readEF(ifstream&);
void readVF(ifstream&);
int getLineCount(ifstream&);
bool dogCompare(dogs lhs, dogs rhs) {return lhs.did < rhs.did;}
bool vetCompare(vet lhs, vet rhs) {return lhs.vid < rhs.vid;}
bool examCompare(examine lhs, examine rhs) {return lhs.vid < rhs.vid;}
void vetExamSeach(struct vet newVetArray[], struct examine newExamArray[],
int, int);
int main()
{
dogs * newDogArray = new dogs[MAX];
examine * newExamArray = new examine[MAX];
vet * newVetArray = new vet[MAX];
ifstream DF, EF, VF;
int dogCount = 0, examCount = 0, vetCount = 0;
DF.open(DFile);
readDF(DF);
EF.open(EFile);
readEF(EF);
VF.open(VFile);
readVF(VF);
DF.open(DFile);
dogCount = getLineCount(DF);
EF.open(EFile);
examCount = getLineCount(EF);
VF.open(VFile);
vetCount = getLineCount(VF);
for(int i = 0; i < dogCount; i++)
newDogArray[i] = DFBuffer[i];
for(int i = 0; i < vetCount; i++)
newVetArray[i] = VFBuffer[i];
for(int i = 0; i < examCount; i++)
newExamArray[i] = EFBuffer[i];
cout << "Sorting...\n";
sort(newDogArray, newDogArray + dogCount, dogCompare);
sort(newExamArray, newExamArray + examCount, examCompare);
sort(newVetArray, newVetArray + vetCount, vetCompare);
cout << "Sorting complete!\n";
vetExamSeach(newVetArray, newExamArray, vetCount, examCount);
return 0;
}
here is the search function. for the sake of this question, im just trying to print what i pass it.
void search(vet newVetArray[], examine newExamArray[], int vCount, int eCount)
{
for(int i = 1; i < vCount; i++)
cout << "in search: " << newVetArray[i].vid << ' ' << newVetArray[i].eLevel << endl;
}
here is the error I'm getting
Here is my files. Not asking you to do my HW just help me solve my issue
When, I run your code, I get the same compilation error of undefined reference for readDf, readEF, readVF, getLineCount and vetExamSeach.
The error is because there is no definition of these functions. There are only just decalarations. When I define them (something random) the errors are gone.
So, define the function(s) and the error(s) would be gone.

C++ - Segmentation fault when returning a string

I have this class
#include "Room.h"
#include "Book.h"
#include <cstdlib>
#include <iostream>
static int book_counter = 100;
//Constructors
Book::Book() {
for(int i = 0; i < 13; i++) {
this->customer_name += 97 + rand() % 26;
}
this->arrival = rand() % 30;
this->duration = 1 + (rand() % 10);
this->ppl = 1 + rand() % 5;
this->room = nullptr;
this->book_code = book_counter++;
}
Book::Book(std::string nm, int arr, int dur, int ppl) {
this->customer_name = nm;
this->arrival = arr;
this->duration = dur;
this->ppl = ppl;
this->room = nullptr;
this->book_code = book_counter++;
}
//Methods
int Book::getArr() {
return arrival;
}
int Book::getDur() {
return duration;
}
int Book::getPpl() {
return ppl;
}
void Book::anathesi(Room* x) {
this->room = x;
}
int Book::getBookCode() {
return book_code;
}
Room* Book::getRoom() {
return room;
}
std::string Book::getCustomerName() {
return customer_name;
}
which includes a string getter method getCustomerName().
When I call this method on main, via an instance created via the first constructor, everything works fine. On the other hand, if the instance is created via the second constructor, the method will cause a segmentation fault.
It seems like customer_name has an infinite length, thus causing a segmentation fault when I try to return it.
The method is called in main with this line of code:
cout << hotel.getBooks(i)->getBookCode() << " " << hotel.getBooks(i)->getCustomerName()
<< " " << hotel.getBooks(i)->getRoom()->getRoomCode() << "\n";
I am new into C++, so please elaborate my fault as much as needed.
The header file for class Book:
#ifndef PROJECT_BOOK_H
#define PROJECT_BOOK_H
#include <string>
class Room;
class Book {
protected:
std::string customer_name;
int book_code;
int arrival;
int duration;
int ppl;
Room* room;
public:
Book();
Book(std::string nm, int arr, int dur, int ppl);
void anathesi(Room* x);
int getArr();
int getDur();
int getPpl();
int getBookCode();
std::string getCustomerName();
Room* getRoom();
};
#endif //PROJECT_BOOK_H
In Hotel.h:
private: std::vector<Book*> books;
public: Book* getBooks(int i);
In Hotel.cpp:
Book* Hotel::getBooks(int i) {
return books[i];
}
Found the problem and fixed it.
I was creating instances with this piece of code:
Book obj(onoma, afiksh - 1, meres, arithmos);
which caused the segmentation I said.
I changed this to:
Book *obj = new Book(onoma, afiksh - 1, meres, arithmos);
and fixed the problem. Thanks for your time and help.
Unfortunately, I don't really know why this works, but it does, everything functions properly. Therefore I guess I'll have to look at new documentation.

how do i create an array where each element in the array, of size 10, is pointing to an object, in C++?

for example lets have a class or struct name Employee with two constructors, a default constructor and a constructor with parameters two strings and an int. why doesn't the following code work?
Employee *employees = (employee*) malloc(sizeof(Employee)*10);
let's say we have an array, size 10, of type string for first name, last name, and one of type int for salary. how to initialize the data members of each object class using the constructor with the parameters?
for (int i = 0; i < 10; i++)
{
employees[i] = employee(firstname[i], lastname[i], salary[i]);
}
I've been trying to do this for a few days now but wasn't successful. Also, can anyone tell how to do this using c++'s new and delete operator? and also is there a way this can be done using vectors?
Thank you
header file
class employee{
std::string firstname;
std::string lastname;
int salary;
public:
employee(std::string, std::string , int);
employee();
void setFirst(std::string);
void setLast(std::string);
void setSalary(int);
std::string getFirst();
std::string getLast();
int getSalary();
};
employee::employee(std::string x, std::string y, int z)
{
setFirst(x);
setLast(y);
setSalary(z);
}
void employee::setFirst(std::string x)
{
firstname = x;
}
void employee::setLast(std::string y)
{
lastname = y;
}
void employee::setSalary(int z)
{
salary = z > 0 ? z : 0;
}
std::string employee::getFirst()
{
return firstname;
}
std::string employee::getLast()
{
return lastname;
}
int employee::getSalary()
{
return salary;
}
.cpp file
#define MAX 20
using namespace std;
int main(int argc, char* argv[])
{
int n = 1;
cout << "number of employees: ";
cin >> n;
string firstname[MAX];
string lastname[MAX];
double salary[MAX];
float raise[MAX];
for (int i = 0; i < n; i++)
{
cout << "Employee " << i + 1 <<endl;
cout << "-----------\n";
cout << "First Name: ";
cin >> firstname[i];
cout << "Last Name: ";
cin >> lastname[i];
cout << "Monthly Salary: ";
cin >> salary[i];
salary[i] *= 12;
cout <<"Yearly percentage raise (e.g 10% or 0%): ";
scanf("%f%%", &raise[i]);
salary[i] *= (((raise[i])/100.00) + 1);
puts("\n");
}
employee *employees = (employee*) malloc(sizeof(employee)*10);
for (int i = 0; i < n; i++)
{
employees[i] = employee(firstname[i], lastname[i], salary[i]);
}
cout << "TESING USING GET FUNCTIONS" << endl;
cout << "---------------------------\n\n";
for (int i = 0; i < n; i++)
{
cout << "Employee " <<i +1<< endl;
cout <<"-----------\n";
printf("First Name: %s", employees[i].getFirst().c_str());
printf("\nLast Name: %s",employees[i].getLast().c_str());
printf("\nYearly Salary: %d\n\n", employees[i].getSalary());
}
}
If you have an array of Employee instances and Employee is not POD (http://en.wikipedia.org/wiki/POD) you need to allocate memory from the stack using the operator new:
Employee* employees = new Employee[10];
And for having this working:
for (int i = 0; i < 10; i++)
{
employees[i] = Employee(firstname[i], lastname[i], age[i]);
}
you need to implement the operator= in your Employee class:
Employee& operator=(const Employee& src)
{
_firstname = src._firstname;
_lastname = src._lastname;
_age = src._age;
return *this;
}
If this looks like your Employee class:
class Employee
{
std::string first_name;
std::string last_name;
// other members and functions ...
};
Then using malloc() to create 10 of these is a complete and utter failure. The reason why is that yes, you allocated memory using malloc(), but that's all you did. You didn't construct 10 Employee objects. Those std::string members need to be constructed, not merely have memory allocated. So with that call to malloc() you have 10 fake Employees that were "created", and as soon as you attempt to do anything with one of them, then boom goes your program.
Do research on POD and non-POD types. You cannot treat non-POD types (as the class above is non-POD) as you would a POD type. For a non-POD type, the instance must be "officially" constructed, (the constructor must be invoked).
On the other hand, malloc() knows nothing concerning C++ and what is required to create an object correctly via construction. All malloc (and calloc, and realloc) knows is to allocate bytes and return a pointer to the allocated space.
Use a vector instead, it's resizable, it's easier to manage, and as Grady stated in his comment, it's also generally not good practice to use malloc in C++ code (although it's possible). Maybe do something that looks like this:
#include <vector>
...
int size = 10;
std::vector<Employee *> employees;
for(int i = 0; i < size; i++)
{
//as far as pulling in your data, that depends on where it's coming from
Employee *temp = new Employee(...);
employees.push_back(temp);
}
I'm rusty on my C++ but this should work.
Try this way:
#include <iostream>
class Employee
{
std::string m_firstname;
std::string m_lastname;
int m_age;
public:
Employee()
{
m_firstname=m_lastname="";
m_age=0;
}
void setFirstName(std::string firstname)
{
m_firstname=firstname;
}
void setLastName(std::string lastname)
{
m_lastname=lastname;
}
void setAge(int age)
{
m_age=age;
}
void displayEmp()
{
std::cout<<m_firstname;
std::cout<<m_lastname;
std::cout<<m_age;
}
};
int main()
{
std::string fname;
std::string lname;
int age;
Employee *employee = new Employee[10];
Employee *employeeptr=employee;
for(int i=0;i<10;i++)
{
std::cin>>fname;
std::cin>>lname;
std::cin>>age;
employeeptr->setFirstName(fname);
employeeptr->setLastName(lname);
employeeptr->setAge(age);
employeeptr++;
}
employeeptr=employee;
for(int i=0;i<10;i++)
{
employeeptr->displayEmp();
employeeptr++;
}
delete []employee;
return 0;
}