Passing c-strings to class function (assigning it to class member) - c++

I have a class called Person:
class Person {
private:
char name[50];
unsigned int number;
public:
void set_data(const char *newname, unsigned int number) {
*name= *newname; //THE MAIN PROBLEM I WANT TO SOLVE
this->number = number;
}
char* get_name() {
return this->name;
}
unsigned int get_number() {
return this->number;
}
};
I have arrays:
const char *names[] = {"Mark", "Pavel", "Bill", "Jasur", "Jeff"};
int phones[] = { 1234567890, 9876543210, 123321456654, 1998946848479, 1234554321 };
I'm using for loop to set Person members:
Person p;
for (int i = 0; i < 5; i++) {
p.set_data(names[i], phones[i]);
cout << p.get_name() << endl;
}
When I run this, I'm getting wrong output.

Using * the way you are, you are only copying the 1st char into name. You are also not null-terminating name either, which is required by the overloaded operator<< that takes a char* as input.
To copy the entire string, you need to use std::strcpy() (or better, std::strncpy()) instead, eg:
#include <cstring>
void set_data(const char *newname, unsigned int newnumber) {
//std::strcpy(name, newname);
std::strncpy(name, newname, 49);
name[49] = '\0';
number = newnumber;
}
However, since this is C++ and not C, you really should be using std::string instead:
#include <string>
class Person {
private:
std::string name;
unsigned int number;
public:
void set_data(const std::string &newname, unsigned int newnumber) {
name = newname;
number = newnumber;
}
std::string get_name() const {
return name;
}
/* or:
const std::string& get_name() const {
return name;
}
*/
unsigned int get_number() const {
return number;
}
};

Related

the code doesn't display and doesn't run either

Below is a program that has class definitions for Item, Customer and Sales. The main simply creates object object of each class and test its member functions. Modify the main program such that it provides a menu driven interface where user can create objects of Item, Customer and a complete a sales transaction with the sales object.The program should also have an option for display the records of items,customers and sales.To make your program more useful,include file handling such that when objects are created for Items,Customers and Transaction,the user will be prompted to save the recordon the file or not.
here's the code it's not displaying anything pleasee help i'm running it by Dev c++
#include <conio.h>
#include <iostream>
#include <string.h>
using namespace std;
class Item {
int itemCode;
private:
double price;
double discount;
protected:
int qtyOnStock;
char *name;
public:
Item() {
itemCode = 0;
strcpy(name, "UNKNOWN");
price = 0;
discount = 0;
qtyOnStock = 100;
}
void setItemCode(int c) { itemCode = c; }
int getItemCode() { return itemCode; }
double getPrice() { return price; }
void setPrice(double p) { price = p; }
void setDiscount(double d) { discount = d; }
double getDiscount(double d) { return ((d < 20 ? d : 20) / 100 * price); }
void setName(char *n) { name = n; }
char *getName() { return name; }
void setQtyOnStock(int q) { qtyOnStock = q; }
int getQtyOnStock() { return qtyOnStock; }
};
class Customer {
private:
int id;
char *name;
char *contactNo;
int type;
public:
Customer() {
id = 0;
strcpy(contactNo, "No Num");
strcpy(name, "No Name");
type = 0;
}
void setId(int newId) { id = newId; }
int getId() { return id; }
void setName(char *n) { strcpy(name, n); }
char *getName() { return name; }
void setContactNo(char *c) { strcpy(contactNo, c); }
char *getContactNo() { return name; }
};
class Sales {
private:
Item item;
Customer cust;
char *date;
int qtySold;
public:
Sales() { date = "mm-dd-yyyy"; }
void setItem(Item newItem) { item = newItem; }
Item getItem() { return item; }
void setCustomer(Customer newCust) { cust = newCust; }
Customer getCustomer() { return cust; }
void setDate(char *newDate) { strcpy(date, newDate); }
char *getDate() { return date; }
void setQtySold(int newQty) { qtySold = newQty; }
int getQtySold() { return qtySold; }
};
int main() {
Item item1;
Customer cust1;
Sales sales1;
item1.setItemCode(143);
item1.setName("Ballpen");
item1.setPrice(12.5);
item1.setQtyOnStock(250);
cust1.setId(123);
cust1.setName("Juan dela Cruz");
sales1.setItem(item1);
sales1.setCustomer(cust1);
sales1.setDate("10-27-2018");
sales1.setQtySold(98);
item1.setQtyOnStock(item1.getQtyOnStock() - sales1.getQtySold());
system("cls");
cout << sales1.getItem().getName() << endl << item1.getQtyOnStock();
getch();
return 0;
}
The main and biggest proble is that you do C-style string handling with char* and even that in a wrong way.
If you would enable all warning in your compiler, it would already tell you the problems. My VS2019 gives 15 errors, 1 warning and 7 messages, when I try to compile your code. Please see:
So, the main problem is that you are using char* that are not initialzed, meaning they point to somehwere, and that you do not allocate memory to store your strings.
So all your strcpy functions will fail and probably crash your system. Also the assignments to a char* will fail in most cases.
You will overwrite some random memory.
All this can be immediately fixed, without big problems, if you would use std::string instead of char*. Because char* are that error prone, C++ introduced the std::string, so, please use it.
Sometimes you have C++ teachers that want you to use char*. Those teachers should be fired. But if you really need to use char*. Then you must allocate memory, before coping data.
Let us assume that you have a string "myName" and you want to copy that.
char* name{};
name = new char[strlen(myName)+1]; // +1 for the trailing '\0'
strcpy(name, myName);
// ...
// ...
// Do stuff
// ...
// ...
delete [] name; // Release memory at the end
But as said. Simply use std::string
Your program as is, cannot work. You need a major refactoring.
In your Item class:
protected:
int qtyOnStock;
char *name;
public:
Item() {
itemCode = 0;
strcpy(name, "UNKNOWN");
price = 0;
discount = 0;
qtyOnStock = 100;
}
name is an unitialized char pointer so copying to it will result in UB.
change char* name to std::string name, replace strcpy(...) name = "UNKNOWN".
Normally though you initialize member variables like this:
Item()
: itemCode(0), itemCode(0), name("UNKNOWN"), price(0), discount(0), qtyOnStrock(100)
{}
a newer compiler lets you initialize in other ways like when declared e.g.:
protected:
int qtyOnStock{100};
std::string name{"UNKNOWN"};
...

