c++ set const char* member variable of class - c++

When I am trying to assign a member variable, which is const char*, it just ends the program.
However, if I get some cin inputs before I assign a member variable, it works.
this is my NameCard.h
class NameCard {
private:
const char* name;
const char* companyName;
const char* phoneNumber;
enum grade{CLERK, SENIOR, ASSIST, MANAGER};
grade my_grade;
NameCard* nextCard;
NameCard* head;
public:
NameCard(const char*, const char*, const char*, int);
void setName();
void setCompanyName();
void setPhoneNumber();
void setMyGrade();
void setHead(NameCard*);
void setNextCard(NameCard*);
void findInfo(char*);
void printAll();
};
This is main.cpp
#include <iostream>
#include <cstring>
#include "NameCard.h"
using namespace std;
NameCard::NameCard(const char* a, const char* b, const char* c, int d){
name = a;
companyName = b;
phoneNumber = c;
switch(d){
case CLERK: my_grade = CLERK; break;
case SENIOR: my_grade = SENIOR; break;
case ASSIST: my_grade = ASSIST; break;
case MANAGER: my_grade = MANAGER; break;
}
cout << name << " " << companyName << " " << phoneNumber << " " << my_grade << endl;
}
void NameCard::setName(){
char* name;
cout << "type name." << endl;
cin >> name;
this->name = name;
cout << this->name << endl;
}
void NameCard::setCompanyName(){
char* company_name;
cout << "type company name." << endl;
cin >> company_name;
this->companyName = company_name;
cout << this->companyName << endl;
}
void NameCard::setPhoneNumber(){
char* phone_number;
cout << "type phone number." << endl;
cin >> phone_number;
phoneNumber = phone_number;
cout << phoneNumber;
};
void NameCard::setMyGrade(){
int input_grade;
cout << "type position. 1)CLERK 2) SENOIR 3) ASSIST 4)MANAGER" << endl;
cin >> input_grade;
switch(input_grade){
case CLERK: my_grade = CLERK; break;
case SENIOR: my_grade = SENIOR; break;
case ASSIST: my_grade = ASSIST; break;
case MANAGER: my_grade = MANAGER; break;
}
cout << input_grade;
};
void NameCard::setHead(NameCard* head){
this->head = head;
};
void NameCard::setNextCard(NameCard* next){
this->nextCard = next;
}
void NameCard::findInfo(char* target_name){
NameCard* temp;
temp = head;
while(temp != NULL){
if(temp->name == target_name){
cout << "name : " << temp->name << endl;
cout << "companyName : " << temp->companyName << endl;
cout << "phoneNumber : " << temp->phoneNumber << endl;
cout << "grade : " << temp->my_grade << endl;
break;
}
temp = temp->nextCard;
}
};
void NameCard::printAll(){
NameCard* temp;
temp = head;
while(temp!= NULL){
cout<< "----------------------------" << endl;
cout << "name : " << temp->name << endl;
cout << "companyName : " << temp->companyName << endl;
cout << "phoneNumber : " << temp->phoneNumber << endl;
cout << "grade : " << temp->my_grade << endl;
temp = temp->nextCard;
}
}
int main(){
int index = 0;
NameCard* head = new NameCard("test", "test", "test", 3);
NameCard* bef = NULL;
// char input[50];
// cout << "nmae ";
// cin >>input;
head->setName();
head->setPhoneNumber();
head->setCompanyName();
head->setMyGrade();
return 0;
}
And the problem is here. This is not working. The program ends right after it gets name from setName(). It just ends at the setName() cin >> name. it did not print name after then, and stopped.
int main(){
int index = 0;
NameCard* head = new NameCard("test", "test", "test", 3);
NameCard* bef = NULL;
// char input[50];
// cout << "nmae ";
// cin >>input;
head->setName();
head->setPhoneNumber();
head->setCompanyName();
head->setMyGrade();
return 0;
}
However, this is working fine. it gets the test input and executes all the code below.
int main(){
int index = 0;
NameCard* head = new NameCard("test", "test", "test", 3);
NameCard* bef = NULL;
char input[50];
cout << "test input ";
cin >>input;
head->setName();
head->setPhoneNumber();
head->setCompanyName();
head->setMyGrade();
return 0;
}

