-6

I've spent pretty much all day trying to do this, I understand pointers and what a linked list does, but I don't know how to actually code it and all I've found are Java and C examples which don't help because I'm using C++. Thanks in advance for taking a look at my code and helping me, I really appreciate it considering how many days I've spent stressed out and confused about this. I'm not going to lie so far most of my deleteNode function is probably trash. But like I've said I'm just lost I don't even know where to start or how to progress because I only understand the concepts.

This is my data file.

John Doe    80
Jane Smith  70
Bill Jones  50
Pat  Hughes 90
Sam  Sosa   40

This is my Header file

#include<string>
using namespace std;
class student {
public:
    student();   // constructor method
    void st_fn(string fn);
    string st_fn();
    void st_ln(string ln);
    string st_ln();
    void st_score(float s);
    float st_score();
    string st_pass_or_fail();
    // need a pointer to the next object
    student *nxt_ptr;
protected:   // protected can be inherited
    float m_score;
    string m_ln;
    string m_fn;
    string m_pf_msg;
};
student::student()  //constructor
{
    nxt_ptr = NULL;
    m_score = 0;
}
void student::st_fn(string fn)
{
    m_fn = fn;
}
string student::st_fn()
{
    return m_fn;
}
void student::st_ln(string ln)
{
    m_ln = ln;
}
string student::st_ln()
{
    return m_ln;
}
void student::st_score(float s)
{
    m_score = s;
}
float student::st_score()
{
    return m_score;
}
string student::st_pass_or_fail()
{
    if (m_score >= 60)
        m_pf_msg = "PASSED";
    else
        m_pf_msg = "FAILED";

    return m_pf_msg;
}

This is my .cpp file.

#include<iostream>
#include<string>
#include<fstream>
#include "Header.h"
using namespace std;
int display_menu()
{
    int option;

    cout << endl << endl;
    cout << "1. Display List" << endl;
    cout << "2. Add a student" << endl;
    cout << "3. Delete first student" << endl;
    cout << "4. Search by Last Name" << endl;
    cout << "5. Exit" << endl;
    cin >> option;

    return option;
}
student * search_last_name(student *h)
{
    student *f = NULL;
    student *t = NULL;
    string s_ln;

    // prompt for last name to search for
    cout << "Enter Last Name of the Student";
    cin >> s_ln;

    if (h != NULL)
    {
        t = h;
        while (t != NULL)
        {
            if (t->st_ln() == s_ln)
                f = t;   // found the last name so save t

            t = t->nxt_ptr;
        }
    }
    else
        cout << "List is empty" << endl;

    return f;

}
void add_student(student *&head)  // h is the head of the list
{
    student *new_st, *r;
    string fn, ln;
    float s;

    cout << "Enter new students first name, last name and score";
    cin >> fn >> ln >> s;

    // instantiate a new node, use new_st
    new_st = new student;
    new_st->st_fn(fn);
    new_st->st_ln(ln);
    new_st->st_score(s);

    if (head == NULL)
        head = new_st;
    else
    {
        // find the last node, use r for this
        // write code
        r = head;
        while (r->nxt_ptr != nullptr)
            r = r->nxt_ptr;

        // add to the back of the list
        // write code
        r->nxt_ptr = new_st;
    } // end of else
} // end of add student
student * delete_front(student * head)
{
    student *t;
    // delete front node
    // check for empty list

    if (head != NULL)
    {
        // delete first node
        t = head;
        head = head->nxt_ptr;
        delete(t);
    }
    else
        cout << "List is empty - nothing to delete" << endl;

    return head;
}
void deleteNode(struct Node *head, struct Node *n)
{
    // When node to be deleted is head node
    if (head == n)
    {
        n = head->next;

        //Remove the link of next node
        head->next = head->next->next;



        return;
    }

    //When not first node, folow the  normal deletion process

    //Find the previous node
    struct Node *prev = head;
    while (prev->next != NULL && prev->next != n)
        prev = prev->next;

    // Check if node really exists in Linked List
    if (prev->next == NULL)
    {
        cout << endl << "Given node is not present in Linked List";
        return;
    }

    //Remove node from linked list should it exist
    prev->next = prev->next->next;


    return;
}

