0
votes

I have a problem with the application crashing at the line of code where if(!head) is being referenced inside the function: insertNode(). head and tail are class members of type node*. It looks like, I am missing something in the way the class members: head, tail are initialized.. This is the runtime error: "Unhandled exception at 0x00245246 in SLinkedlist_array.exe: 0xC0000005: Access violation reading location 0x00000000."

    slinkedlist.h:
    typedef struct node
    {
        int value;
        struct node* next;
    } node;

    class slinkedlist
    {
    public:
        //ctor, dtor, insertNode(int, int), displayList()
    private:
        node* head, tail;
    };

    slinkedlist.cpp:
    bool slinkedlist::insertNode(int value, int aftNodeVal)
    {
        int toinsertval = value;
        int searchkey = aftNodeVal;
        bool retval = false;

        // If it's a new linked list
        if(!head)  // THIS IS WHERE THE APPLICATION CRASHES!
        {
            node* head = new node;
            head->value = toinsertval;
            head->next = NULL;
            return true;
        }
        else //It's not a new list
        {
            while(head->next != NULL)
            {
                 //some more code here... 
            }
        }
        return retval;
    }

    void slinkedlist::displayList()
    {
        while(!head)
        {
            do
            {
                cout << head->value << " " ;
                head = head->next;
            }
            while(head->next != NULL);
        }
        //return void;
    }

    main.cpp:
    int main()
    {
        slinkedlist *s1 = NULL;
        s1->insertNode(4, -1);
        s1->displayList();
        while(1);
    }`
2
You s1->insertNode(4, -1);, but s1 has not initialized.Gupta
Unrelated: The typedefing of typedef struct node { int value; struct node* next; } node; is not necessary. C++ is more than smart enough to figure out what node is without it. struct node { int value; struct node* next; }; is sufficient.user4581301
Related: Read up on the Member Initializer List.user4581301
Depending on how and where you define a variable, it may or may not be initialized. Some reading on those rules. In this case you're right and the problem is initialization. head and tail are not being initialized. Here's a link to documentation on the may different ways you can initialize in C++. Pick the one that makes the most sense. But...user4581301

2 Answers

1
votes

The answer is simple: you have null-pointer dereference here:

slinkedlist *s1 = NULL;
s1->insertNode(4, -1);
s1->displayList();

That's what exactly the system tells to you: "Access violation reading location 0x00000000"

Solution can be like:

slinkedlist *s1 = new slinkedlist;
s1->insertNode(4, -1);
s1->displayList();
delete s1;

Or like this (why not to use just an object on the stack?):

slinkedlist s1;
s1.insertNode(4, -1);
s1.displayList();

Or more C++ way (if you NEED a pointer):

auto s1 = make_unique<slinkedlist>(); // s1 is a std::unique_ptr<slinkedlist>
s1->insertNode(4, -1);
s1->displayList();
0
votes
slinkedlist *s1 = NULL;

defines a pointer to a slinkedlist and DOES initialize it Unfortunately it initializes it to NULL, a safe parking address where (usually) no object are allowed to exist. For the vast majority of CPUs (every CPU I've ever worked on) accessing this dead zone around NULL will crash the program, making it much easier to detect bugs.

There is no need for a pointer here. If you don't need pointer, don't use one. Your life will be much easier.

int main()
{
    slinkedlist s1; // default initializes
    s1.insertNode(4, -1);
    s1.displayList();
    while(1); // rethink this. If you want to hold a program open to see the output 
              // while debugging, place a breakpoint in the debugger.   
}

Default initializing of s1 alone will not help you because it will do the absolute minimum work to initialize its member variables, and in the case of a pointer the minimum work is to do nothing and leave head and tail uninitialized and pointing (sort of. tail is NOT a pointer) to an indeterminate location. Because you aren't also asking about the compiler error you should get from assigning NULL to tail, the program is clearly not initializing tail and I'll assume the slinkedlist constructor doesn't do much.

Side note: If you have a constructor or destructor that don't do anything (and don't need to do anything) leave them out and let the compiler generate the appropriate code. Code that does not exist (and doesn't need to exist) has no bugs.

class slinkedlist
{
public:
    //ctor, dtor, insertNode(int, int), displayList()
private:
    node* head, tail; // the * only applies to head.
};

could be

class slinkedlist
{
public:
    //ctor, dtor, insertNode(int, int), displayList()
private:
    node* head = nullptr;
    node* tail = nullptr;
};

if you are compiling to recent (2011 or newer) C++ Standards. You won't need a constructor, the work is done for you with the default assignments. You will still need a destructor along with a copy constructor and an assignment operator to satisfy The Rule of Three.

In older C++ Standards you need to make the constructor smarter

class slinkedlist
{
public:
    slinkedlist(): head(NULL), tail(NULL)
    {
    }
    //dtor, insertNode(int, int), displayList()
private:
    node* head; // I recommend splitting the definitions up. It makes the code easier 
                // to read and makes it harder to make mistakes.
    node* tail;
};

You will still need a destructor, a copy constructor, and an assignment operator.

Note that this also applies to node. If you dynamically allocate a node and do not explicitly set next to a value, you won't know where next points, and all of the tests like

while(head->next != NULL)

will fail horribly.