You are writing to memory you didn't allocate and most likely don't own.
Check this for example
void NameCard::setName(){
char* name;
cout << "type name." << endl;
cin >> name;
this->name = name;
cout << this->name << endl;
}
You declare char* name and try to read from cin into it. But name is just an uninitialized pointer.
One fix may be to declare name as an array, which also decays to a pointer (so it can be used as a pointer), but does have associated memory. Like this
char name[50];
Or if you want it to be dynamically allocated
char* name = new char[50];
// Use it and when you are done delete it
// Never forget to release memory allocated with new or you get a memory leak
delete[] name;
The key point is that the pointer needs to point to some memory block you know you can use. Note that in the example I allocated 50 chars, you have to make sure you never use (read/write) past the allocated memory, or you get the same error you have been getting and potentially program termination.
A safer alternative is to use std::string, which automatically handles memory for you, so you don't have to mind about allocation and releasing.
You could do something like
std::string name;
std::cin >> name;

Related

c++ program printing out address instead of value

I have a program that takes in information through a struct and puts it into a vector, and I'm trying to print that information out but instead get an address. The structure should hold the values correctly so I think it's either my pointers or the way I'm printing it out.
#include <iostream>
#include <cstring>
#include<vector>
using namespace std;
struct student
{
char* fName;
char* lName;
int id;
float gpa;
};
void add(vector<student*>*);
int main()
{
vector <student*>* list = new vector<student*>();
if (strcmp(cmd,"ADD") == 0)
{
add(list);
}
else if (strcmp(cmd,"PRINT") == 0)
{
for(vector<student*>::iterator i = list->begin(); i != list->end(); i++)
{
cout << *i;
}
cout << "print" << endl;
}
}
void add(vector<student*>* paramlist)
{
student* s = new student();
s->fName = new char[25];
s->lName = new char[25];
cout << "Enter first name" << endl;
cin >> s->fName;
cout << "Enter last name" << endl;
cin >> s->lName;
cout << "Enter id number" << endl;
cin >> s->id;
cout << "Enter GPA" << endl;
cin >> s->gpa;
paramlist->push_back(s);
}
Or it might have something to do with the way I iterate through the vector.
You need to add an operator overload for your struct, to define how the struct should appear when printed. You also need to dereference the pointer as well as the iterator.
// Define how the struct should look when printed.
// This function makes it appear like:
// Name: John Smith, ID: 1235, GPA: 4.0
std::ostream &operator<<(std::ostream &os, const student &val) {
os
<< "Name: " << val.fname << " " << val.lname
<< ", ID: " << val.id
<< ", GPA: " << val.gpa
<< endl;
return os;
}
Then later...
for(vector<student*>::iterator i = list->begin(); i != list->end(); i++)
{
// Dereference twice, once for the iterator, and again for the pointer.
cout << **i << endl;
}
You have to dereference twice **i.
With *i you get the address of vector<student*> element that is student*.
You get student, you need other *.
You may use for (auto i: list) to make your life easier.

When reading in a .txt file in c++, how do I change a number that's stored in the .txt file as "365048" to "36, 50, 48" using a dynamic array?

