0

I'm quite new with c++ and need some help with the following code.

#include <iostream>
using namespace std;

struct  student {
    string name;
    int age;
    float marks;
};

struct student *initiateStudent(string , int , float);

int main ( ) {
    int totalStudents = 1;
    string name;
    int age;

    float marks;

    cin >> totalStudents;

    student *stud[totalStudents];

    for( int i = 0; i < totalStudents; i++ )  {
        cin >> name >> age >> marks;
        stud[i] = initiateStudent(name,age,marks);
    }
    cout << stud[0]->name;

    return 0;
}

struct student *initiateStudent(string name, int age, float marks)
{
    student *temp_student;

    temp_student->name  = name;
    temp_student->age   = age;
    temp_student->marks = marks;
    return temp_student;
}

I need in the function initiateStudent return a struct pointer to the pointer array stud by passing the members name, age, marks. I know that the problem sofar is the fact that temp_student is destroyed when I return to the main file. So my question is how it could be done by just passing the members of the struct and then return back with information to the pointer array stud.

Thank you very much.

AT90
  • 25
  • 3
  • `student *temp_student;` misses an allocation: you have undefined behaviour here. – Jean-François Fabre Sep 25 '16 at 20:01
  • Which book are you using to learn C++? You seem to have picked up some bad habits already :( – Lightness Races in Orbit Sep 25 '16 at 20:02
  • `code.c:10:3:warning - "student" found in code - possible sunday's night homework - expect downvoting when answering` :) – Jean-François Fabre Sep 25 '16 at 20:02
  • a sigfault in your function: you haven't initialized pointer student temp and trying o use it. if you initialize it with new it won't be destroyed even after return of function – Raindrop7 Sep 25 '16 at 20:05
  • I think you can create the pointer with `new` then return it. The pointer that receives the allocated pointer should be splicitly deleted at some point, though. – Gabriel Vasconcelos Sep 25 '16 at 20:06
  • 2
    Off topic: rather than `initiateStudent`, prefer a constructor in `student`. Interesting fun fact: `struct` in C++ is nothing more than a `class` with relaxed access permissions. Anything you can do in a `class`, you can do in a `struct`. – user4581301 Sep 25 '16 at 20:07
  • What er the bad habits? I would like to know them already :) – AT90 Sep 25 '16 at 20:08
  • A mere pointer is effectively just a number that represents some memory address. When you say just `struct student *variable;`, `variable` can contain any garbage that was in the memory at the moment of its creation. You'll need to make it point to some valid memory first. – ForceBru Sep 25 '16 at 20:08
  • If I say temp_student = new student, it seems to work. But My question is then would temp_student have to be deleted or is there another way to fix the problem by not changing the arguments of my function? – AT90 Sep 25 '16 at 20:12
  • You'll have to manually `delete` it at some point. Using an external function to create an instance is C style though, and for C++ is not the recommended, as @user4581301 pointed out. – Gabriel Vasconcelos Sep 25 '16 at 20:21

2 Answers2

2

Semi-answer To explain the bad habits:

#include <string>
#include <iostream>
#include <vector>

//using namespace std; often injects subtle bugs. Use with caution
// read more here: 
// http://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice


struct student
{
    std::string name; // explicit namespacing reduces possibility of unwanted collisions
    int age;
    float marks;
    //added constructor in place of initialization function.
    student(std::string name, int age, float marks):name(name), age(age), marks(marks)
    {
    }
};

int main()
{
    int totalStudents = 1;
    std::string name;
    int age;

    float marks;

    while (!(std::cin >> totalStudents)) // testing input for success
                                         // Needed extra brackets caught by M.M
                                         // teach me to not test even a throw-away example    
    {
        std::cout << "must... have... good... input..." << std::endl; 
        cin.clear(); // clear the error and get rid of any other garbage the user may have input.
        cin.ignore(numeric_limits<streamsize>::max(), '\n');

    }

    //student *stud[totalStudents]; illegal in C++
    std::vector<student *> stud(totalStudents); // using dynamic array instead

    for (int i = 0; i < totalStudents; )// i++ removed
    {
        if (std::cin >> name >> age >> marks) //testing input
        {
            stud[i] = new student(name, age, marks); // using constructor
            i++; // and put here. Only increment if input is valid.
        }
        else
        {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
    }
    std::cout << stud[0]->name;

    for (student * stu: stud) // cleaning up allocated memory
    {
        delete stu; 
    }

    return 0;
}

One of the beauties of C++ is you rarely need to self-manage memory. In fact there are huge advantages in not doing it above and beyond not having to clean up after yourself.

#include <string>
#include <iostream>
#include <vector>


struct student
{
    std::string name;     
    int age;
    float marks;

    student(std::string name, int age, float marks):name(name), age(age), marks(marks)
    {
    }
};

int main()
{
    std::string name;
    int age;
    float marks;

    std::vector<student> stud; // look ma! No pointer!

    while (std::cin >> name >> age >> marks) //exits loop on bad input
    {
        stud.emplace_back(name, age, marks); // building directly in vector
                                             // vector will size itself as needed.
    }
    std::cout << stud[0].name;

    return 0;
}

One more caveat: >> is whiespace delimited. That means it stops when it finds whitespace (space, tab, end of line...) so a name of "John Jacob Jingleheimer-Shmidt" will go into name as "John". >> will then attempt to interpret "Jacob" as age, and that will not go so well.

user4581301
  • 33,082
  • 7
  • 33
  • 54
  • Just a question, though: Is `for (int i = 0; i < totalStudents; )` considered good practice in C++ ? In my opinion, that's one of the cases where a while loop might be clearer. Just my 2 cents, I could be mistaken (coming primarily from a C background). – MayeulC Sep 25 '16 at 20:43
  • 1
    That's personal prefference. To be honest, I'd clean that up to `int i = 0; while (i < totalStudents)` to make sure the intent was absolutely clear. Sucks when the brain draws in a non-existent `i++` because it's expecting one. I didn't because I wanted to keep that example as similar as possible to the original for easy comparing. – user4581301 Sep 25 '16 at 20:53
0

the simple solution is to make your initiateStudent() creates temp_student on the heap (with new): and returns it. keep in mind heap allocated memory is not freed automatically so don't forget to free it later on yourself.

#include <iostream>
#include <string>
using namespace std;

struct  student {
    string name;
    int age;
    float marks;
};

struct student *initiateStudent(string , int , float);

int main ( ) {
    int totalStudents = 1;
    string name;
    int age;

    float marks;

    cout << "Total student: ";
    cin >> totalStudents;
    cin.sync(); // very very important to not affect the next input (name)

    student* stud = new student[totalStudents];

    for( int i = 0; i < totalStudents; i++ ) 
    {
        cout << "Name: ";
        getline(cin, name);
        cin.sync();
        cout << "age: ";
        cin >> age;
        cout << endl;
        cout << "Marks: ";
        cin >> marks;
        cout << endl;
        cin.sync();

        stud[i] = *initiateStudent(name, age, marks);
    }

    cout << "Student 1: " << stud[0].name << endl;

    delete[] stud;
    stud = NULL;

    return 0;
}

struct student *initiateStudent(string name, int age, float marks)
{
    student *temp_student = new student;

    temp_student->name  = name;
    temp_student->age   = age;
    temp_student->marks = marks;
    return temp_student;
}
Raindrop7
  • 3,889
  • 3
  • 16
  • 27