Class does not persist vector of objects after addition

My code is as shown below. The problem is inside the int main() function, r.printItems() is not printing anything. What am I missing here?
main.cpp
#include <bits/stdc++.h>
#include "Customer.h"
#include "MenuCreator.h"
#include "FoodItem.h"
MenuCreator m1;
void createCustomer() {
Customer c1("mrg", "m#gmail.com", "9654357", "+91");
}
void createRestaurantItem(Restaurant &rest) {
rest.addItems(FoodItem("t1"));
rest.addItems(FoodItem("D1"));
}
void createMenu() {
m1.createMenu("sg");
Category c1;
c1.setName("Non-veg");
m1.addCategory(c1);
Restaurant r1;
r1.setName("ABC");
r1.setDescription("Test Restaurant");
createRestaurantItem(r1);
c1.addRestaurants(r1);
}
vector<Restaurant> getRestaurantsForCategory(string category) {
return m1.getRestaurantsForCategories(category);
}
int main() {
createCustomer();
createMenu();
for (auto r: getRestaurantsForCategory("Non-veg")) {
r.printItems();
}
return 0;
}
MenuCreator.h
#include <bits/stdc++.h>
#include "Menu.h"
using namespace std;
class MenuCreator {
public:
void createMenu(string name) {
Menu m1;
m1.setName(name);
menu = m1;
}
void addCategory(const Category &categ) {
categories.push_back(categ);
}
const Menu &getMenu() const {
return menu;
}
const vector<Category> &getCategories() const {
return categories;
}
void addRestaurantForCategory(string name, const Restaurant restaurant) {
for(auto categ: categories) {
if (categ.getName() == name) {
categ.addRestaurants(restaurant);
}
}
}
const vector<Restaurant> &getRestaurantsForCategories(string category) {
for(auto categ: categories) {
if(categ.getName() == category) return categ.getRestaurants();
}
}
private:
Menu menu;
vector<Category> categories;
};
Menu.h
#include<bits/stdc++.h>
#include "Category.h"
using namespace std;
class Menu {
public:
const string &getName() const {
return name;
}
void setName(const string &name) {
Menu::name = name;
}
private:
string name;
string description;
vector<Category> categories;
};
Category.h
using namespace std;
class Category {
public:
const string &getName() const {
return name;
}
void setName(const string &name) {
Category::name = name;
}
const string &getDescription() const {
return description;
}
void setDescription(const string &description) {
Category::description = description;
}
const vector<Restaurant> &getRestaurants() const {
return restaurants;
}
void setRestaurants(const vector<Restaurant> &restaurants) {
Category::restaurants = restaurants;
}
void addRestaurants(const Restaurant &rt) {
Category::restaurants.push_back(rt);
}
private:
string name;
string description;
vector<Restaurant> restaurants;
};
FoodItem.h
#include <bits/stdc++.h>
#include <vector>
#include "FoodItem.h"
using namespace std;
class Restaurant {
public:
Restaurant() {
this->id = gen_random(12);
}
virtual ~Restaurant() {
}
const string &getName() const {
return name;
}
void setName(const string &name) {
Restaurant::name = name;
}
const string &getDescription() const {
return description;
}
void setDescription(const string &description) {
Restaurant::description = description;
}
double getLat() const {
return lat;
}
void setLat(double lat) {
Restaurant::lat = lat;
}
double getLang() const {
return lang;
}
void setLang(double lang) {
Restaurant::lang = lang;
}
const string &getImageUrl() const {
return imageUrl;
}
void setImageUrl(const string &imageUrl) {
Restaurant::imageUrl = imageUrl;
}
const string &getVideoUrl() const {
return videoUrl;
}
void setVideoUrl(const string &videoUrl) {
Restaurant::videoUrl = videoUrl;
}
const vector<FoodItem> &getItems() const {
return items;
}
void setItems(const vector<FoodItem> &items) {
Restaurant::items = items;
}
void addItems(const FoodItem &item) {
this->items.push_back(item);
}
string gen_random(const int len) {
string tmp_s;
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
srand( (unsigned) time(NULL) * getpid());
tmp_s.reserve(len);
for (int i = 0; i < len; ++i)
tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)];
return tmp_s;
}
const string &getId() const {
return id;
}
void printItems() {
for(auto it: items) {
cout<<"item: "<<it.getName()<<endl;
}
}
private:
string id;
string name;
string description;
double lat;
double lang;
string imageUrl;
string videoUrl;
string createdAt;
string updatedAt;
vector<FoodItem> items;
};
Restaurant.h
#include <bits/stdc++.h>
#include <vector>
#include "FoodItem.h"
using namespace std;
class Restaurant {
public:
Restaurant() {
this->id = gen_random(12);
}
virtual ~Restaurant() {
}
const string &getName() const {
return name;
}
void setName(const string &name) {
Restaurant::name = name;
}
const string &getDescription() const {
return description;
}
void setDescription(const string &description) {
Restaurant::description = description;
}
double getLat() const {
return lat;
}
void setLat(double lat) {
Restaurant::lat = lat;
}
double getLang() const {
return lang;
}
void setLang(double lang) {
Restaurant::lang = lang;
}
const string &getImageUrl() const {
return imageUrl;
}
void setImageUrl(const string &imageUrl) {
Restaurant::imageUrl = imageUrl;
}
const string &getVideoUrl() const {
return videoUrl;
}
void setVideoUrl(const string &videoUrl) {
Restaurant::videoUrl = videoUrl;
}
const vector<FoodItem> &getItems() const {
return items;
}
void setItems(const vector<FoodItem> &items) {
Restaurant::items = items;
}
void addItems(const FoodItem &item) {
this->items.push_back(item);
}
string gen_random(const int len) {
string tmp_s;
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
srand( (unsigned) time(NULL) * getpid());
tmp_s.reserve(len);
for (int i = 0; i < len; ++i)
tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)];
return tmp_s;
}
const string &getId() const {
return id;
}
void printItems() {
for(auto it: items) {
cout<<"item: "<<it.getName()<<endl;
}
}
private:
string id;
string name;
string description;
double lat;
double lang;
string imageUrl;
string videoUrl;
string createdAt;
string updatedAt;
vector<FoodItem> items;
};
When createMenu() in main.cpp is setting up the menu, it creates a local Category object named c1 and adds it to the menu, which makes a copy of c1 when pushingnit into the MenuCreator::categories vector. No Restaurant objects had been added to c1 yet when that copy is created. So when a Restaurant is then added to c1 afterwards, the copy is not updated. That is why there are no Restaurant objects in the menu when MenuCreator::getRestaurantsForCategory() tries to return them.
Change createMenu() to fully initialize c1 before adding it to the menu, eg:
void createMenu() {
m1.createMenu("sg");
Category c1;
c1.setName("Non-veg");
Restaurant r1;
r1.setName("ABC");
r1.setDescription("Test Restaurant");
createRestaurantItem(r1);
c1.addRestaurants(r1);
m1.addCategory(c1); // <-- move down here
}
Also, on a side note, the return value of MenuCreator::getRestaurantsForCategories() is undefined if the specified category is not found. Since the return value is a reference to a vector, it needs to either return a static vector that is empty, or else throw an exception.

