- Present the LineStorage state invariant;
Consider the consequences of violating each part.
Important: the LineStorage code is complex and error-prone;
because of the heavy use of pointers,
even a trivial error can cause a core dump.
- Show that LSInit establishes the state invariant.
- Show that LSAddLine maintains the state invariant.
Paraphrase the code.
Then do the proof for the empty list case followed by
the non-empty list case.
Emphasize: the first few lines of a function often
falsify the state invariant; then the remaining
lines must make it true. Viewed this way, the state invariant
gives important guidance to the programmer.
- Question: suppose that
LSAddLine
is replaced by:
KWStatus LSAddLine() {}
Does this version maintain the state invariant?
- Question: If you show that a function maintains
the state invariant, have you also shown that
the function is correct?
Partial Module Implementation: LineStorage.h
/********** LineStorage module---implementation **********/
#include
#include
#include "kwic.h"
#include "LineStorage.h"
/***** local constants *****/
/***** local types *****/
/*Each line is a list of WordNodes.*/
typedef struct WordNode {
char* word;
struct WordNode* nextWordPtr;
} WordNode;
typedef WordNode* WordNodePtr;
/*The LineStorage module stores a list of LineNodes*/
typedef struct LineNode {
struct LineNode* nextLinePtr;
WordNodePtr headWordPtr;
WordNodePtr tailWordPtr;
int wordCount;
} LineNode;
typedef LineNode* LineNodePtr;
/***** local variables *****/
static LineNodePtr headLinePtr, tailLinePtr;
static int lineCount;
/***** state invariant *****
1. if lineCount == 0 then
headlinePtr == NULL
taillinePtr == NULL
else
headLinePtr points to a null-terminated linked list of LineNodes.
tailLinePtr points to the last LineNode in this list.
There are lineCount LineNodes in this list.
2. for every LineNode allocated by LineStorage
if wordCount == 0 then
headWordPtr == NULL
tailWordPtr == NULL
else
headWordPtr points to a null-terminated linked list of WordNodes.
tailWordPtr points to the last WordNode in this list.
There are wordCount WordNodes in this list.
3. For every WordNode allocated word is a null-terminated array of characters.
4. All of the dynamic memory allocated by LineStorage (and not yet freed)
is in the list structure headed by headLinePtr.
*/
/***** local functions *****/
/*
...
*/
/***** exported functions *****/
void LSInit(void)
{
headLinePtr = NULL;
tailLinePtr = NULL;
lineCount = 0;
}
KWStatus LSAddLine(void)
{
LineNodePtr newLinePtr;
/* create and fill a LineNode */
newLinePtr = malloc(sizeof(LineNode));
if (newLinePtr == NULL)
return KWMEMORYERROR;
lineCount++;
newLinePtr->nextLinePtr = NULL;
newLinePtr->headWordPtr = NULL;
newLinePtr->tailWordPtr = NULL;
newLinePtr->wordCount = 0;
/* link in the new LineNode */
if (tailLinePtr == NULL) {
headLinePtr = newLinePtr;
} else {
tailLinePtr->nextLinePtr = newLinePtr;
}
tailLinePtr = newLinePtr;
return KWSUCCESS;
}