Note - I have searched a lot on pointers and references for C++.
I don't seem to understand them in THIS particular scenario. Hence posting it here!
The following is CORRECT code. It is working. I wrote this for an online C++ practice problem. A part of the code was given to me initially.
I don't understand why an array of Person objects is being created in the main function with a *per[n] as shown below:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
class Person {
string name;
int age;
public:
Person(){
name = "";
}
virtual void putdata() = 0;
virtual void getdata() = 0;
};
class Professor: public Person {
int publications, cur_id;
string name;
int age;
public:
static int professorCount;
Professor(){
name = "";
age = 0;
publications = 0;
cur_id = professorCount + 1;
professorCount++;
}
void getdata(){
cin >> name >> age >> publications;
}
void putdata(){
cout << name << " " << age << " " << publications << " " << cur_id << endl;
}
};
class Student: public Person {
int marks[6];
int cur_id;
string name;
int age;
public:
static int studentCount;
Student(){
name = "";
age = 0;
cur_id = studentCount + 1;
studentCount++;
}
void getdata(){
cin >> name >> age >> marks[0] >> marks[1] >> marks[2] >> marks[3] >> marks[4] >> marks[5];
}
void putdata(){
cout << name << " " << age << " " << marks[0] + marks[1] + marks[2] + marks[3] + marks[4] + marks[5] << " " << cur_id << endl;
}
};
int Professor::professorCount = 0;
int Student::studentCount = 0;
In this main function below, an array of Person objects is being created, but it is given a * in the beginning. How is it working?
int main(){
int n, val;
cin>>n; //The number of objects that is going to be created.
Person *per[n]; // THIS ONE RIGHT HERE! THIS ONE!
for(int i = 0;i < n;i++){
cin>>val;
if(val == 1){
// If val is 1 current object is of type Professor
per[i] = new Professor;
}
else per[i] = new Student; // Else the current object is of type Student
per[i]->getdata(); // Get the data from the user.
}
for(int i=0;i<n;i++)
per[i]->putdata(); // Print the required output for each object.
return 0;
}
I don't understand why an array of Person objects is being created in the main function with a *per[n] as shown below
The purpose of storing a pointer is to support virtual polymorphism (abstract classes like Person cannot be instantiated). A smart pointer serves that as well, but takes care about the correct dynamic memory management.
There's no need to use raw pointers or raw arrays in c++ at all. That code doesn't give a good example of "best practices".
At the main() function
Person *per[n]; // Note that VLA's aren't standard c++ syntax
should be replaced with
std::vector<std::unique_ptr<Person>> per(n);
and the loop accordingly
for(int i = 0;i < n;i++){
cin>>val;
if(val == 1){
// If val is 1 current object is of type Professor
per[i] = std::make_unique<Professor>();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
// Else the current object is of type Student
else per[i] = std::make_unique<Student>();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
per[i]->getdata(); // Get the data from the user.
}
Also
int marks[6];
should be replaced with
std::array<int,6> marks;
std::array is way more convenient and less error prone when passed as function parameter, etc.
You're creating an array of pointers to Person objects. That's how assignments like per[i] = new Professor; can work - new Professor returns a pointer to a Professor object, so you need an array of pointers to store that.
Related
#include <iostream>
using namespace std;
class car{
string owner;
string car_num;
string issue_date;
car(string o, string cn, string id)
{
owner = o;
car_num = cn;
issue_date = id;
}
void getInfo()
{
cout << "Car's Owner's Name : " << owner << endl;
cout << "Cars' Number : " << car_num << endl;
cout << "Car's Issue Date : " << issue_date << endl;
}
};
int main()
{
int n;
cout << "Enter total number of cars stored in your garage : \n";
cin >> n;
car c1[n]; //incomplete code due to the issue
return 0;
}
Here I want to take the total car numbers from user. And also want to take the car properties from user by using a loop. But how Can I do that while using a constructor?
My advice is not to over use the constructor. It supposed to construct, and really should only construct. In your case, you don't even really need a constructor.
Instead add a new function to do initialization.
Traditional is to use an operator >> which is often an external function.
As for the loop...
car c1[n]; //incomplete code due to the issue
is not legal C++ (although it's allowed in C, and many compilers that are also C compilers)
It's better to use a vector. So...
vector<car> c1(n);
for (auto& c : c1)
cin >> c;
An advanced technique is to use a istream iterator, which will allow you to use algorithms like std::copy, calling the input operator for each member of the vector. However, it's really not required, just a "nicety"
car c1[n]; //incomplete code due to the issue
In fact, you have 2 issues here:
Variable-Length Arrays (VLA) are not allowed in standard C++. They
are optionally allowed in standard C, and are supported by some
C++ compilers as an extension.
You can't have an array of objects w/o default constructor (unless you fully initialize it).
Assuming you don't want to change the class (other than insert public: after the data members), the modern solution should use std::vector:
std::vector<car> c;
//incomplete part
for(int i = 0; i < n; i++){
std::string owner, car_num, issue_date;
//TODO: get the strings from the user here ...
c.emplace_back(owner, car_num, issue_date);
}
Use pointer array instead.e.g.
car* c1[n];
//incomplete part
for(int i = 0; i < n; i++){
//take input and process
c1[i] = new car(//put processed inputs here);
}
PS: I feel like I made a mistake somewhere but can't test it now. If it doesn't work, put a comment here.
You can use loop with std::cin, likefor(int i=0;i<n;++i){std::cin<<num;}. The 'n' I mentioned in the code can also be assigned by std::cin
int n;
std::cin>>n;
car* cars=new car[n];
for(int i=0;i<n;++i)
{
std::getline(cars[i].owner,std::cin);
// and something other you'd like to do, like to test its validity
}
#include <iostream>
using namespace std;
class car{
public:
string owner;
string car_num;
string issue_date;
void cars(string o, string cn, string id)
{
owner = o;
car_num = cn;
issue_date = id;
getInfo();
}
void getInfo()
{
cout << "Car's Owner's Name : " << owner << endl;
cout << "Cars' Number : " << car_num << endl;
cout << "Car's Issue Date : " << issue_date << endl;
}
};
int main()
{
int n;
string a,b,c;
cout << "Enter total number of cars stored in your garage : \n";
cin >> n;
car cas[n]; //incomplete code due to the issue
for(int i=0;i<n;++i)
{
cout<<"value1:";
cin>>a;
cout<<"value2:";
cin>>b;
cout<<"value3:";
cin>>c;
cas[i].cars(a,b,c);
}
return 0;
}
I'm collecting names and test scores to populate a vector. Both the function and main method can't recognize the struct's members. How can I get it to see the members? Or is there a better way to populate a vector of structs with user input using a function?
I've searched other similar posts, but it seems like it's just a simple code error I missed.
#include <iostream>
#include <vector>
using namespace std;
const int classSize = 1;
struct StudentType {
string studentFName;
string studentLName;
int testScore;
char grade;
};
vector<StudentType> collectStudentData(vector<StudentType> students[classSize]) {
for (int i = 0; i < classSize; i++) {
cout << "Student " << i << "'s name and test score" << endl;
cin >> students[i].studentFName >> students[i].studentLName >> students[i].testScore;
}
return students[classSize];
};
int main() {
vector<StudentType> students[classSize] = {};
students[classSize] = collectStudentData(students);
cout << students[1].studentFName << students[1].studentLName << students[1].studentFName;
};
'studentFName': is not a member of 'std::vector>'
This line creates an array of vectors:
vector<StudentType> students[classSize] = {};
What you want is this a single vector:
vector<StudentType> students;
Where that gets initialized to a zero-length array.
When it comes to adding data you don't need to return from the other method, you can pass in a reference and add to it:
void collectStudentData(vector<StudentType>& students) {
for (int i = 0; i < classSize; i++) {
// Read in one at a time
StudentType student;
cout << "Student " << i << "'s name and test score" << endl;
cin >> student.studentFName >> student.studentLName >> student.testScore;
// Add to the array
students.push_back(student);
}
}
Ideally classSize is either passed in as an argument, or you just type a blank line to end input. Using a global variable is really messy and should be strongly discouraged.
vector<StudentType> students[classSize]
Is one issue. You are not declaring a function that takes a vector, you are declaring a function that takes an array of vectors.
Secondly, if you only applied that change you would be passing an empty vector, you can initialize vector to be a particular size by passing in the size to the constructor.
Furthermore, it seems that you would benefit from passing the students vector by reference
vector<StudentType>& students
instead, the & creates a reference. Right now your code is copying the vector when it is passed into the function
#include <iostream>
#include <vector>
using namespace std;
const int classSize = 1;
struct StudentType {
string studentFName;
string studentLName;
int testScore;
char grade;
};
void collectStudentData(vector<StudentType>& students) {
for (int i = 0; i < classSize; i++) {
cout << "Student " << i << "'s name and test score" << endl;
cin >> students[i].studentFName >> students[i].studentLName >> students[i].testScore;
}
return students;
};
int main() {
vector<StudentType> students{classSize};
collectStudentData(students);
cout << students[0].studentFName << students[0].studentLName << students[0].studentFName;
};
If you wanted to improve the code further, you would use an iterator in the for loop instead, and preferably you wouldn't need to construct the vector in main, and pass it into a function to mutate it. You could just construct it and return it from the function.
I need to make a dynamic array in C++, and ask a user to input a name until the user types exit.
It should keep asking for more and more names, recording them to a dynamic string array, then randomly choosing as many names as the user wants from the list.
I should be able to figure out the random numbers part, but the continuous input is giving me issues. I'm not sure how to have the length variable continue changing values.
#include <iostream>
#include <string>
using namespace std;
int main()
{
int length;
string* x;
x = new string[length];
string newName;
for (int i = 0; i < length; i++)
{
cout << "Enter name: (or type exit to continue) " << flush;
cin >> newName;
while (newName != "exit")
{
newName = x[i];
}
}
cout << x[1] << x[2];
int qq;
cin >> qq;
return 0;
}
Any help would be greatly appreciated.
A few errors:
length is never assigned a value
You're overwriting newName with an unassigned value x[i] of the array in newName = x[i];
x is never dynamically reassigned with a new array of different length
Let's consider a solution:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int length = 2; // Assign a default value
int i = 0; // Our insertion point in the array
string* x;
x = new string[length];
string newName;
cout << "Enter name: (or type exit to continue) " << flush;
cin >> newName; // Dear diary, this is my first input
while (newName != "exit")
{
if (i >= length) // If the array is bursting at the seams
{
string* xx = new string[length * 2]; // Twice the size, twice the fun
for (int ii = 0; ii < length; ii++)
{
xx[ii] = x[ii]; // Copy the names from the old array
}
delete [] x; // Delete the old array assigned with `new`
x = xx; // Point `x` to the new array
length *= 2; // Update the array length
}
x[i] = newName; // Phew, finally we can insert
i++; // Increment insertion point
cout << "Enter name: (or type exit to continue) " << flush;
cin >> newName; // Ask for new input at the end so it's always checked
}
cout << x[1] << x[2]; // Print second and third names since array is 0-indexed
int qq;
cin >> qq; // Whatever sorcery this is
return 0;
}
Addressing the errors mentioned:
length is assigned a default value at the start
Reverse the direction to get x[i] = newName;
x is dynamically assigned a new array of exponentially-increasing length
Happy learning!
I am currently trying to write some function which will iterate through a dynamic array which holds students records in this format:
Name ID Age
Once this function finds the youngest age, return this as a pointer to the main function and output it.
The problem is the function is of type Student, which is my structure; and is formatted like so:
struct Student{
string name;
string id;
int age;
};
I am struggling to return the pointer (ptr) and output it to the console, as currently it is outputting (what I think) is the memory location...
Here is my code so far,
Any advice will be very helpful.
The structure:
struct Student{
string name;
string id;
int age;
};
The function call:
cout << "Youngest: " << youngest(student_Dynamic, sizeOf) << endl;
And the function:
Student* youngest(Student* s, int size)
{
int tempAge = 0;
int youngestAge = 100;
Student *pt = new Student;
for (int i = 0;i < size;i++)
{
tempAge = (s+i)->age;
if (tempAge < youngestAge)
{
youngestAge = tempAge;
pt->age = youngestAge;
}
}
return pt; //Here I am trying to return the pointer so that it outputs the youngest age
//to the console window...
}
UPDATE:
This question has now been answered by 'Billy Pilgrim'
Thankyou everyone for the advice!
You are returning the pointer, which is what is being printed. It should be something like:
Student * s = youngest(student_Dynamic, sizeOf);
cout << "Youngest: " << s->name << endl;
(Not sure what sizeOf is:).
Ok, so my pointer logic is a little flawed, but I'm working on it. My problem is in the main.cpp file below, Inside the getStructData() function. I have the questions listed down there in comments, and what I think seems right, but know it's not. I will now put the question up here, out of the comments.
I have a function getMyStructData(), I can currently print out the elements of a specific struct based on an index number. Instead I'd like to copy the elements of that struct at the given index number (int structureArrayIndex) from the private structure into the structure of the pointer argument.
Inside myStructure.h
struct myStructure
{
int myInteger;
double myDoublesArray[5];
char myCharArray[80];
};
Inside myClass.h
#include "myStructure.h"
class myClass
{
private:
myStructure myStruct[5]
private:
Prog1Class();
~Prog1Class();
void setMyStructData();
void getMyStructData(int structureArrayIndex, struct myStructure *info);
};
Inside main.cpp
#include<iostream>
#include <string>
#include "myClass.h"
#include "myStructure.h"
using namespace std;
void myClass::setMyStructData()
{
for(int i = 0; i < 5 ; i++)
{
cout << "Please enter an integer: " << endl;
cin >> myStruct[i].myInteger;
for(int j = 0; j< 5; j++)
{
cout << "Please enter a double: ";
cin >> myStruct[i].myDoublesArray[j];
}
cout << endl << "Please enter a string: ";
cin.ignore(256, '\n');
cin.getline(myStruct[i].myCharArray, 80, '\n');
}
}
void Prog1Class::getStructData(int structureArrayIndex, struct myStructure *info)
{
//****Below I have what's working, but Instead of just printing out the elements, what I want to do is copy the elements of that struct at the given index number (int structureArrayIndex) from that private structure into the structure of the pointer argument.
//I'm guessing something like this:
// info = &myStructure[structureArrayIndex];
//I know that's wrong, but that's where I'm stuck.
//****Here is how I would print out all of the data using the int structureArrayIndex
cout << myStruct[structureArrayIndex].myInteger << endl;
for (int k = 0; k < 5; k++)
{
cout << myStruct[structureArrayIndex].myDoublesArray[k] << endl;
}
cout << myStruct[structureArrayIndex].myCharArray << endl;
}
int main(void)
{
myClass c;
c.setMyStructData();
c.getStructData(1);
cin.get();
}
In your commented code, you are assigning pointers and not an actual copy of the data.
To do what you ask with the code you provided you may do:
// Check that info isn't null
if (!info) {
return;
}
// Simple copy assignment of private structure to info.
*info = myStruct[structureArrayIndex];
This dereferences the pointer info and does a default copy operation of the myStructure type in myStruct array at the structureArrayIndex.
You have to assign content of myStruct[structureArrayIndex] to content of info.
*info = myStruct[structureArrayIndex];