void display_list(student *t)
{
    if (t == NULL)
        cout << "List is Empty!";
    else
    {

        while (t != NULL)
        {
            cout << "******Student******" << endl;
            cout << t->st_ln() << endl;
            cout << t->st_fn() << endl;
            cout << t->st_score() << endl << endl;
            t = t->nxt_ptr;
        }
    }
}
int main()
{
    string ln, fn;
    float s;
    int n;
    ifstream infile;
    student *head = NULL;   //pointer to a student object
    student *cp = NULL;     // pointer to end of the list
    student *new_st = NULL;  // pointer to a new student object
    student *f = NULL;      // pointer to found node

    int option;  // the numbe of menu item the user selects


    infile.open("lab8d.txt");

    while (!infile.eof())
    {
        infile >> fn >> ln >> s;
        //instantiate a student object
        new_st = new student;
        //load the object with data
        new_st->st_fn(fn);
        new_st->st_ln(ln);
        new_st->st_score(s);

        // check for empty list - its a special case
        if (head == NULL)
        {
            head = new_st;
            cp = new_st;
        }
        else   // list is not empty
        {
            cp->nxt_ptr = new_st;
            cp = new_st;
        }

    }  // end of loop

       // loop to give the user some options

    option = display_menu();

    while (option != 5)
    {
        if (option == 1)
            display_list(head);
        else if (option == 2)
            add_student(head);
        else if (option == 3)
            head = delete_front(head);
        else if (option == 4)
        {
            f = search_last_name(head);

            if (f != NULL)
            {
                cout << f->st_fn() << endl;
                cout << f->st_ln() << endl;
                cout << f->st_score() << endl;
                cout << f->st_pass_or_fail() << endl;
            }
            else
                cout << "Name not in the list" << endl;
        }
        else if (option == 6)
        {
            cout << "Enter the number of the node you would like to delete: " << endl;
            cin >> n;

        }

        option = display_menu();

    }


    system("pause");

    return 0;

}
  • the issue is that it is not clear what do you delete and what should remain. If for instance a head should be removed, you would call your function deleteNode(head, head). But head is the pointer to your list. If you call this function, the pointer to your list will not be changed, but the head node will disappear. I mean this is a basic issue in your program. There are lot of other issues. I would recommend to start thinking about interfaces – rhaport May 14 '18 at 20:40
  • I recommend separating the linked list logic from all of the other logic. This make sit a lot easier to test and debug the linked list. Get the linked list working correctly, then add in the Student and then finally add the menu system. – user4581301 May 14 '18 at 20:40
  • 1
    And watch out for `while (!infile.eof())` It's a very common bug. Good write-up here: [Why is iostream::eof inside a loop condition considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – user4581301 May 14 '18 at 20:42
  • As Andrey says, it's not clear what you want to delete and when. You know how to delete a node, so you need to be able to decide which one and just do it. What would that criteria be? – Victoria Ruiz May 14 '18 at 20:42
  • @user4581301 this is actually for a class im taking and the instructor provided us with most of that as a starting program – WhyIsCodingSoDifficult May 14 '18 at 20:43
  • @WhyIsCodingSoDifficult In that case, it might be a good idea to supplement that course with a good C++ book. – Baum mit Augen May 14 '18 at 20:45
  • In that case, find some way to quietly and privately correct the teacher. No point in letting them pass bad code onto future students. Make sure you have a teacher that's up to being corrected first though. No point torpedoing your semester. – user4581301 May 14 '18 at 20:45
  • @VictoriaRuiz I was planning on asking the user for a last name or the number of the node they would like to remove using cout and cin. – WhyIsCodingSoDifficult May 14 '18 at 20:52
  • How to save this question: Focus it on one problem you are having. Remove everything not needed to reproduce that problem. Most of the time when you get to this point all you have left is the bug and can see how to fix it yourself. If not, you're in excellent position to ask a question and get a good answer. Recommended reading: [mcve]. – user4581301 May 14 '18 at 20:57
  • "*all I've found are Java and C examples which don't help because I'm using C++*" - C examples will usually work just fine in C++ with little-to-no tweaking – Remy Lebeau May 14 '18 at 22:53
  • @RemyLebeau Note that a lot of stuff in C are bad practices in C++ though. – eesiraed May 15 '18 at 00:24
  • 1
    @FeiXiang yes, but at least they would compile, and be a starting point for the OP, who is clearly taking a C++ class that teaches C'isms. – Remy Lebeau May 15 '18 at 02:10

1 Answers1

2

The simpler and self-contained your functions are, the easier they are to test and debug, and the less like they are to fail.

Try something more like this:

Student.h:

#include <string>

class student_list;

class student
{
public:
    student();
    student(const std::string &fn, const std::string &ln, float s, student *nxt = NULL);

    void next(student *s);
    student* next() const;

    void firstName(const std::string &fn);
    std::string firstName() const;

    void lastName(const std::string &ln);
    std::string lastName() const;

    void score(float s);
    float score() const;

    std::string pass_or_fail() const;

    void display(bool showPassOrFail = false) const;

    friend class student_list;

protected:   // protected can be inherited
    student *m_next;
    std::string m_fn;
    std::string m_ln;
    float m_score;
};

Student.cpp:

#include "Student.h"
#include <iostream>

student::student()
    : m_next(NULL), m_score(0)
{
}

student::student(const std::string &fn, const std::string &ln, float s, student *nxt)
    : m_next(nxt), m_fn(fn), m_ln(ln), m_score(s)
{
}