Define dynamic arrays in class inheritance

I am trying to initialize 2 dynamic arrays which class student will have an array containing all the courses registered and class course will have an array containing all the students registered to the class. I defined class Course and Student like this:
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
class Course;
class Student {
std::string name; // person’s name
int id; // person’s age
Course* courses;
int course_register; // number of organization registered to
public:
Student();
Student(const Student& s) {
name = s.getName();
id = s.getAge();
course_register = s.getorg_register();
}
Student(std::string n, int i) {
id = i;
name = n;
}
int getAge() const { return id; }
string getName() const { return name; }
int getorg_register() const { return course_register; }
};
class Course {
std::string name; // name of the org
Student* students; // list of members
int size; // actual size of the org
int dim; // max size of the org
public:
Course()
{
dim = 100;
students = new Student[dim];
};
Course(const Course& course)
{
name = course.getName();
dim = course.getDim();
size = course.getSize();
students = new Student[dim];
for (int i = 0; i < size; i++) {
students[i] = course.getStudent(i);
}
}
~Course()
{
delete[] students;
}
Student getStudent(int i) {return students[i];}
Student* getStudents() {return students;}
int getSize(){return size;}
int getDim() {return dim;}
string getName() {return name;}
};
Student::Student() {
courses = new Course[5];
}
When I try to compile, I get an exception unhandled at runtime for constructor Student::Student(). Can someone explain to me why I get a runtime error? And how would you change it to make it work?
A Student should contain a list that refers to the Courses it is enrolled in, it should not create the Courses themselves.
A Course should contain a list that refers to the Students enrolled in it, it should not create the Students themselves.
Does that make sense? In this case, refers means "use a pointer". For instance, Student could have a std::vector<Course*>, and Course could have a std::vector<Student*>. Then you can have a method that enrolls a Student into a Course, where a pointer to the Student is added to the Course's list, and a pointer to the Course is added to the Student's list, eg:
Student.h
#ifndef StudentH
#define StudentH
#include <string>
#include <vector>
class Course;
class Student {
std::string name;
int id;
std::vector<Course*> courses;
void addCourse(Course *c);
void removeCourse(Course *c);
friend class Course;
public:
Student(std::string n, int i);
Student(const Student& s);
Student(Student&& s);
~Student();
Student& operator=(Student rhs);
int getId() const;
string getName() const;
std::vector<Course*> getCourses() const;
void enroll(Course &c);
void drop(Course &c);
};
#endif
Student.cpp
#include "Student.h"
#include "Course.h"
Student::Student(std::string n, int i) {
name = n;
id = i;
}
Student::Student(const Student& s) {
name = s.name;
id = s.id;
for (Course *c : s.courses) {
c->enroll(*this);
}
}
Student::Student(Student&& s) {
name = std::move(s.name);
id = s.id; s.id = 0;
courses = std::move(s.courses);
for (Course *c : courses) {
c->removeStudent(&s);
c->addStudent(this);
}
}
Student::~Student() {
for(Course *c : courses) {
c->removeStudent(this);
}
}
Student& Student::operator=(Student rhs) {
Student temp(std::move(rhs));
for (Course *c : courses) {
c->removeStudent(this);
}
name = std::move(temp.name);
id = temp.id; temp.id = 0;
courses = std::move(temp.courses);
for (Course *c : courses) {
c->removeStudent(&temp);
c->addStudent(this);
}
return *this;
}
void Student::addCourse(Course *c) {
if (std::find(courses.begin(), courses.end(), c) == courses.end()) {
courses.push_back(c);
}
}
void Student::removeCourse(Course *c) {
auto iter = std::find(courses.begin(), courses.end(), c);
if (iter != courses.end())
courses.erase(iter);
}
}
int Student::getId() const {
return id;
}
string Student::getName() const {
return name;
}
std::vector<Course*> Student::getCourses() const {
return courses;
}
void Student::enroll(Course &c) {
c.enroll(*this);
}
void Student::drop(Course &c) {
c.drop(*this);
}
Course.h
#ifndef CourseH
#define CourseH
#include <string>
#include <vector>
class Student;
class Course {
std::string name;
std::vector<Student*> students;
void addStudent(Student *s);
void removeStudent(Student *s);
friend class Student;
public:
Course(std::string n);
Course(const Course& c);
Course(Course&& c);
~Course();
Course& operator=(Course rhs);
string getName() const;
std::vector<Student*> getStudents() const;
void enroll(Student &s);
void drop(Student &s);
};
#endif
Course.cpp
#include "Course.h"
#include "Student.h"
Course::Course(std::string n) {
name = n;
}
Course::Course(const Course& c) {
name = c.name;
for (Student *s : c.students) {
enroll(*s);
}
}
Course::Course(Course&& c) {
name = std::move(c.name);
students = std::move(c.students);
for (Student *s : students) {
s->removeCourse(&c);
s->addCourse(this);
}
}
Course::~Course()
{
for(Student *s : students) {
s->removeCourse(this);
}
}
Course& Course::operator=(Course rhs)
{
Course temp(std::move(rhs));
for (Student *s : students) {
s->removeCourse(this);
}
name = std::move(temp.name);
students = std::move(temp.students);
for (Student *s : students) {
s->removeCourse(&temp);
s->addCourse(this);
}
return *this;
}
void Course::addStudent(Student *s) {
if (std::find(students.begin(), students.end(), s) == students.end()) {
students.push_back(s);
}
}
void Course::removeStudent(Student *s) {
auto iter = std::find(students.begin(), students.end(), s);
if (iter != students.end())
students.erase(iter);
}
}
string Course::getName() const {
return name;
}
std::vector<Student*> Course::getStudents() const {
return students;
}
void Course::enroll(Student &s) {
addStudent(&s);
s.addCourse(this);
}
void Course::drop(Student &s) {
removeStudent(&s);
s.removeCourse(this);
}
Main.cpp
#include "Student.h"
#include "Course.h"
int main()
{
Course c("Math");
Student p("Joe", 12345);
p.enroll(c);
return 0;
}
You have infinite recursion. The Course constructor calls the Student constructor. The Student constructor calls the Course constructor. This continues until you've used up all the stack space.
You'll want to rethink your design of your two classes.

