Thursday, 18 June 2015

Nested structures in CPP with examples

Nested structures in CPP with examples:

Yes, it is possible to write the nested structures within another structure.

The declaration syntax is what you would expect, as you can see in the following structure.
The below program represents the pushdown stack as a simple linked list so it “never” runs out of memory:


#ifndef _STRUCTURES_TEST_H_

#define _STRUCTURES_TEST_H_

struct Structures_Test {

struct StructLink {

  void* pData;

  StructLink* stNext;

  void Init (void* pVal, StructLink* stNxt);

}*ocHead;

  Structures_Test (void);

  void Init ();

  void PushData (void* pVal);

  void* Peek ();

  void* PopData ();

  void CleanUp ();

};

#endif //_STRUCTURES_TEST_H_



The nested struct is called StructLink, and it contains a pointer to the stNext StructLink  in the list and a pointer to the data stored in the StructLink. If the stNext pointer is zero, it means you’re at the end of the list.

Notice that the ocHead pointer is defined right after the declaration for struct StructLink , instead of a separate definition StructLink *stNext. This is a syntax that came from C, but it emphasizes the importance of the semicolon after the structure declaration; the semicolon indicates the end of the comma-separated list of definitions of that structure
type. (Usually the list is empty.)

The nested structure has its own Init ( ) function, like all the structures presented so far, to ensure proper initialization. Stack has both an Init ( ) and cleanup( ) function, as well as PushData( ), which takes a pointer to the data you wish to store  and PopData ( ), which returns the data pointer from the top of the Stack and removes the top element.
The peek( ) function also returns the data pointer from the top element, but it leaves the top element on the Stack.


#include "stdafx.h"
#include "Structures_Test.h"

using namespace std;

void Structures_Test::StructLink::Init (void* dat, StructLink* nxt)

{

  pData = dat;

  stNext = nxt;

}


void Structures_Test::Init ()

  { ocHead = 0; }

void Structures_Test::PushData(void* dat)

{

  StructLink* newLink = new StructLink;

  newLink->Init (dat, ocHead);

  ocHead = newLink;

}

void* Structures_Test::Peek ()

{

return ocHead->pData;

}

void* Structures_Test::PopData ()

{

if (ocHead == 0)

   return 0;

void* result = ocHead->pData;

StructLink* oldHead = ocHead;

ocHead = ocHead->stNext;

delete oldHead;

return result;

}


The first definition is particularly interesting because it shows you how to define a member of a nested structure. You simply use an additional level of scope resolution to specify the name of the enclosing struct. Stack:: StructLink::Init ( t)akes the arguments and assigns them to its members.
Stack::Init ( )sets ocHead to zero, so the object knows it has an empty list.

Stack::PushData( ) takes the argument, which is a pointer to the variable you want to keep track of, and pushes it on the Stack. First, it uses new to allocate storage for the StructLink it will insert at the top. Then it calls StructLink’s Init ( ) function to assign the appropriate values to the members of the StructLink. Notice that the stNext pointer is assigned to the current ocHead; then ocHead is assigned to the new StructLink pointer.

This effectively pushes the StructLink in at the top of the list. Stack::PopData ( ) captures the data pointer at the current top of the Stack; then it moves the ocHead pointer down and deletes the old top of the Stack, finally returning the captured pointer. When PopData ( ) removes the last element, then ocHead again becomes zero, meaning the Stack is empty.

Stack::cleanup( ) doesn’t actually do any cleanup. Instead, it establishes a firm policy that “you (the client programmer using this Stackobject) are responsible for popping all the elements off this Stackand deleting them.” The require( )is used to indicate that a programming error has occurred if the Stackis not empty.

Why couldn’t the Stack destructor be responsible for all the objects that the client programmer didn’t PopData ( )? The problem is that the Stack is holding void pointers, and you’ll learn in another post  that calling delete for a void* doesn’t clean things up properly. The subject of “who’s responsible for the memory” is not even that simple, as we’ll see in later posts.
Here’s an example to test the Stack:
#include "stdafx.h"

#include <fstream>

#include <iostream>

#include <string>

using namespace std;

#include "Structures_Test.h"

int _tmain(int argc, _TCHAR* argv[])

{

  Structures_Test ObjStruct;

  ObjStruct.Init ();

  string strLine;

while (/* Read the file and store lines in th stack*/) 

ObjStruct.PushData(new string(strLine));

string* MyStr;

while((MyStr = (string*)ObjStruct.PopData()) != 0) {

cout << *MyStr << endl;

delete MyStr;

}

 return 0;

}


The above example is very much similar to the previous one, but it pushes lines from a file (as string pointers) on the Stack and then pops them off, which results in the file being printed out in reverse order. Note that the PopData ( ) member function returns a void* and this must be cast back to a string*before it can be used. To print the string, the pointer is dereferenced.


No comments: