C++ , Student Class with set and get functions - c++

I've tried to write a class for a student information(name,IDno,and degree), this information will be printed on the screen; but I don't know where is the errors?!
#include <iostream>
#include <conio.h>
using namespace std;
class Student {
private:
char name;
int idnumber;
char degree;
public:
Student(char,int,char);
void setName(char n){name = n;}
int getName(){return name;}
void setIdnumber(char id){idnumber = id;}
int getIdnumber(){return idnumber;}
void setDegree(char d){degree = d;}
int getDegree(){return degree;}
};
Student::Student(char n,int id,char d){
name = n;
idnumber = id;
degree = d;
}
int main(){
Student s1, s2;
s1.setName(Sara);
s1.setIdnumber(333);
s1.setDegree(A);
s2.setName(Jack);
s2.setIdnumber(222);
s2.setDegree(B);
cout << "name: " << s1.getName() << ",IDnumber: " << s1.getIdnumber() << ",Degree: " << s1.getDegree() << endl;
cout << "name: " << s2.getName() << ",IDnumber: " << s2.getIdnumber() << ",Degree: " << s2.getDegree() << endl;
getch();
return 0;
}

Apparently, you have the following issues:
Student s1, s2;
This will try to call the default constructor. However, you defined a constructor that takes 3 parameters, which inhibits the compiler to generate a default constructor for you, so you will fail to create those objects, which effectively makes your follow up member function calls fail.
s1.setName(Sara);
setName takes char type as parameter type, if you mean string literal "Sara", then you will have trouble. Similar issues can be found in other function calls. You should fix this.
Meanwhile, you should prefer to use member initialization list instead of using assignment in constructor body to initialize your members.
Student::Student(char n,int id,char d): name(n), idnumber(id), degree(d){}
make sure that your members are declared in order of name, idnumber, degree.

char is a single character, not a string. try using std::string instead.
also, to declare a string literal, surround your string in quotes ""
eg:
s1.setName("Sara");
also, to use std::string, you will need to #include <string>

There are few problems with your code
char name;
name here is just a char literal so it will only store one literal while you are trying to pass string Sara to it. So change name to array or pointer
char name[10] or char *name
Also while passing name pass it with double quotes like "Sara". Change all the formal arguments in the functions to char array or pointer.
Student s1, s2;
Here while creating objects s1 and s2 it will call default constructor, which you have not provided, So include default constructor in your code
Student(){}
s1.setDegree(A);
Here you are trying to pass a literal not a variable so quote it
s1.setDegree('A');
C++ provides string datatype which is much easy to use wrt to char or char[], so use it. You can operate upon it like you use other datatype like int, double.
That will avoid your hassle to specify array length, using strcpy() to copy strings.
string name;

Related

C++ memcpy/strcpy of char pointer to class member char pointer

