-1

How can I simply pass this line of text to a member function? That's all I'm asking... There is a member function called Student:Populate(std::string) that I would like to connect the particular instance of Student to the data of the specific file line... I don't know how to do it syntactically.

it's for a school assignment so I must use manual allocation of new/delete, no smart pointers and no vectors so just ruling those out off the bat.

int main(){
std::stringstream stream;
std::string current;
Student temp;
Student *database = new Student[50];

inFile.open("students.dat", std::ifstream::in);
outFile.open("FullReport.txt",std::ofstream::out);

while(getline(inFile,current)){
   for(int i = 0; i < 50; i++){
        Student[i] = new Student(current); //this line doesn't work when it's compiled

        outFile << Student[i] <<std::endl; //neither does this one

       //there is a Student Populate(std::string); function I would like to pass the data to... How can I do that? 

   }
   inFile.close();
   outFile.close();
}

COMPILER ERRORS:

error: expected unqualified-id before ‘[’ token Student[i] = new Student(current); ^ main.cpp:26:27: error: expected primary-expression before ‘[’ token outFile << Student[i] <

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • The shown code appears to do exactly what you claim you don't know how to do: "pass a string to a specific object". The shown code constructs one `Student` at a time, passing a `std::string` to the object's constructor. Congratulations, you've done it! Or, maybe, perhaps you'd like to explain exactly what your actual question is? – Sam Varshavchik Oct 26 '19 at 00:45
  • Oh okay well this code is sure not working at all ...errors from compiler: expected unqualified-id before ‘[’ token Student[i] = new Student(current); ^ main.cpp:26:27: error: expected primary-expression before ‘[’ token outFile << Student[i] < – amorphous_solid Oct 26 '19 at 00:48
  • What made you "`Student *database = new Student[50];`"? – Ted Lyngmo Oct 26 '19 at 00:51
  • Oh Hey. Yeah. I see it. Typo: `Student[i]` should be `database[i]`. `database` is the variable. `Student` is the type. – user4581301 Oct 26 '19 at 00:51
  • @TedLyngmo I saw other people do it, but I'm having trouble walking thru the array successfully. Any suggestions? – amorphous_solid Oct 26 '19 at 00:52
  • @amorphous_solid The other people were probably adviced not to go down that path further. It can of course be done. Modern uses of C++ refrains from naked pointers though. – Ted Lyngmo Oct 26 '19 at 00:54
  • 3
    You're not going to make much progress learning C++ if you take the approach of simply copying what "other people do". C++ is the most complicated general purpose programming language in use today, and you simply need to learn, study, and understand C++ by yourself. – Sam Varshavchik Oct 26 '19 at 00:55
  • 1
    `RAII` <- a good thing to have in mind – Ted Lyngmo Oct 26 '19 at 00:57
  • @user4581301 with that change: student.h:10:1: error: main.cpp: In function ‘int main()’: main.cpp:25:37: error: no matching function for call to ‘Student::Student(std::string&)’ database[i] = new Student(current); ^ main.cpp:25:37: note: candidates are: In file included from main.cpp:5:0: student.h:6:7: note: Student::Student() class Student{ ^ student.h:6:7: note: candidate expects 0 arguments, 1 provided student.h:6:7: note: Student::Student(const Student&) ^ etc – amorphous_solid Oct 26 '19 at 00:58
  • @TedLyngmo optimization doesn't matter for this assignment.. i just need help on how to pass to the student class only, that's all . This isn't working – amorphous_solid Oct 26 '19 at 01:00
  • From your code, `Student` is a type, but you have a statement `Student[i] = new Student(current)` which treats it as a variable (assigning to it) and - on the right hand side as a type (creating an instance of the type). Variables and types are not interchangeable like that, and the compiler does not try to read your mind to work out how to unpick such contradictions. Something is either one or the other, not both at once. – Peter Oct 26 '19 at 01:01
  • Optimization? No, I suggest resourse management. - – Ted Lyngmo Oct 26 '19 at 01:02
  • Lots of stuff going on here. I'd need a whole answer to break it all down. Recommendation: Write little bits of code at a time. Write, compile, test. When the code tests out, write a bit more. Try to write everything all at once and you'll be picking out errors until the cows come home. If you write, say, two lines and the program doesn't work, can you guess where the mistakes probably are? If you said the two lines I just added, you're almost certainly right! Finding a problem with 2 lines is way, way easier than with 20. – user4581301 Oct 26 '19 at 01:02
  • @user4581301 I didn't write it all at once, this is just a simple question. How do I pass a line of data to an object function? I don't think it's very complex – amorphous_solid Oct 26 '19 at 01:05
  • `new Student(current);` would do it, so long as `Student` has a constructor that takes a `std::string`. It's all the scaffolding you have around it that's giving you trouble. Start by proving you can read one line and create one `Student`. Then make a loop that reads more lines and makes a `Student` for each line. Then add in the dynamic array and store the students. One step at a time. – user4581301 Oct 26 '19 at 01:07
  • You already are passing "a line of data to an object function" just fine. You're doing an excellent job of it. That's not the problem with the shown code. – Sam Varshavchik Oct 26 '19 at 01:11
  • Stop - "`Student *database = new Student[50];`" is silly Today. `std::vector ...` be fine! Why 50? And WHY "new"? What gave you that idea? – Ted Lyngmo Oct 26 '19 at 01:14
  • 1
    @Ted because School. No `vector`s allowed. Have to learn to do it the *easy* way first. – user4581301 Oct 26 '19 at 01:20
  • @user4581301 :-) because learing it the hard way makes it easy I guess. – Ted Lyngmo Oct 26 '19 at 01:23
  • @Ted Yup. It means they head off and learn Java or Python instead. Much easier. – user4581301 Oct 26 '19 at 01:32
  • @user4581301 :-) that's sort of giving up ... I'm not there at all. – Ted Lyngmo Oct 26 '19 at 01:34
  • Teacher says: No "std" - ok, create your own with the purpose of solving the problem at hand. Ask how to, and - wow - duplicates will fly in - which is a good thing. – Ted Lyngmo Oct 26 '19 at 01:37

2 Answers2

2

So, a couple of things.

First, there is no Student[i]. Student is a class name. Classes don't have a way to access from operator[] unless you overload it (probably a future topic in your class) and even then it probably won't be static, meaning that Student[i] has no real meaning.

There is, however a database[i], which is probably what you want.

Secondly, database[i] is not a pointer, so there is no reason to allocate with new. You already did that above with the line Student *database = new Student[50];, so even something like database[i] = new Student(current); is pointless. Instead, try this:

database[i] = Student(current);

This assigns a new instance of Student to database[i]. No new needed here.

Finally, note that this would assign a new instance of Student to database[i], meaning it will call a constructor. If you don't have a constructor that accepts a std::string, that won't compile. It also won't call Populate() either.

If you want to call Student::Populate(), to do that you need to call it on an instance of the object. Like this:

database[i].Populate(current);

I hope that's what you were asking.


P. S. I should also mention that as a general rule, you shouldn't use new. The Standard Template Library is far better.

Of course, most school assignments don't allow this, so sometimes you have to use new. But I guess I should still mention it.

  • Any comment on "new..."? – Ted Lyngmo Oct 26 '19 at 01:40
  • You mean "don't use it"? Yes, of course. Unless your professor has something against the STL, which most do for some reason. –  Oct 26 '19 at 01:41
  • I figure it's usually not worth mentioning when the OP writes things like "it's for a school assignment" because 99% of the time it's implied they can't use STL. But I added a PS just to keep it straight. –  Oct 26 '19 at 01:46
  • 1
    It's always worth it - until it's not. +1 from me. I wished for the proper way of managing a resource - but, ok, this'll do. You did "you shouldn't use new." – Ted Lyngmo Oct 26 '19 at 01:49
  • Thank you for the feedback everyone <3 – amorphous_solid Nov 15 '19 at 08:28
1

Lets go thought this bit by bit

int main()
{   
    std::stringstream stream;

stream's not used here. For now let's get rid of it. It'll come back again later, though.

    std::string current;
    Student temp;
    Student *database = new Student[50];

This creates 50 Students.

    inFile.open("students.dat", std::ifstream::in);
    outFile.open("FullReport.txt",std::ofstream::out);

Opens the files. Can be done a bit better, but right.

    while(getline(inFile,current))
    {   

Perfect. Got a line from the file.

        for(int i = 0; i < 50; i++)

With this one line from the file, do the same thing 50 times. Ask your Rubber duck if it thinks this makes sense.

        {   
            Student[i] = new Student(current);

Student is a type, not a variable. You can't store in a type. Odds are you meant to use database, but it is an array of Students, and new Student(current) provides pointers to Students.

            outFile << Student[i] <<std::endl;
        }
        inFile.close();
        outFile.close();

Closing the files too soon. You haven't read all of the students yet.

    }
}

How to fix:

int main()
{
    std::string current;
    Student **database = new Student*[50];

database is an array of 50 pointers to Students, al ready to accept new Students. But more on this later.

    std::ifstream inFile("students.dat");
    std::ofstream outFile("FullReport.txt");

If we define the file streams here and specify the direction (ifstream, ofstream) we don't need to specify it again. Plus we can open the file right in the constructor. Who needs messy calls to open? Finally because the files are local variables they will automatically be destroyed and close at the end of the function. No need for a messy call to close. (See What is meant by Resource Acquisition is Initialization (RAII)? for more on this concept) Code you don't have to write doesn't have bugs. And if it somehow does, they aren't your fault.

    int count = 0;

count is a much more descriptive name than i

    while (std::getline(inFile, current))
    {

nothing changed here. This is fantastic. There is a famous question on Stack Overflow that is famous because of how many people get this wrong. Kudos. You got it right.

        database[count] = new Student(current);

new Student allocated and added to database. More on this later.

        outFile << *database[count] << std::endl;

And written to output file. Note the * to dereference the pointer and get the value pointed at so it can be printed with a regular << operator (which you have to provide, by the way). Without the * the program will print out the contents of the pointer: An address.

        count++;
    }
}

And one more time without all of the explanation for easy code reading

int main()
{
    std::string current;
    Student **database = new Student*[50];

    std::ifstream inFile("students.dat");
    std::ofstream outFile("FullReport.txt");

    int count = 0;

    while (std::getline(inFile, current))
    {

        database[count] = new Student(current);

        outFile << *database[count] << std::endl;

        count++;
    }
}

OK it's later. You don't want

Student **database = new Student*[50];

It's pretty gross for several reasons.

  1. Modern computers are fantastic at thinking in straight lines. If the data is on one nice straight line they can read ahead and have the data ready for you before you need it. Arrays of data are awesome. Arrays of pointer to data prevent the computer from getting up speed. It reads one Student, then it has to look up another pointer to find the next Student. This can be slow. Cripplingly slow. With an array of Students while you are using Student 0, the computer is loading (or has already loaded when it loaded Student 0) the next bunch of Students.
  2. Every dynamic allocation has a cost. The program has to ask the OS for a block of memory. The OS has to find one. This can be expensive. It's much better to get one big block of memory and divvy it up into an array of Students.
  3. Each dynamic allocation has to be put away. Allocate 50 Students and you need to have code that puts away 50 Students. Allocate an Array of Students, you put away one Array of Students

You want something more like

int main()
{
    std::string current;
    Student *database = new Student[50];

    std::ifstream inFile("students.dat");
    std::ofstream outFile("FullReport.txt");

    int count = 0;

    while (std::getline(inFile, current))
    {
        database[count] = Student(current);
        outFile << *database[count] << std::endl;
        count++;
    }
}

And of course what you really want is

int main()
{
    std::string current;
    std::vector<Student> database;

    std::ifstream inFile("students.dat");
    std::ofstream outFile("FullReport.txt");

    while (std::getline(inFile, current))
    {
        database.emplace_back(current);
        outFile << database.back() << std::endl;
        count++;
    }
}

But this will get a nice round zero from the instructor. First rule of school is give the teacher what they want and pass the course. Second rule is read a bunch of other stuff to learn what you weren't taught so you won't be useless once you graduate.

user4581301
  • 33,082
  • 7
  • 33
  • 54