I have been trying to separate a number stored in a .txt file as "365048" to "36, 50, 48" when it has been read into my program using a dynamic array and i'm not sure where I am going wrong. The variable i'm having the issue with is int* purchases.
Code from Main.cpp
// Repeat_Assessment_C++_Aisling.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include "Customer.h"
using namespace std;
void OutputFileStream();
void parseLine(const string& str);
void InputFileStream();
//void printActions();
void OutputFileStream()
{
cout << "Creating and writing to file: Customer.txt" << endl;
ofstream outStream("customers.txt"); // write mode (overwrites existing data)
if (outStream.good())
{
int customerID = 150033;
outStream << "This is a line of text.\n";
outStream << "This is another line of text.\n";
outStream << "This is a line of text.\n";
int numOfPurchases = 4;
int purchases = 0;
outStream << customerID << "Mr" << "Jack" << "New" << numOfPurchases << purchases << endl;
outStream.close(); // close file
cout << "File written.\n" << endl;
}
else
cout << "Unable to open file";
}
void parseLine(const string& str) {
stringstream strStream(str); //create string stream from the string
// int customerID;
string title;
string name;
string type;
//int numOfPurchases;
//int purchases;
string s;
int customerID = 150033;
getline(strStream, s, ';');
customerID = stoi(s);
getline(strStream, title, ';');
getline(strStream, name, ';');
getline(strStream, type, ';');
int numOfPurchases = 4;
getline(strStream, s, ';');
numOfPurchases = stoi(s);
int purchases = 0;
getline(strStream, s, ';');
purchases = stoi(s);
int* purchasesArray = new int[3];
purchasesArray[0] = (purchases & (255 << 24)) >> 24;
purchasesArray[1] = (purchases & (255 << 16)) >> 16;
purchasesArray[2] = (purchases & (255 << 8)) >> 8;
for (int i = 0; i < 3; i++)
{
int purchasesArray[3];
}
cout << " CustomerID: " << customerID << "Title:" << title << " Name: " << name << " Type:" << type << " Number of Purchases: " << numOfPurchases << "Purchases: " << purchases << endl;
}
void InputFileStream() {
cout << "Reading from a semi-colon delimited txt file" << endl;
string line;
ifstream inStream("customers.txt"); //opens file as an input file stream
if (inStream.good()) //if the file is opened successfully and not empty
{
while (getline(inStream, line)) //reads line until false return
{
parseLine(line);
}
inStream.close();
}
else
cout << "unable to open file or the file is empty!";
}
int main()
{
InputFileStream();
Customer cust1;
cust1.setCustomerID(150032);
cust1.setTitle("Mr");
cust1.setName("Joey");
cust1.setNumOfPurchases(3);
cust1.setPurchases(366, 352, 334);
cust1.setType("New");
cout << cust1.getCustomerID() << endl;
cout << cust1.getTitle() << endl;
cout << cust1.getName() << endl;
cout << cust1.getNumOfPurchases() << endl;
cout << cust1.getPurchases() << endl;
cout << cust1.getType() << endl;
return 0;
}
Code from Customer.h
#pragma once
#include<iostream>
using namespace std;
#include<string>
class Customer
{
private:
int customerID;
string title;
string name;
int numOfPurchases;
int* purchases;
string type;
public:
Customer(); // default constructor
Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type);
//copy overload assignment
Customer& operator=(Customer& otherCustomer);
Customer(const Customer& source);
~Customer(); //destructor
//Getters and Setters
void setCustomerID(int customerID);
void setTitle(string title);
void setName(string name);
void setNumOfPurchases(int numOfPurchases);
void setPurchases(int purchase1, int purchase2, int purchase3);
void setType(string type);
int getCustomerID();
string getTitle();
string getName();
int getNumOfPurchases();
int* getPurchases();
string getType();
void printCustomer() {
cout << customerID << "," << title << "," << name << "," << numOfPurchases << "," << purchases << "," << type << endl;
}
friend std::ostream& operator<<(std::ostream& out, Customer& customer); // overloaded operator<<
friend istream& operator>> (istream& in, Customer& customer); // overloaded operator >>
};
Code from Customer.cpp
#include "Customer.h"
#include <iostream>
#include <string>
#include<utility>
using namespace std;
//default constructor
Customer::Customer() {
}
//Full constructor
Customer::Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type)
{
this->customerID = customerID;
this->title = title;
this->name = name;
this->numOfPurchases = numOfPurchases;
purchases = new int[3];
purchases[0] = purchase1;
purchases[1] = purchase2;
purchases[2] = purchase3;
this->type = type;
}
Customer::Customer(const Customer& source) //copy constructor
{
cout << "copy constructor called" << endl;
this->customerID = source.customerID;
this->title = source.title;
this->name = source.name;
this->numOfPurchases = source.numOfPurchases;
this->purchases = new int[3];
purchases[0] = source.purchases[0];
purchases[1] = source.purchases[1];
purchases[2] = source.purchases[2];
this->type = source.type;
}
//overloaded assignment operator=
Customer& Customer::operator= (Customer& otherCustomer)
{
cout << "Overloaded assignment operator= called" << endl;
//self-assignment guard
if (this == &otherCustomer)
return *this; //refernce to the same object
// copy data from the source (rhs) to this object (the destination)
name = otherCustomer.name;
//must make a new scores object to store a copy of the other student
if (purchases != nullptr)
delete[] purchases;
purchases = new int[3];
for (int i = 0; i < 3; i++) {
purchases[i] = otherCustomer.purchases[i];
}
//return this existing object so we can chain this operator
return *this;
}
Customer::~Customer() {
cout << "Destructor ~Customer called" << endl;
delete[] purchases;
}
// Overloaded insertion operator (Outputs Character object data as an output stream)
// Defined in header file as a "friend" function, as it is not a member function
//
ostream& operator<<(ostream& out, Customer& customer)
{
cout << "Customer details ( output by insertion operator<< )" << endl;
cout << "Customer ID: " << customer.customerID << endl;
cout << "Title: " << customer.title << endl;
cout << "Name: " << customer.name << endl;
cout << "Number of purchases: " << customer.numOfPurchases << endl;
cout << "Purchases: ";
for (int i = 0; i < 3; i++)
{
if (i > 0) cout << ",";
cout << customer.purchases[i];
}
cout << "Type: " << customer.type << endl;
return out;
}
istream& operator>> (istream& in, Customer& customer)
{
cout << "Enter Customer details ( using the extraction operator>> )" << endl;
cout << "Enter Customer ID: " << endl;
cin >> customer.customerID;
cout << "Enter Title: " << endl;
getline(cin, customer.title);
cout << "Enter Name: " << endl;
getline(cin, customer.name);
cout << "Enter Number of Purchases: ";
cin >> customer.numOfPurchases;
cout << "Enter Purchases: ";
cin >> customer.purchases[0];
cin >> customer.purchases[1];
cin >> customer.purchases[2];
cout << "Enter Type";
getline(cin, customer.type);
cout << endl;
return in;
}
int Customer::getCustomerID()
{
return customerID;
}
string Customer::getTitle()
{
return title;
}
string Customer::getName()
{
return name;
}
int Customer::getNumOfPurchases()
{
return numOfPurchases;
}
int* Customer::getPurchases()
{
return purchases;
}
string Customer::getType()
{
return type;
}
void Customer::setCustomerID(int customerID)
{
if (customerID < 1) {
cout << "Customer ID has to be equal to 1 or more" << endl; //Changed all the "throw invalid_argument" messages to cout as they were causing an issue with my main.cpp file and an abort message kept appearing every time I ran my main.cpp file.
}
this->customerID = customerID;
}
void Customer::setTitle(string title)
{
if (title.length() < 2) {
cout << "Title has to be more than or equal to 2 characters" << endl;
}
this->title = title;
}
void Customer::setName(string name)
{
if (name.length() < 4) {
cout << "Length of name should be more than or equal to 4 characters" << endl;
}
this->name = name;
}
//Got help ith this on stack overflow as I was using "&&" instead of using "||" for the if statement
void Customer::setNumOfPurchases(int numOfPurchases)
{
if(numOfPurchases <0 || numOfPurchases > 10000){
cout << "Number of purchases should be between 0 to 10000" << endl;
}
this->numOfPurchases = numOfPurchases;
}
void Customer::setPurchases(int purchase1, int purchase2, int purchase3)
{
if (purchase1 < 0 || purchase2 < 0 || purchase3 < 0) {
cout << "Purchases must be more than or equal to zero" << endl;
}
}
//Got help from stack overflow on comparing strings as I originally didnt use "type.compare"
void Customer::setType(string type) {
if (type.compare("New") !=0 || type.compare("Either") !=0) {
cout << "Type of purchase has to be New or Either" << endl;
}
}
Text in my customers.txt file:
150034;Mr;Sean Brennan;New;5;365048;\n
150035;Mrs;Aisling Smith;Regular;6;375149;\n
150036;Mr;John Smith;New;7;385250;\n
150037;Mrs;Sharon Hanratty;Regular;8;395351;
Trouble seems to be that you are trying to divide input into its hexadecimal digits and it looks like you are looking for decimal digits.
May be you can do something like following:
purchasesArray[0] = purchases / 10000;
purchasesArray[1] = (purchases / 100) % 100;
purchasesArray[2] = purchases % 100;
instead of
purchasesArray[0] = (purchases & (255 << 24)) >> 24;
purchasesArray[1] = (purchases & (255 << 16)) >> 16;
purchasesArray[2] = (purchases & (255 << 8)) >> 8;
Note: If your input is pretty big, above solution can be bad performancewise.
Note 2: Even if you really want hexadecimal digits, your parsing is problematic.
Edit for note 2:
To parse a 6 digit hexadecimal number you might do this:
purchasesArray[0] = (purchases & (255 << 16)) >> 16;
purchasesArray[1] = (purchases & (255 << 8)) >> 8;
purchasesArray[2] = purchases & 255;
your code seems to parse first 6 digits of an 8 digit hex number.
That is why I called it problematic.