Getting Member String from Class C++

I have a class that contain some game level settings.
class Stage {
private:
int level;
int stars;
std::string imgName;
public:
int getLevel(){ return level; };
void setLevel(int n){ level = n; };
int getStars(){ return stars; };
void setStars(int n){ stars = n; };
std::string getImgName(){ return imgName; };
void setImgName(std::string name){ imgName = name; };
};
Then in my program I set the info.
Stage* stagesArr = new Stage[3];
stagesArr[0].setLevel(0);
stagesArr[0].setStars(1200);
stagesArr[0].setImgName("stage0.png");
Then if I want to get this info the string is giving me an odd output.
CCLOG("Level: %i", stagesArr[0].getLevel());
CCLOG("Required stars: %i", stagesArr[0].getStars());
CCLOG("Image Name: %s", stagesArr[0].getImgName());
//Level:0
//Required stars: 1200
//Image Name: T%s //Or just random stuff.
What am I missing here?
Suspected that CCLOG() uses the same formatting rules like the <x>printf() function family does, you need to pass a const char* with the format specifier %s.
Your getImgName() returns a std::string value though, which isn't directly compatible with a const char*.
To achieve the latter, you should call the std::string::c_str() function:
CCLOG("Image Name: %s", stagesArr[0].getImgName().c_str());
Also you can improve your getter/setter functions specifying constness applicability more clear:
int getLevel() const { return level; }
// ^^^^^^
int getStars() const { return stars; }
// ^^^^^^
const std::string& getImgName() const { return imgName; }
// ^^^^^ // ^^^^^^
void setImgName(const std::string& name) { imgName = name; }
// ^^^^^
Note:
As a matter of style you can omit the get / set prefixes for getter/setter functions in c++, as the signatures are disambiguate enough:
int Level() const { return level; }
void Level(int n){ level = n; }
int Stars() const { return stars; }
void Stars(int n){ stars = n; }
const std::string& ImgName() const { return imgName; }
void ImgName(const std::string& name){ imgName = name; }
My personally preferred style is to use lower caps and disambiguate class member variables with a _ postfix:
class Stage {
private:
int level_;
int stars_;
std::string img_name_;
public:
int level() const { return level_; }
void level(int n) { level_ = n; }
int stars() const { return stars_; }
void stars(int n){ stars_ = n; }
const std::string& img_name() const { return img_name_; }
void img_name(const std::string& name) { img_name_ = name; };
};