void student::next(student *s)
{
    m_next = s;
}

student* student::next() const
{
    return m_next;
}

void student::firstName(const std::string &fn)
{
    m_fn = fn;
}

std::string student::firstName() const
{
    return m_fn;
}

void student::lastName(const std::string &ln)
{
    m_ln = ln;
}

std::string student::lastName() const
{
    return m_ln;
}

void student::score(float s)
{
    m_score = s;
}

float student::score() const
{
    return m_score;
}

std::string student::pass_or_fail() const
{
    if (m_score >= 60)
        return "PASSED";
    else
        return "FAILED";
}

void student::display(bool showPassOrFail) const
{
    std::cout << lastName() << std::endl;
    std::cout << firstName() << std::endl;
    std::cout << score() << std::endl;

    if (showPassOrFail)
        std::cout << pass_or_fail() << std::endl;
}

StudentList.h:

#include <string>

class student;

class student_list
{
public:
    student_list();
    ~student_list();

    student* search_last_name(const std::string &ln);

    student* insert(const std::string &fn, const std::string &ln, float s, student* after = NULL);

    bool remove(int idx);

    void display() const;

private:
    student *m_head;
};

StudentList.cpp:

student_list::student_list()
    : m_head(NULL)
{
}

student_list::~student_list()
{
    while (m_head)
        remove(0);
}

student* student_list::search_last_name(const std::string &ln)
{
    student *t = m_head;
    while (t)
    {
        if (t->lastName() == ln)
            break;   // found the last name

        t = t->next();
    }

    return t;
}

student* student_list::insert(const std::string &fn, const std::string &ln, float s, student* after)
{
    student **r;

    if (after)
    {
        // add to list after the specified node
        // get pointer to next node
        r = &(after->m_next);
    }
    else
    {
        // add to the back of the list

        // find pointer to last node
        r = &m_head;
        while (*r)
            r = &((*r)->m_next);
    }

    // instantiate a new node
    student *new_st = new student(fn, ln, s);
    if (after)
        new_st->next(*r);

    // add to list
    *r = new_st;

    return new_st;
}

bool student_list::remove(int idx)
{
    // delete a node at index

    // find pointer to node
    student **r = &m_head;
    while ((*r) && (idx-- > 0))
        r = &((*r)->m_next);

    if (*r)
    {
        // delete node
        student *t = *r;
        *r = t->next();
        delete t;
        return true;
    }

    return false;
}

void student_list::display() const
{
    student *t = m_head;
    if (!t)
        std::cout << "List is Empty!" << std::endl;
    else
    {
        do
        {
            std::cout << "******Student******" << std::endl;
            t->display();
            t = t->next();
        }
        while (t);
    }
}

Main.cpp:

#include "Student.h"
#include "StudentList.h"

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <limits>
#include <cstdlib>

int read_number()
{
    int value;

    while (!(std::cin >> value))
    {
        std::cout << "Must be a number, try again: ";
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }

    return value;
}

int display_menu()
{
    int option;

    std::cout << std::endl << std::endl;

    std::cout << "1. Display List" << std::endl;
    std::cout << "2. Add a student" << std::endl;
    std::cout << "3. Delete first student" << std::endl;
    std::cout << "4. Search by Last Name" << std::endl;
    std::cout << "5. Delete student by index" << std::endl;
    std::cout << "6. Exit" << std::endl << std::endl;

    std::cout << "Choice: ";

    do
    {
        option = read_number();

        if ((option >= 1) && (option <= 6))
            break;

        std::cout << "Must be 1..6, try again: ";
    }
    while (true);

    return (option != 6) ? option : -1;
}

int main()
{
    student_list students;

    std::ifstream infile("lab8d.txt");
    if (infile.is_open())
    {
        student *cp = NULL;
        std::string ln, fn;
        float s;

        while (infile >> fn >> ln >> s)
            cp = students.insert(fn, ln, s, cp);

        infile.close();
    }

    // loop to give the user some options

    int option;  // the number of menu item the user selects

    while ((option = display_menu()) != -1)
    {
        switch (option)
        {
            case 1:
            {
                students.display();
                break;
            }

            case 2:
            {
                // prompt for student info
                std::string info;
                std::cout << "Enter new student's first name, last name, and score: ";

                std::string ln, fn;
                float s;

                if (std::cin >> fn >> ln >> s)
                    students.insert(fn, ln, s);

                break;
            }

            case 3:
            {
                if (!students.remove(0))
                    std::cout << "List is empty" << std::endl;

                break;
            }

            case 4:
            {
                // prompt for last name to search for
                std::string ln;
                std::cout << "Enter Last Name of the Student: ";

                if (std::cin >> ln)
                {
                    student *f = students.search_last_name(ln);
                    if (f)
                        f->display(true);
                    else
                        std::cout << "Name not found in List" << std::endl;
                }

                break;
            }

            case 5:
            {
                std::cout << "Enter the index of the Student to Delete: " << std::endl;
                int idx = read_number();

                if (!students.remove(idx))
                    std::cout << "Index not found in List" << std::endl;

                break;
            }
        }
    }

    std::system("pause");

    return 0;
}