Read Access Violation Code: 0xCDCDCDE1 and Code :0xCDCDCDE1

I'm doing a Shopping Mall project in Link List C++. In which I have to insert new Shop,Search Shop, Delete Shop, Count Shops and Display all. I written some of code.
I wrote the code but:
(1) it give error in input after when I input 2nd time and press input at last input i gives following Exception.
"Exception thrown: read access violation.
std::_String_alloc > >::_Mysize(...) returned 0xCDCDCDE1."
(2) When I display it give following Exception:
Exception thrown: read access violation.
temp was 0xCDCDCDCD.
Here is main.
int main()
{
ShoppingMallList* shopList=new ShoppingMallList();
string name="";
int shopNumber;
string brandShop;
int floor;
string shoptype;
do
{
system("cls");
cout << "**************WELCOME TO MALL**************\n1: Add Shop\n2: Search Shop\n3: Count Shops\n4:Display Shops\n5: Quit" << endl;
int option;
cin >> option;
switch (option)
{
case 1:
{
input(name, shopNumber, brandShop, floor, shoptype);
shopList->Insert(name, shopNumber, brandShop, floor, shoptype);
}
break;
case 2:
{
string name1;
cin.clear();
cin.ignore();
cout << "Enter Name of Shop to Search: ";
getline(cin, name1);
shopList->search(name1);
}
break;
case 4:
{
shopList->Print();
}
break;
case 5:
{
shopList->~ShoppingMallList();
exit(0);
}
break;
default:
continue;
}
system("pause");
shopList;
} while (true);
return 0;
}
void input(string& name, int& shopNumber, string& brandShop, int& floor, string& shoptype)
{
char temp;
cin.clear();
cin.ignore();
cout << "Enter Name: ";
getline(cin, name);
cout << "Enter Shop Number: ";
cin >> shopNumber;
cin.clear();
cin.ignore();
cout << "Enter Brand(yes/no): ";
getline(cin, brandShop);
cout << "Enter Floor: ";
cin >> floor;
cin.clear();
cin.ignore();
cout << "Enter Shop Type: ";
getline(cin, shoptype);
}
Here is shoppingMall.h
class ShoppingMall
{
friend std::ostream& operator<<(std::ostream& cout, const ShoppingMall& shop);
friend class ShoppingMallList;
public:
ShoppingMall(std::string& , int&, std::string&, int&, std::string&);
private:
std::string name;
int shopNumber;
std::string brandshop;
int floor;
std::string shopType;
ShoppingMall* link;
};
ShoppingMall::ShoppingMall(std::string& name , int& shopNumber, std::string& brandShop, int& floor, std::string& shoptype) : name(name), shopNumber(shopNumber), brandshop(brandShop), floor(floor), shopType(shoptype)
{
}
std::ostream& operator<<(std::ostream& cout, const ShoppingMall& shop)
{
cout << "Name: " << shop.name << std::endl << "Shop Number: " << shop.shopNumber << std::endl << "Brand Shop: " << shop.brandshop << std::endl << "Floor: " << shop.floor << std::endl << "Shop Type: " << shop.shopType << std::endl;
return cout;
}
And here is ShoppingMallList.h header file.
class ShoppingMallList
{
public:
ShoppingMallList();
void addToHead(std::string&, int&, std::string&, int&, std::string&);
void Insert(std::string&, int&, std::string&, int&, std::string&);
void Print();
int getsize();
void deleteShop(std::string&);
void search(std::string&);
private:
ShoppingMall* head;
int size;
};
ShoppingMallList::ShoppingMallList() : head(0), size(0)
{
}
void ShoppingMallList::addToHead(std::string& name, int& shopNumber, std::string& brandShop, int& floor, std::string& shoptype)
{
ShoppingMall* temp = new ShoppingMall(name,shopNumber,brandShop,floor,shoptype);
if (head==0)
{
head = temp;
}
else
{
temp->link = head;
head = temp;
}
size++;
}
int ShoppingMallList::getsize()
{
return size;
}
void ShoppingMallList::Print()
{
ShoppingMall* temp = head;
while ( temp != 0 )
{
std::cout << "Name: " << temp->name << std::endl << "Shop Number: " << temp->shopNumber << std::endl << "Brand Shop: " << temp->brandshop << std::endl << "Floor: " << temp->floor << std::endl << "Shop Type: " << temp->shopType << std::endl;
temp = temp->link;
}
}
void ShoppingMallList::Insert(std::string& name, int& shopNumber, std::string& brandShop, int& floor, std::string& shoptype)
{
ShoppingMall* newShop = new ShoppingMall(name, shopNumber, brandShop, floor, shoptype);
//case-1 EmptyList
if ( head == 0 )
{
head = newShop;
}
else
{
ShoppingMall* temp = head;
ShoppingMall* previous = 0;
// Traversing link to find insert location
while (temp!=0)
{
if ( temp->name >= newShop->name )
{
break;
}
else
{
previous = temp;
temp = temp->link;
}
}
//case-2 Adding To Head
if ( temp == head )
{
newShop->link = head;
head = newShop;
}
//case-3 Adding After Head
else
{
newShop->link = temp;
previous->link = newShop;
}
}
size++;
}
void ShoppingMallList::deleteShop(std::string& name)
{
ShoppingMall* temp=head;
ShoppingMall* previous = 0;
if (head == 0)
{
//Case-1 If There is no node
std::cout << "Shop cannot be deleted becasue the there no Node " << std::endl;
}
//Traversing Node to find node to delete
while (temp!=0)
{
if ( temp->name == name )
{
break;
}
else
{
previous = temp;
temp = temp->link;
}
}
//case-2 If Shop with name passed not found
if ( temp == 0 )
{
std::cout << "Shop of name " << name << " not found!" << std::endl;
}
else
{
//case-3 Delete node from head Node
if ( temp == head )
{
head = head->link;
}
//delete other than head shop
else
{
previous->link = temp->link;
}
delete temp;
size--;
}
}
void ShoppingMallList::search(std::string& name)
{
ShoppingMall* tempShop = head;
while ( tempShop != 0 )
{
if (tempShop->name == name)
{
std::cout << "Name: " << tempShop->name << std::endl << "Shop Number: " << tempShop->shopNumber << std::endl << "Brand Shop: " << tempShop- >brandshop << std::endl << "Floor: " << tempShop->floor << std::endl << "Shop Type: " << tempShop->shopType << std::endl;
}
else
{
tempShop = tempShop->link;
}
}
if ( tempShop == 0 )
{
std::cout << "Shop of name " << name << " not found!" << std::endl;
}
}
link field of ShoppingMall class is not initialized in constructor and contains some random rubbish. All list iterations like:
while ( temp != 0 )
{
// Code skipped for simplicity
temp = temp->link;
}
could cause Access Violation because condition temp != 0 never met and skipped code access memory at random address.
To fix it:
ShoppingMall::ShoppingMall(const std::string& name, int shopNumber, std::string& brandShop, int floor, const std::string& shoptype)
: link(nullptr), name(name), shopNumber(shopNumber), brandshop(brandShop), floor(floor), shopType(shoptype)
{
}

