Unusual Data Types CSC-3004 Introduction to Software Development Spring 2015 Dr. James Skon
Unusual Data Types Some languages support exotic kinds of data: Structures Pointers Global Data
Structures The term "structure" refers to data that's built up from other types. structs in C and C+ Java and C++, classes also sometimes perform as structures You'll generally want to create classes rather than structures Use structures to clarify data relationships. Structures bundle groups of related items together.
C++ struct struct person { char name[50]; int age; float salary; }; person bill, sam; bill.age = 50; // Access an element sam = bill; // copy an entire structure
Structure and parameters Use structures to simplify parameter lists. display(name,age,salary); or display(bill);
Pointers Pointer usage is one of the most error-prone areas of modern programming! For this reason modern languages like Java, C#, and Visual Basic don't provide a pointer data type Many common security problems, especially buffer overruns, can be traced back to erroneous use of pointers
Pointers The knowledge of how to interpret the contents of a location in memory is provided by the base type of the pointer Memory doesn't have any inherent interpretation associated with it, only through use of a specific type of pointer that the bits in a particular location are interpreted as meaningful data.
Views of memory
Errors with Pointers Some of the most difficult errors to diagnose! When a pointer points to where it shouldn’t, you write data into an area of memory you shouldn't This is called "memory corruption."
Pointers and Memory corruption symptoms Immediate crash alters the results of a calculation in another part of the program cause your program to skip routines unpredictably No obvious symptoms A pointer error can be like a ticking time bomb
Working with pointers – Two prong strategy Work very hard to create correct code up front. Detect pointer errors as soon after they are coded as possible.
Isolate pointer operations in routines or classes Instead of directly using pointers, write access routines. Once they are correctly debugged and working, errors less likely as other code evolves. Create access routines such as NextLink(), PreviousLink(), InsertLink(), and DeleteLink() Reuse of working routines is much safer since you aren’t directly using pointers.
Declare and define pointers at the same time Employee *employeePtr; // lots of code ... employeePtr = new Employee; OR Employee *employeePtr = new Employee;
Safer Pointer Use Delete pointers at the same scoping level as they were allocated Keep allocation and deallocation of pointers symmetric Check pointers before using them Check range of values for sanity Check the variable referenced by the pointer before using it
Pointers: Dog-Tags fields Use dog-tag fields to check for corrupted memory. A "tag field" or "dog tag" is a field you add to a structure solely for the purpose of error checking When you allocate a variable, put a value that should remain unchanged into its tag field When you use it, check the dog tag first When you delete the pointer, corrupt the field so that you will know it is no longer good
Pointers: Dog-Tags fields xxxxxxxxxxxx During Use Tag Data EA21 1:1:1 In the beginning … After Delete 0000 1:1:1 In the beginning … Check for valid tag value before every access
Pointers: Add explicit redundancies Store some fields twice. If the data in the redundant fields doesn't match, you know memory has been corrupted Lots of overhead – but if you isolate the pointer operation in accessor functions you can hide the complexity
Use extra pointer variables for clarity void InsertLink( Node *currentNode, Node *insertNode ) { // insert "insertNode" after "currentNode" insertNode->next = currentNode->next; insertNode->previous = currentNode; if ( currentNode->next != NULL ) { currentNode->next->previous = insertNode; } currentNode->next = insertNode; Needlessly Complex
Use extra pointer variables for clarity void InsertLink( Node *startNode, Node *newMiddleNode ) { // insert "newMiddleNode" between "startNode" and "followingNode" Node *followingNode = startNode->next; newMiddleNode->next = followingNode; newMiddleNode->previous = startNode; if ( followingNode != NULL ) { followingNode->previous = newMiddleNode; } startNode->next = newMiddleNode; Simpler
Pointers: Draw a picture
Pointers Delete pointers in linked lists in the right order. Don’t delete pointers pointing objects which in turn point to other objects Delete
Pointer - Allocate a reserve parachute of memory If your program uses dynamic memory, you need to avoid the problem of suddenly running out of memory, leaving your user and your user's data lost in RAM space When you run out of memory, free the reserve parachute, clean up, and shut down Reserved Use Heap
Pointers – Shredding you Garbage Forcing Deallocated Memory to Contain Junk Data Why? You won’t be fooled into thinking references to dellocated memory are working because it still contains “good” data
Pointer – Set to null after deleting memory it points to To make sure you aren’t pointing to something non-valid pointer->SetContentsToGarbage(); delete pointer; pointer = NULL;
Pointer – Keep track of pointers ASSERT( pointer != NULL, "Attempting to delete null pointer." ); if ( IsPointerInList( pointer ) ) { memset( pointer, GARBAGE_DATA, MemoryBlockSize( pointer ) ); RemovePointerFromList( pointer ); delete pointer; pointer = NULL; } else { ASSERT( FALSE, "Attempting to delete unallocated pointer." );
Global Data Global variables are accessible anywhere in a program. Inherently unsafe, since they can be modified anywhere. (Side-effect) Every global variable adds to the coupling everywhere!
Global Data Used with discipline, global variables are useful in several situations Preservation of global values Emulation of named constants Emulation of enumerated types
Global Data Alternative – access Routines Create a class for global data, and create accessor functions to access the data. Global Data system_status memory_avail … other_stuff system_status.Get(); memory_avail.Set(new_value);