Why is my strcmp constructor not working?

#include <iostream>
#include <string>
using namespace std;
class String {
public:
String (){
//default
value = 0;
name = "noname";
}
String (int x){
setValue(x);
}
String (string y){
setName(y);
}
String (int x ,string y) {
setValue(x);
setName(y);
}
void setValue(int x){
value = x;
}
void setName(string y){
name = y;
}
int getValue(){
return value;
}
string getName(){
return name;
}
int Compare (const char* name1,const char* name2){
const char* n1 = name1;
const char* n2 = name2;
if (strcmp(n1, n2) != 0)
cout <<"test"<<endl;
};
private:
int value;
string name;
const char* n1;
const char* n2;
};
int main ()
{
string str1 ("abcd");
string str2 ("bbbb");
int Compare("abcd", "bbbb");
//String coin1(1,"Penny");
//cout<<"Coin 1 is a "<<coin1.getName()<<" and its worth $"<<coin1.getValue()<<endl;
//String coin2(10,"Dime");
//cout<<"Coin 2 is a "<<coin2.getName()<<" and its worth $"<<coin2.getValue()<<endl;
return 0;
}
I am probably going about this completely wrong but I can't think of any way else to do it.I'm trying to make a strcmp that allows the comparison of the String object to another String object or to a “C” type string but I seem to be doing it wrong.
Because you're not instantiating your String object.
Try with the following main()
int main ()
{
String str1 ("abcd"); // create an instance of String class
String str2 ("bbbb"); // create another
printf("%i", str1.Compare("abcd", "bbbb"));
printf("%i", str2.Compare("abcd", "bbbb"));
return 0;
}
You can also make your Compare() method to work with the instanced string instead, so:
int Compare (const char* nameOther)
{
const char* n1 = name.c_str();
const char* n2 = nameOther;
int result = strcmp(n1, n2);
if (result != 0)
cout <<"not equal"<<endl;
else
cout <<"equal"<<endl;
return result; // you forgot the 'return' at Compare().
};
Then you can do:
int main ()
{
String str1 ("abcd"); // create an instance of String class
String str2 ("bbbb"); // create another
printf("%i", str1.Compare("abcd"));
printf("%i", str2.Compare("abcd"));
return 0;
}
After you tested it, you can remove the unnecessary code from Compare():
int Compare (const char* nameOther)
{
return strcmp(name.c_str(), nameOther);
};