Trying to make string array passed through methods C++

I'm trying to read names and ages from user, until user inputs "stop". Then just print all these values. Please help me , I'm just the beginner in C++
// Pass.cpp
// Reading names and ages from user and outputting them
#include <iostream>
#include <iomanip>
#include <cstring>
using std::cout;
using std::cin;
using std::endl;
using std::setw;
using std::strcmp;
char** larger(char** arr);
int* larger(int* arr);
void read_data(char*** names, int** ages);
void print_data(char*** names, int** ages);
int main()
{
char** names = new char*[5];
char*** p_names = &names;
int* ages = new int[5];
int** p_ages = &ages;
read_data(p_names,p_ages);
print_data(p_names,p_ages);
}
void read_data(char*** names, int** ages)
{
const char* sent = "stop";
const int MAX = 15;
int count = 0;
char UI[MAX];
cout << "Enter names and ages."
<< endl << "Maximum length of name is " << MAX
<< endl << "When stop enter \"" << sent << "\".";
while (true)
{
cout << endl << "Name: ";
cin.getline(UI,MAX,'\n');
if (!strcmp(UI, sent))
break;
if (count + 1 > sizeof (&ages) / sizeof (&ages[0]))
{
*names = larger(*names);
*ages = larger(*ages);
}
*names[count] = UI;
cout << endl << "Age: ";
cin >> *ages[count++];
}
}
void print_data(char*** names, int** ages)
{
for (int i = 0; i < sizeof(*ages) / sizeof(*ages[0]);i++)
{
cout << endl << setw(10) << "Name: " << *names[i]
<< setw(10) << "Age: " << *ages[i];
}
}
char** larger(char** names)
{
const int size = sizeof(names) / sizeof(*names);
char** new_arr = new char*[2*size];
for (int i = 0; i < size; i++)
new_arr[i] = names[i];
return new_arr;
}
int* larger(int* ages)
{
const int size = sizeof(ages) / sizeof(*ages);
int* new_arr = new int[2 * size];
for (int i = 0; i < size; i++)
new_arr[i] = ages[i];
return new_arr;
}
You are really over complicating things.
Given the original problem:
Write a program that reads a number (an integer) and a name (less than
15 characters) from the keyboard. Design the program so that the data
is done in one function, and the output in another. Store the data in
the main() function. The program should end when zero is entered for
the number. Think about how you are going to pass the data between
functions
The problem wants you to think about passing parameters to functions. A simple solution would be:
#include "stdafx.h"
#include <iostream>
#include <iomanip>
using namespace std;
// Pass in a char array and an integer reference.
// These values will be modified in the function
void read_data(char name[], int& age)
{
cout << endl << "Age: ";
cin >> age;
cin.ignore();
cout << endl << "Name: ";
cin.getline(name, 16);
}
// Pass a const array and an int value
// These values will not be modified
void print_data(char const *name, int age)
{
cout << endl << setw(10) << "Name: " << name
<< setw(10) << "Age: " << age;
}
int main()
{
char name[16];
int age;
cout << "Enter names and ages."
<< endl << "Enter 0 age to quit.";
do {
read_data(name, age);
print_data(name, age);
} while (0 != age)
}
EDIT: Modified per user3290289's comment
EDIT2: Storing data in an array
// Simplify by storing data in a struct (so we don't have to manage 2 arrays)
struct Person {
char name[16];
int age;
};
// Returns how many People were input
int read_data(Person*& arr)
{
int block = 10; // How many persons to allocate at a time
arr = NULL;
int arr_size = 0;
int index = 0;
while (true) {
if (index == arr_size) {
arr_size += block;
arr = (Person *)realloc(arr, arr_size * sizeof(Person)); // Reallocation
// Should check for error here!
}
cout << endl << "Age: ";
cin >> arr[index].age;
cin.ignore();
if (0 == arr[index].age) {
return index;
}
cout << endl << "Name: ";
cin.getline(arr[index++].name, 16);
}
}
void print_data(Person *arr, int count)
{
for (int i = 0; i < count; i++) {
cout << endl << setw(10) << "Name: " << arr[i].name
<< setw(10) << "Age: " << arr[i].age;
}
}
int main()
{
Person *arr;
int count = read_data(arr);
print_data(arr, count);
free(arr); // Free the memory
}
try this:
#include <iostream>
#include <iomanip>
#include <vector>
#include <sstream>
using std::cout;
using std::cin;
using std::endl;
using std::setw;
using std::strcmp;
void read_data(std::vector<std::string> &names, std::vector<int> &ages);
void print_data(std::vector<std::string> &names, std::vector<int> &ages);
int main()
{
std::vector<std::string> names;
std::vector<int> ages;
read_data(names, ages);
print_data(names, ages);
}
void read_data(std::vector<std::string> &names, std::vector<int> &ages)
{
const char* sent = "stop";
cout << "Enter names and ages."
<< endl << "When stop enter \"" << sent << "\".";
while (true)
{
std::string input;
cout << endl << "Name: ";
std::getline(cin, input);
if (!strcmp(input.c_str(), sent))
break;
names.push_back(input);
cout << endl << "Age: ";
std::string age;
std::getline(cin, age);
ages.push_back(atoi(age.c_str()));
}
}
void print_data(std::vector<std::string> &names, std::vector<int> &ages)
{
for (int i = 0; i < names.capacity() ; i++)
{
cout << endl << setw(10) << "Name: " << names.at(i)
<< setw(10) << "Age: " << ages.at(i);
}
}
One problem I see is this if statement:
if (count + 1 > sizeof (&ages) / sizeof (&ages[0]))
&ages is the address of an int**, a pointer, and so it's size is 8 (usually) as that is the size of a pointer type. The function does not know the size of the array, sizeof will only return the correct answer when ages is declared in the same scope.
sizeof(&ages) / sizeof(&ages[0])
will always return 1
I believe one natural solution about this problem is as follows:
create a "std::map" instance. Here std::map would sort the elements according to the age. Here my assumption is after storing the data into the container, you would like to find about a particular student age/smallest/largest and all various manipulation with data.Just storing and printing the data does not make much sense in general.
create a "std::pair" and take the both input from the user into the std::pair "first" and "second" member respectively. Now you can insert this "std::pair" instance value into the above "std::map" object.
While printing, you can now fetch the each element of "std::map" in the form of "std::pair" and then you can display pair "first" and "second" part respectively.

