Pointer Array usage - c++

I have a Movie class which has constructor takes 7 parameter like this;
Movie:: Movie(string ttle,string sts ,double prc,int yr,string gnr,Date rls,int id)
I would like to use dynamic memory for an movie array but it gives error and i could not find it
int main() {
int counter=0; // size of array
Movie *moviearray;
moviearray= new Movie[counter];
ifstream filein("DVD_list.txt");
for (string line; getline(filein, line); )
{
counter++;
vector<string> v;
split(line, '\t', v); // v is an vector and puts string words that has splitted based on tab
moviearray[counter] =(v[0],v[1] ,stod(v[2]),stoi(v[3]),v[4],Date(v[5]),stoi(v[6])); // ERROR
How can I create an movie object in that array?

This:
int counter=0; // size of array
moviearray= new Movie[counter];
Does not make sense. You are allocating an array of zero objects. Later you use it. This is illegal.
Instead, try:
std::vector<Movie> movies;
Then in your loop:
movies.push_back(Movie(v[0],v[1] ,stod(v[2]),stoi(v[3]),v[4],v[5],stoi(v[6])));

Related

How do you use arrays of objects as parameters? C++

Im trying to pass an arrays of objects to a function so that it can be filled with the contents of a text file.
Update: Removed _menu[] from the function parameters and also from main. The code compiles just fine, but now it crashes right after openMenu asks for the cin to the filename.
code:
class Dish {
public:
int _itemNo;
string _category;
string _description;
double _price;
Dish();
Dish(int itemNo, string category, string description,
double price);
}
class DishDb{
private:
int _nElems;
public:
Dish _menu[20];
void openMenu(ifstream &fromFile);
};
void DishDb::openMenu(ifstream &fromFile){
string fileName;
int itemNo;
double price;
string description;
string category;
int numOfDishes = 0;
cout << "Enter file name: ";
cin >> fileName;
ifstream inFile(fileName);
do{
inFile >> itemNo;
_menu[numOfDishes]._itemNo = itemNo;
getline(inFile, category, ':');
_menu[numOfDishes]._category = category;
getline(inFile, description, ':');
_menu[numOfDishes]._description = description;
inFile >> price;
_menu[numOfDishes]._price = price;
numOfDishes++;
}while(!inFile.eof());
inFile.close();
cout << endl << "Menu was loaded.";
}
int main(){
string filename;
cout << "Enter today's transaction file name: ";
cin >> filename;
DishDb DDb;
ifstream inFile;
Dish _menu[20];
DDb.openMenu(inFile);
DDb.display();
return 0;
}
No errors for some reason
By default, arguments in C++ are passed by value.
By the phrasing of your question it seems like you are trying emulate pass-by-reference which is default in many other languages.
What you want to do in that case is have the function accept either a pointer (Dish* dishArr) or reference (Dish& dishArr) to the array. In either case, you can then use the pointer/reference to access the memory where the object resides from inside the function.
Note you will likely want to also pass in the size of the array so that you don't go out of the bounds of the array.
Pointer Example
void mutateDishArray(Dish* dishPtr, int numDishes) {
for(int i = 0; i < numDishes; ++i) {
dishPtr[i] = Dish(); // dereferencing the pointer using the array syntax
// this is equivalent to writing *(dishPtr+i) = Dish(); using the dereference operator '*'
}
}
int main() {
Dish dishArray[10]; // an array with memory for 10 dishes on the stack
mutateDishArray(dishArray, 10); // pass a pointer to the array (an array reference will decay into a pointer so we don't need the address-of operator '&')
}
That answers your question, but to fit your class layout, you may want to alter your code as follows.
You have a member definition for Dish _menu[20] array in the DishDb class, but you never initialize it with a constructor. Instead, you create a Dish _menu[20] array in main(). That array is outside the scope of the method DishDb::openMenu and not at all related to the Dish _menu[20] array defined in the Dish class.
class DishDb{
private:
int _nElems;
int _menuSize;
Dish* _menu;
public:
DishDb();
void openMenu(ifstream &fromFile);
};
DishDb::DishDb(Dish* _menu, int _menuSize)
: _nElems(0) // this is a 'member initializer-list'
, _menuSize(_menuSize)
, _menu(_menu)
{
}
Now, the DishDb constructor will accept a pointer to the array you had already made in main() and its member methods will have access to it through that pointer.
int main(){
string filename;
cout << "Enter today's transaction file name: ";
cin >> filename;
Dish _menu[20];
DishDb DDb(_menu, 20); // The DishDb is now constructed with a pointer to the _menu array on the stack
ifstream inFile;
DDb.openMenu(inFile);
DDb.display();
}
More on member initializer lists: https://en.cppreference.com/w/cpp/language/initializer_list
Here is a trivial example of using an array as a parameter for a function, for reference:
#include <iostream>
void func(int intArr[], unsigned int arrLength) {
for(unsigned int i = 0; i < arrLength; i++) {
std::cout << intArr[i] << '\n';
}
}
int main(int argc, char* argv[]) {
const unsigned int SIZE = 10;
int myInts[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
func(myInts, SIZE);
return 0;
}
Behind the scenes, arrays are treated as pointers when passed into a function. The parameter int intArr[] could have been int *intArr with no change in effect. Incidentally, I see that you made your array of Dish objects a public variable, but you should really make it private because half the reason we encapsulate data within classes is to make sure that other code (that has no business altering our data) cannot change it directly. Instead, you should add a method that can update the array after performing its own checks and another method that can pass out a pointer to the array.
A couple other things to possibly revisit:
Class definitions must end with a semicolon, but you are missing one at the end of your class Dish definition.
!inFile.eof() is actually a really bad test to use to see if you have reached the end of a file. This is because inFile.eof() will only return true after you have attempted to read past the end of the file, but if you try to read past the end of a file you will get a segfault. Rather, you will want a loop condition that will guarantee that the next read from the file you perform is a valid read. You can accomplish this with a loop similar to:
while(inFile >> itemNo && getline(inFile, category, ':') && getline(inFile, description, ':') && inFile >> price){
_menu[numOfDishes]._itemNo = itemNo;
_menu[numOfDishes]._category = category;
_menu[numOfDishes]._description = description;
_menu[numOfDishes]._price = price;
numOfDishes++;
}
I would highly recommend reading this post on Stack Overflow for a better explanation about why this works better.
It looks like you're probably using using namespace std; somewhere outside of what you showed us, but this is considered bad practice. You won't always run into problems when using it, but as you go on to make larger projects the danger level goes up pretty quickly. This other post on Stack Overflow gives a good explanation of why.

How to read substring with ifstream C++

This is content of my file txt:
1 Joey 1992
2 Lisa 1996
3 Hary 1998
And I have a struct:
struct MyStruct
{
int ID;
char *Name;
int Old;
};
I have a main () as this:
int main ()
{
MyStruct *List;
int Rows, Columns;
ReadFile (List, Rows, Columns, "file.txt");
return 0;
}
Now, I want to write a function ReadFile to get information from file txt and store into a List, beside store Rows and Colums:
void ReadFile (MyStruct *&List, int &Rows, int &Colums, char const *path)
{
// need help here
}
I know how to use ifstream to read integer from txt, but I don't know how to read substring, such as:
"Joey", "Lisa" and "Hary"
to store each into char *Name.
Please help me. Thanks so much !
You seem to work on old school exercises: you use arrays and c-string to store data elements, with all the hassle of manual memory management.
A first (old-school) approach
I'll use only very basic language features and avoid any modern C++ features
void ReadFile (MyStruct *&List, int &Rows, int &Colums, char const *path)
{
const int maxst=30; // max size of a string
Rows=0; // starting row
ifstream ifs(path);
int id;
while (ifs>>id) {
MyStruct *n=new MyStruct[++Rows]; // Allocate array big enough
for (int i=0; i<Rows-1; i++) // Copy from old array
n[i] = List[i];
if (Rows>1)
delete[] List; // Delete old array
List = n;
List[Rows-1].ID = id; // Fill new element
List[Rows-1].Name = new char[maxst];
ifs.width(maxst); // avoid buffer overflow
ifs>>List[Rows-1].Name; // read into string
ifs>>List[Rows-1].Old;
ifs.ignore(INT_MAX,'\n'); // skip everything else on the line
}
}
This assumes that List and Rows are uninitialized when the function is called. Note that Columns is not used here.
Note that you'll have to clean the mess when you no longer need the List: you have first to delete all the Name and then delete List.
How to do it in more modern C++
Nowadays, you'd no longer use char* but string:
struct MyStruct {
int ID;
string Name;
int Old;
};
And you wouldn't use an array for keeping all the items, but a container such as vector:
int main ()
{
vector<MyStruct> List;
ReadFile (List, "file.txt"); // no nead for Rows. It is replaced by List.size()
return 0;
}
And then you'd read it like this:
void ReadFile (vector<MyStruct>& List, string path)
{
ifstream ifs(path);
MyStruct i;
while (ifs>>i.ID>>i.Name>>i.Old) {
List.push_back(i); // add a new item on list
ifs.ignore(INT_MAX,'\n'); // skip everything else on the line
}
}
No worries about memory management; no worries about maximum size of strings.

Split a string inside a class constructor

I have a class with 2 data members: size and an array of ints (dynamically allocated). The purpose of the class is to create an array of a size and fill it with values. The task is to create a constructor that takes a string as its parameter, but the string looks like this: "12|13|14|15" etc. I have searched this but all the solutions are a little too complicated, as they involve vectors and we haven't started with vectors yet. I basically want to put these numbers into the array of ints, 1 by 1 and also find out the size of the array. How can I do that? I tried messing with getline and stringstream but that gave me a load of errors. My code looks like this.
#include <string>
#include <iostream>
#include <sstream>
using namespace std;
class IntArrays {
private:
static int objcount;
int size;
public:
int *arrayints;
const static int objcountf();
IntArrays(int);
IntArrays(const IntArrays &p){
size = p.size;
for (int i = 0;i <size;i++){
arrayints[i] = p.arrayints[i];
}
}
IntArrays(std::string f){
// ignore the other constructors, this is the constructor that is giving me trouble
int counter =0;
istringstream inStream(f);
string newstring;
while (getline(iss,newstring, '|')){
arrayints[counter] = stoi(newstring);
counter++;}
void enternums();
(note that this is only the header file, and that the current string constructor I have there does not work.
This code is my version. I prefer to use a vector rather than a raw array.
Class definition:
class IntArrays {
public:
IntArrays(const string&, const char&);
const vector<int>& data() { return _data; }
const int size() { return _data.size(); }
private:
vector<int> _data;
};
The following is the constructor implementation:
IntArrays::IntArrays(const string& str, const char& delimiter) {
string buff;
for(auto& n:str) {
if(n != delimiter) buff+=n; else
if(n == delimiter && buff != "") {
_data.push_back(stoi(buff));
buff = "";
}
}
if(buff != "") _data.push_back(stoi(buff));
}
And then we just use the class:
IntArrays a("1|4|9|6|69", '|');
vector<int> da = a.data();
IntArrays b("1,4,9,6,69", ',');
vector<int> db = b.data();
I will try to have a recursion for that =p
Sorry that I cannot provide a c++ version =p..
This is a java version i guess.
list parse(string data, list base) {
if (data.length > 0) {
string s = data.subStr(0,1);
if (s == "|") {
base.push(0); //set the initial value for a new value
} else {
int i = parseInt(s);
int result = base.pop()*10 + i; //recalculate the result
base.push(result);
}
return parse(data.subStr(1),base); //recursion
} else {
return base; //return the result
}
}
As Joachim pointed out, you do not initialize the pointer. Unfortunately, you do not have the size of the array before the allocation, so you are left with a few solutions:
process the input twice (really bad if you have a large number of entries); On the first pass, count the inputs. Then allocate the array, then read them again, into the allocated array.
read the inputs into a linked list; Each element in the list would hold a value, and the address of the next element.
Preallocate a block of memory and hope it is large enough to read the entire array. If it is not, reallocate a larger block and copy the already read values into it, then discard the initial block (this is what std::vector does).

Returning array from function with data from file

I got a C++ program with which I insert the information in a file. I got a second one ( this one ) program to get the data. My goal is to get all the data and return it as array with type Student. In the GetFromFile method I'm getting the information and I can print it, but how I can return it and use it like this in the main function:
int size;
Student *students = getFromFile( "D:\\test.txt", size );
cout << students[0].name;
The error I'm getting is
[Warning] address of local variable `students' returned
This is my code:
struct Student
{
string name;
char egn[11];
short grade;
double avg_grades;
int excused, unexcused;
};
Student* getFromFile(string filename, int &length)
{
fstream file;
file.open(filename.c_str(), ios::in);
file >> length;
Student students[length];
for ( int i = 0; i < length; i++ )
{
file >> students[i].name >> students[i].egn >> students[i].grade >> students[i].avg_grades >> students[i].excused >> students[i].unexcused;
}
file.close();
return students;
}
int main()
{
int size;
Student *students = getFromFile( "D:\\test.txt", size );
cout << students[0].name;
Firstly, this:
file >> length;
Student students[length];
Is non-standard extension. Length of array should be known at compile-time.
Secondly, you're returning pointer to the memory that will be released once array goes out of scope. You should use std::vector instead:
#include <vector>
// ...
std::vector<Student> getFromFile(string filename)
{
// ...
std::vector<Student> students(length);
Also you no longer need to pass length by reference, since std::vector has size member function.
In getFromFile you are returning a pointer to a vector that only exists in that function. Then, in main you have a pointer to some data that is not valid.
You should use Student *students = new Student[length]; in getFromFile, and delete [] students; in main after using the data. But using a vector for this as others say is a better idea.

vector by reference in a struct?

I want to create a struct containing a double and a vector of strings. I tried this
int main ()
{
struct List
{
double price;
vector<string> items;
};
List list;
ifstream infile ("Aap.txt");
double p;
infile>>p;
list.price=p;
cout<<list.price<<endl;
int i=0;
string name;
getline(infile,name);
while(infile)
{
list.items.push_back(name);
cout<<list.items[i]<<endl;
i++;
getline(infile,name);
}
infile.close();
if (!infile)
{
cout<<"File closed."<<endl;
}
return 0;
This is not filling my vector, because it is not by reference in the struct I suppose?
But when I define the vector in the struct as:
vector<string>& items;
I get an error saying:
error: structure `list' with uninitialized reference members.
How can I fix this?
Thank you for helping!
Your code works perfectly fine.
There's a little issue of the first read: if you have a newline character in your input file after the price value, that newline character will remain unread. In this situation the first call to getline will read an empty string, meaning that the first name in your items array will end up empty.