i have a custom class, let's call it "Student" and a main method. I'm instanciating the class, and just want to output the content of the class.
My programm crashes with a: Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
Actual Code
Student.h
#ifndef PROG2_STUDENT_H
#define PROG2_STUDENT_H
#include <iostream>
class Student
{
private:
char *name;
char *firstName;
unsigned matriculationNumber;
unsigned semester;
public:
Student(char *name, char *firstName, unsigned matriculationNumber, unsigned semester);
~Student();
friend std::ostream &operator<<(std::ostream &ostream, const Student &student);
private:
};
#endif
Student.cpp
#include <cstring>
#include "Student.h"
Student::Student(char *name, char *firstName, unsigned matriculationNumber, unsigned semester)
{
std::strcpy(this->name, name);
std::strcpy(this->firstName, firstName);
this->matriculationNumber = matriculationNumber;
this->semester = semester;
}
Student::~Student()
{
delete[] this->name;
delete[] this->firstName;
}
std::ostream &operator<<(std::ostream &stream, const Student &input)
{
stream << input.name << ", " << input.firstName << ": "
<< input.semester << " Semester, MA " << input.matriculationNumber;
return stream;
}
and my main
#include <iostream>
#include "StudentPackage/Collection/StudentCollection.h"
int main()
{
Student studentOne((char *)"Testerson", (char *)"Test", 12345, 2);
std::cout << studentOne << std::endl;
return 0;
}
What i have tried
I have tried several things, including memcpy. But with memcpy I'm not able to detect the size of the char array correctly.
When i change the Student Constructor to the following, i get problems with the delete/free in the destructor. I guess, this isn't the correct way anyway, but this is happening, because the scope of the input variables are destroyed before the class destructor is called, correct?
Student::Student(char *name, char *firstName, unsigned matriculationNumber, unsigned semester)
{
this->name = name;
this->firstName = firstName;
this->matriculationNumber = matriculationNumber;
this->semester = semester;
}
Question
How can i correctly copy the char array from constructor (name to this->name)?
How can i correctly copy the char array from constructor (firstName to this->firstName)?
std::strcpy does not allocate memory. So your program is copying input to a "garbage" address that is occurred in the memory area where your Student object is placed. And as result no surprise that you are getting segment violation as result. There are two solutions:
a "C-style" way - allocate memory manually (i.e. like auto n = std::strlen(name); this->name = new char[n + 1]; std::strcpy(this->name, name);), but then you need to delete it manually (i.e. delete name;) in the destructor. btw, n + 1 because you also need room for the null-terminator, strlen result does not include it.
much better and more "C++" way - use std::string (i.e. declate name member variable as std::string). Then you just can do an asignment: this->name = name;, and no need manual memory management - std::string will take care.
(Code style) Also recommend to use some prefix or postfix for member variables, i.e. like m_name(more "Microsoft" style), or name_ - more "Google" style, to avoid those unnecessary this->.

Strange output printing char array

human header
class human
{
char name[];
public:
void setName(char nameValue[]);
char* getName();
}
human cpp
void human::setName(char nameValue[])
{
char name[] = "walter";
}
char* human::getName()
{
return name;
}
main cpp
int main()
{
human myHuman;
char name[] = "walter";
myHuman.setName(name);
char* result3 = myHuman.getName();
cout << "My human has a name of " << result3 << endl;
return 0;
}
I assign the string "walter" but when I print it I get "╠╠╠╠╦ß╩d└²╒".
I don't understand which part is wrong. Can you tell me what's wrong with my code?
First and foremost you are assigning nameValue to a variable local to the function setName, which means that the class variable name is still unitialized when you return it in getName, hence the strange output.
The char name[]; declaration is also incorrect, C++ does not allow for variable length arrays or arrays with unspecified bounds unless they are immediately initialized in which case the size will be deduced given the size of the assigned string.
On that note, warnings must have been issued by your compiler, if not, crank them up, or better yet, make it treat warnings as errors, you'll have more robust code.
For the purpose of your assignment you should just go ahead and use pointers, a small problem arises because C++ does not allow for assignment of string literals to char* variables, this is easily fixed if you use const char*, your compiler may allow the former but it is illegal as per C++ rules.
Applying the corrections above, your code should look more like this:
class human
{
const char* name;
public:
void setName(const char *nameValue);
const char* getName();
};
void human::setName(const char *nameValue)
{
name = nameValue;
}
const char* human::getName(){
return name;
}
int main()
{
human myHuman;
const char* name = "walter";
myHuman.setName(name);
const char* result3 = myHuman.getName();
cout << "My human has a name of " << result3 << endl;
return EXIT_SUCCESS;
}

(C++ OOP) Why name[] is not changing when I assign its pointer to a new value?