That being said, you really should be using the std::list container instead, eg:

Student.h:

#include <string>

class student_list;

class student
{
public:
    student();
    student(const std::string &fn, const std::string &ln, float s);

    void firstName(const std::string &fn);
    std::string firstName() const;

    void lastName(const std::string &ln);
    std::string lastName() const;

    void score(float s);
    float score() const;

    std::string pass_or_fail() const;

    void display(bool showPassOrFail = false) const;

    friend class student_list;

protected:   // protected can be inherited
    std::string m_fn;
    std::string m_ln;
    float m_score;
};

Student.cpp:

#include "Student.h"
#include <iostream>

student::student()
    : m_score(0)
{
}

student::student(const std::string &fn, const std::string &ln, float s)
    : m_fn(fn), m_ln(ln), m_score(s)
{
}

void student::firstName(const std::string &fn)
{
    m_fn = fn;
}

std::string student::firstName() const
{
    return m_fn;
}

void student::lastName(const std::string &ln)
{
    m_ln = ln;
}

std::string student::lastName() const
{
    return m_ln;
}

void student::score(float s)
{
    m_score = s;
}

float student::score() const
{
    return m_score;
}

std::string student::pass_or_fail() const
{
    if (m_score >= 60)
        return "PASSED";
    else
        return "FAILED";
}

void student::display(bool showPassOrFail) const
{
    std::cout << lastName() << std::endl;
    std::cout << firstName() << std::endl;
    std::cout << score() << std::endl;

    if (showPassOrFail)
        std::cout << pass_or_fail() << std::endl;
}

Main.cpp:

#include "Student.h"

#include <list>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <limits>
#include <algorithm>
#include <cstdlib>

int read_number()
{
    int value;

    while (!(std::cin >> value))
    {
        std::cout << "Must be a number, try again: ";
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }

    return value;
}

int display_menu()
{
    int option;

    std::cout << std::endl << std::endl;

    std::cout << "1. Display List" << std::endl;
    std::cout << "2. Add a student" << std::endl;
    std::cout << "3. Delete first student" << std::endl;
    std::cout << "4. Search by Last Name" << std::endl;
    std::cout << "5. Delete student by index" << std::endl;
    std::cout << "6. Exit" << std::endl << std::endl;

    std::cout << "Choice: ";

    do
    {
        option = read_number();

        if ((option >= 1) && (option <= 6))
            break;

        std::cout << "Must be 1..6, try again: ";
    }
    while (true);

    return (option != 6) ? option : -1;
}

int main()
{
    std::list<student> students;

    std::ifstream infile("lab8d.txt");
    if (infile.is_open())
    {
        std::string ln, fn;
        float s;

        while (infile >> fn >> ln >> s)
            students.push_back(student(fn, ln, s));

        infile.close();
    }

    // loop to give the user some options

    int option;  // the number of menu item the user selects

    while ((option = display_menu()) != -1)
    {
        switch (option)
        {
            case 1:
            {
                if (students.empty())
                    std::cout << "List is Empty!" << std::endl;
                else
                {
                    for(const auto &s : students)
                    {
                        std::cout << "******Student******" << std::endl;
                        s.display();
                    }
                }

                break;
            }

            case 2:
            {
                // prompt for student info
                std::string info;
                std::cout << "Enter new student's first name, last name, and score: ";

                std::string ln, fn;
                float s;

                if (std::cin >> fn >> ln >> s)
                    students.push_back(student(fn, ln, s));

                break;
            }

            case 3:
            {
                if (students.empty())
                    std::cout << "List is empty" << std::endl;
                else
                    students.erase(students.begin());

                break;
            }

            case 4:
            {
                // prompt for last name to search for
                std::string ln;
                std::cout << "Enter Last Name of the Student: ";

                if (std::cin >> ln)
                {
                    auto f = std::find(students.begin(), students.end(),
                        [&](const student &s){ return (s.lastName() == ln); }
                    );
                    if (f != students.end())
                        f->display(true);
                    else
                        std::cout << "Name not found in List" << std::endl;
                }

                break;
            }

            case 5:
            {
                std::cout << "Enter the index of the Student to Delete: " << std::endl;
                int idx = read_number();

                if ((idx < 0) || (idx >= students.size()))
                    std::cout << "Index not found in List" << std::endl;
                else
                    students.erase(std::next(students.begin(), idx));

                break;
            }
        }
    }

    std::system("pause");

    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770