Disappearing of object inside variable of another object

I got strange program behaviour and crashing.
I created class 'List', with array of pointers to objects of class 'Student'. I observe that I succesfully called 'Student' object in 'List' constructor. But I'm unable to call 'Student' object from any other 'List' methods.
I even checked the same line for testing inside 'List' constructor and 'push' method, resulting in program crash.
Here is testing line: cout << (studentBox[numb] -> getRef()) << endl;
Here is the problematic part of code:
#include <iostream>
using namespace std;
class Student
{
private:
int referenceNumb;
int markNumb;
public:
Student();
Student(int, int);
~Student();
int getRef();
int getMark();
};
class List
{
private:
int numb;
Student* studentBox[1000];
public:
List();
~List();
void push(int, int);
int getAVG();
};
int main()
{
List* base = NULL;
int x, y;
char mod;
do
{
cout << "Waiting for orders." << endl;
cout << "1 - Quit," << endl;
cout << "2 - Add new student," << endl;
cout << "3 - Calculate average mark," << endl;
cout << "0 - Create new list." << endl;
cin >> mod;
switch(mod)
{
case '0': base = new List(); break;
case '1': cout << "Bye."; break;
case '2':
if(base != NULL)
{
cout << "Specify student's reference number: "; cin >> x;
cout << "Specify student's mark: "; cin >> y;
base->push(x, y);
}
else cout << "List does not exist!" << endl;
break;
case '3':
if(base != NULL)
{
cout << "Average mark is equal: " << base->getAVG();
}
else cout << "List does not exist!";
cout << endl;
break;
default: cout << "Correct command required!" << endl; break;
}
}
while(mod!='1');
return 0;
}
Student::Student()
{
referenceNumb = NULL;
markNumb = NULL;
}
Student::Student(int r, int m)
{
referenceNumb = r;
markNumb = m;
}
Student::~Student()
{
referenceNumb = NULL;
markNumb = NULL;
cout << "pusto." << endl;
}
int Student::getRef()
{
return referenceNumb;
}
int Student::getMark()
{
return markNumb;
}
List::List()
{
int numb = 0;
studentBox[numb] = new Student();
cout << (studentBox[numb] -> getRef()) << endl;
}
List::~List()
{
}
void List::push(int x, int y)
{
cout << (studentBox[numb] -> getRef()) << endl;
if(studentBox[numb] != NULL)
{
studentBox[numb] = new Student();
cout << (studentBox[numb] -> getRef()) << endl;
}
else cout << "Hujnia" << endl;
}
int List::getAVG()
{
int temp = 0;
for(int i=0; i<numb; i++)
{
temp += studentBox[i]->getMark();
}
return (temp / numb);
}
There are a couple of major problems that I see. The first is that the numb member of the List isn't initialized.
List::List()
{
int numb = 0; // this creates a new local variable called numb, it doesn't
// initialize the numb member.
studentBox[numb] = new Student();
cout << (studentBox[numb] -> getRef()) << endl;
}
Do this instead:
List::List()
: numb(0) // initialize the numb member to zero.
{
studentBox[numb] = new Student();
cout << (studentBox[numb] -> getRef()) << endl;
}
Another problem is that numb appears to be meant to indicate the size of the list, but it is never changed when a new student is added.