I am new to C++ OOP concepts and I come from a Java OOP background. I have tried this->name=name but I get an error and then I tried to use a pointer, but, even though the code runs, it does not 'save' the name in the object's name.
#include <iostream>
using namespace std;
class Person{
private:
char name[];
int age;
public:
Person(char name[], int age){
char* pName=this->name;
pName=name;
this->age=age;
cout<<this->name;
}
getInformation(){
cout<<"name: "<<this->name<<" age: "<<this->age;
}
};
int main(){
Person foo("foo",5);
}
In C++, arrays usually need to be declared with a length - in this case, char name[] would be invalid.
Additionally, arrays declared int array[5] (with a size) cannot be directly assigned to. i.e. this is invalid:
class A
{
public:
int array[5];
void foo() {
int other_array[5] = {0, 0, 0, 0, 0};
this->array = other_array;
}
}
Instead, you need to assign each element one at a time (e.g. in a loop):
for(int i = 0; i < 5; ++i) this->array[i] = other_array[i];
This is because in C++ arrays have space for all the elements, unlike Java where char name[] is a pointer to an array. If you want to be able to directly change what array a variable refers to, you should use a pointer instead - a pointer can be dereferenced like an array:
class A
{
public:
int *array;
int foo(int *other_array) {
this->array = other_array;
}
}
Though if you do this, be careful of memory management.
Ignoring (for the moment) the fact that the code is invalid and won't compile; here:
char* pName=this->name;
You instantiate a local pointer and assign the unitialised pointer name to it. Then you immediately reassign it with a pointer to the parameter name:
pName=name;
But both pName and name are temporary and are pointers to strings, not the strings themselves. Moreover pName is not a reference to this->name. So on return from the Person() constructor, the object remains unchanged (and uninitialised). You may have intended:
char*& pName = this->name ;
pName = name ;
But that is simply a convoluted form of:
this->name = name ;
and is still ill advised because you are then assigning this->name with the address of the literal string "foo" from main() which is const. In any case you are giving Person a pointer to data that belongs to something else and is not "owned" by Person, and Person has no knowledge of the data's lifetime or validity. It is recipe for all kinds of bugs and undesired behaviour.
Null-terminated (or ASCIZ or C-style) strings are not a true data type; it is merely a char array convention. Moreover arrays even are not first-class data types in C++ and you cannot assign one array to another or pass an array by value as a function argument - instead assignment and argument passing are pointer operations. In Person(), name is a pointer to the first character in the string constant "foo" not an independent string containing "foo".
To correct this using C-style strings:
#include <iostream>
#include <cstring>
class Person
{
private:
char name[256]; // << Must have size here.
int age;
public:
Person( const char* name, int age) // << Must have const arg for "foo" to be a valid parameter.
{
std::strncpy( this->name, // << C strings must be explicitly copied, not "assigned".
name,
sizeof(this->age) - 1 ) ;
this->age = age;
}
void getInformation() const // << must have return type, and may be const.
{
std::cout << "name: " << this->name << " age: " << this->age << "\n" ;
}
} ;
However in most cases it would be preferable to use C++ std::string objects:
#include <iostream>
#include <string> // << Use C++ string library
// (i.e. string rather than cstring/string.h)
class Person
{
private:
std::string name; // << std::string memory management is intrinsic
int age;
public:
Person( const std::string name, int age)
{
this->name = name ; // << Assignment possible due to
// operator overloading
this->age = age;
}
void getInformation() const
{
std::cout << "name: " << this->name << " age: " << this->age << "\n" ;
}
} ;
As said above, std::string is to recommend for now.
Not only for this problem, std::string is very nice to work with in many cases. especially in the learningface.
Just take a look at the string class here from MS' site:
https://learn.microsoft.com/en-us/cpp/standard-library/basic-string-class?view=vs-2019
If you're using c++, it's way better to use std::string to deal with strings.
But answring to your question, when you assign a value to any variable, it overrides its previous value and gets a new one.
In your code:
char* pName=this->name;
pName=name;
The first line assigns a new value to your pName variable. and the second line, simply overrides your first line, and copies something new into your pName variable. so, that's not a correct approach for what you want to do.
If you want to have a char * variable and copy content of another char * into it, I suggest something like:
private:
char *name;
...
public:
Person(char name[], int age){
this->name = strdup(name);
...
}
And be careful to free memory of name in your destructor function.

getting error on compiling small C++ program

when i compile the program i get an error about int when i create a bookClass object using the 2 argument constructor. the error has somerthing to do with the integer argument parsed to the constructor. the program is:
#include <iostream>
#include <string>
using namespace std;
class bookClass{
private:
string bookName;
int bookNumber;
public:
void setName(string c){
bookName=c;
}
void setNumber(int d){
bookNumber=d;
}
string getName(){
return bookName;
}
int getNumber(){
return bookNumber;
}
bookClass(string a, int b){
bookName=a;
bookNumber=b;
}
};
int main()
{
int numberr;
string name;
cout << "Enter the book name: ";
cin >> name;
cout << "\nEnter the book number: ";
cin >> numberr;
bookClass book=new bookClass(name, numberr);
cout << "\n\nThe book " << book.getName() << " has book number " <<
book.getNumber() << endl;
return 0;
}
Compiling your code I didn't get the error you suggested. However, there is an issue with this line:
bookClass book = new bookClass(name, numberr);
C++ is not Java. new returns a pointer to memory dynamically allocated for the given class.
What you want is just:
bookClass book (name, numberr);
The problem with your code is simple. I suppose you were programming in Java or C# before C++. In C++ we call new operator only if we want to create an object explicitely on heap (and get a pointer to it).
bookClass* book=new bookClass(name, numberr);
However, now you are in troubles because you are calling book.getName() where book is of type pointer to something and it has no member getName(). You have to first dereference that pointer and then call a member function (*book).getName(); or simply book->getName();.
However, since C++'s objects do not have to be on the heap (Java objects have to) you can create an object without new operator using bookClass book(name, numberr);

initializing an passing a string array as a parameter

Can I initiate a string array and pass it as a function that initializes it. I know this sounds redundant, but basically I want to initiate a string array and then pass it to a variable so that I can use it later? Something like this:
This is the .h:
class ScreenBasics{
void setupAnswers(int &_numberOfAnswers, string *_answersText);
string *answersText;
{
This will be the implementation .cpp
void ScreenBasics::setupAnswers(int &_numberOfAnswers, string *_answersText){
answersText = _answersText; // this is where I get confused cause I don't know if I should initiate my string pointer using new like answersText = new string(_numberOfAnswers);
{
so in the main.cpp I can do something like this:
int main( ) {
ScreenBasics basics;
int numberOfAnswers = 4;
string newAnswers [] = { "Good", "Superb", "Great", "Perfect"};
basics.setupAnswers(numberOfAnswers, newAnswers);
// let's say I want to call some of those answers later
for ( int i = 0; i < numberOfAnswers; i++){
cout << basics.answersText[i] << endl;
}
}
Thanks!
Have you thougt about using structs? Both classes and structs can have a mixture of public and private members, can use inheritance, and can have member functions. I would recommend using structs as plain-old-data structures without any class-like features, and using classes as aggregate data structures with private data and member functions.
Your code would look like the following:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct movies_t {
string title;
int year;
} mine, yours;
int main ()
{
string mystr;
mine.title = "2001 A Space Odyssey";
mine.year = 1968;
cout << "Enter title: ";
getline (cin,yours.title);
cout << "Enter year: ";
getline (cin,mystr);
stringstream(mystr) >> yours.year;
cout << "My favorite movie is:\n ";
printmovie (mine);
cout << "And yours is:\n ";
printmovie (yours);
return 0;
}
void printmovie (movies_t movie)
{
cout << movie.title;
cout << " (" << movie.year << ")\n";
}
Please let me know if you have any questions!
It sounds like your class should use a constructor to initialize the pointer.
class ScreenBasics
{
ScreenBasics(std::string* _answersText, std::size_t size)
: answersText(new std::string[size])
{
// copy values from _answersText to answersText
}
};
Note that since you are allocating a resource dynamically, you will need to implement The Rule of Three: that is, you need to create a copy-constructor, copy-assignment operator and destructor. This is because their default implementations do not semantocally conform to our requirements. For instance, the default copy-constructor and copy-assignment operator perform shallow copies (that is, they copy the pointer but not what it points to). Also, the destructor doesn't free the memory allocated my new[]. You will need to provide your own definition of the destructor that calls delete[].
Fortunately, all this can be avoided by using the standard library container std::vector, which is a dynamic array class that handles the memory allocation for you. The default implementations of the aforementioned constructors will correctly copy/copy-assign a vector if the need be:
class ScreenBasics
{
ScreenBasics(std:vector<std::string> _answersText)
: answersText(_answersText)
{
}
};
Notice that the size also didn't have to be passed as a parameter. A vector maintains its size internally.